Open8

SNSの作成

絶対定時退勤絶対定時退勤

アプリの作成

python manage.py startapp sns

アプリの登録

django_app\django_app\settings.py
# Application definition

INSTALLED_APPS = [
    "django.contrib.admin",
    "django.contrib.auth",
    "django.contrib.contenttypes",
    "django.contrib.sessions",
    "django.contrib.messages",
    "django.contrib.staticfiles",
    # 新規追加
    "hello",
    # SNS登録
    "sns",
]
絶対定時退勤絶対定時退勤

データベースを設計する

【ユーザー】
    Djangoのものを使用
【メッセージ】
    owner ID:投稿者
    content:コンテンツ
    good count:goodした数
    pub_date:投稿日時

【good】
    owner ID:投稿者
    message ID:goodしたメッセージID
    pub_date:goodした日時
    pub_date:投稿日時

モデルの作成

django_app\sns\models.py
# データベースを設計する
【ユーザー】
    Djangoのものを使用
【メッセージ】
    owner ID:投稿者
    content:コンテンツ
    good count:goodした数
    pub_date:投稿日時

【good】
    owner ID:投稿者
    message ID:goodしたメッセージID
    pub_date:goodした日時
    pub_date:投稿日時

# モデルの作成
```py:django_app\sns\models.py
from django.db import models
from django.contrib.auth.models import User

# Create your models here.


# Message クラス
class Message(models.Model):
    # 投稿者ID(Djangoのユーザーから引っ張ってくる)
    owner = models.ForeignKey(
        User,
        on_delete=models.CASCADE,
        related_name="messge_owner",
    )

    # 投稿したコンテンツ
    content = models.TextField(
        max_length=1000,
    )

    # goodカウント
    good_count = models.IntegerField(
        default=0,
    )

    # 投稿日時:自動で作成するように設定
    pub_date = models.DateTimeField(
        auto_now_add=True,
    )

    # データの設定
    class Meta:
        # 並び順はpub_dateの古いものから
        ordering = ("-pub_date",)


# goodクラス
class Good(models.Model):
    # 投稿者
    owner = models.ForeignKey(
        User,
        on_delete=models.CASCADE,
        related_name="good_owner",
    )

    # メッセージ
    message = models.ForeignKey(
        Message,
        on_delete=models.CASCADE,
    )

    # 投稿日
    pub_date = models.DateTimeField(
        auto_now_add=True,
    )

    # 表示文字列
    def __str__(self):
        return f'"{str(self.message)}"(by {str(self.ownew)})'

    # 設定
    class Meta:
        # 並び順はpub_dateの古いものから
        ordering = ("-pub_date",)

マイグレーション実行

(system) PS F:\Django_project\django_app> python manage.py makemigrations sns
Migrations for 'sns':
  sns\migrations\0001_initial.py
    + Create model Message
    + Create model Good

テーブルの登録

django_app\sns\admin.py
from django.contrib import admin
from .models import *

# Register your models here.
# テーブルの登録
admin.site.register(Message)
admin.site.register(Good)

# 管理ツールでユーザーの登録

python manage.py runserver

http://127.0.0.1:8000/admin/にアクセスする


# マイグレーション実行

(system) PS F:\Django_project\django_app> python manage.py makemigrations sns
Migrations for 'sns':
sns\migrations\0001_initial.py
+ Create model Message
+ Create model Good


# テーブルの登録
```py:django_app\sns\admin.py
from django.contrib import admin
from .models import *

# Register your models here.
# テーブルの登録
admin.site.register(Message)
admin.site.register(Good)

# 管理ツールでユーザーの登録

python manage.py runserver

http://127.0.0.1:8000/admin/にアクセスする


からユーザ追加をする
こんなかんじ

絶対定時退勤絶対定時退勤

フォームの作成

django_app\sns\forms.py
from django import forms
from .models import *
from django.contrib.auth.models import User


# Messageのフォーム(使わないけど一応)
class MessageForm(forms.ModelForm):
    class Meta:
        model = Message
        fields = [
            "owner",
            "content",
        ]


# goodフォーム
class GoodForm(forms.ModelForm):
    class Meta:
        model = Good
        fields = [
            "owner",
            "message",
        ]


# 投稿フォーム
class PostForm(forms.Form):
    content = forms.CharField(
        max_length=500,
        widget=forms.Textarea(
            attrs={
                "class": "form-control",
                "row": 2,
            }
        ),
    )

    # インスタンスを初期化するメソッド
    def __init__(self, user, *args, **kwargs):
        super(PostForm, self).__init__(*args, **kwargs)

URLの設定

snsフォルダ内に「sns.py」を作成する

django_app\sns\urls.py
from django.urls import path
from . import views


urlpatterns = [
    path(
        "",
        views.index,
        name="index",
    ),
    path(
        "<int;page>",
        views.index,
        name="index",
    ),
    path(
        "post",
        views.goods,
        name="goods",
    ),
    path(
        "goods/<int:good_id>",
        views.good,
        name="good",
    ),
]

プロジェクト登録

django_app\django_app\urls.py
from django.contrib import admin
from django.urls import path, include

# URL(アドレス)を管理する
urlpatterns = [
    path("admin/", admin.site.urls),
    path("hello/", include("hello.urls")),
    path("sns/", include("sns.urls")),
]

views.py

django_app\sns\views.py
from django.shortcuts import render
from django.shortcuts import redirect
from django.contrib.auth.models import User
from django.contrib import messages
from django.core.paginator import Paginator
from django.db.models import Q
from django.contrib.auth.decorators import login_required

from .models import Message, Good
from .forms import PostForm


# indexビュー関数
@login_required(login_url="/admin/login")
def index(request, page=1):
    # 1ページあたりの表示数
    max = 10
    form = PostForm(request.user)
    msgs = Message.objects.all()

    # ペネトレーションで指定ページを取得
    paginate = Paginator(msgs, max)
    page_items = paginate.get_page(page)

    params = {
        "login_user": request.user,
        "form": form,
        "contents": page_items,
    }

    return render(request, "sns/index/html", params)


# goodsのビュー関数
@login_required(login_url="/admin/login")
def post(request):
    # POST送信時
    if request.method == "POST":

        # 送信内容の取得
        content = request.POST["content"]

        # Messageを作成、保存
        msg = Message()
        msg.owner = request.user
        msg.content = content
        msg.save()
        return redirect(to="/sns")

    # ページ取得
    else:
        # ログインユーザーのメッセージを全て取得
        messages = Message.objects.filter(owner=request.user).all()

        params = {
            "login_user": request.user,
            "contents": messages,
        }

        return render(request, "sns/post.html", params)


# goodボタンの処理
@login_required(login_url="/admin/login")
def good(request, good_id):
    # goodするMessageを取得
    good_msg = Message.objects.get(id=good_id)

    # 自分がメッセージにgoodした回数を調べる
    is_good = Good.objects.filter(
        owner=request.user,
        messages=good_msg,
    ).count()

    # 0より大きければgood済み
    if is_good > 0:
        # システムメッセージ
        messages.success(request, "既にメッセージはGoodしています")
        return redirect(to="/sns")

    # Messageのgoodを増やす
    good_msg.good_count += 1
    good_msg.save()

    # goodを作成して設定ー>保存
    good = Good()
    good.ownew = request.user
    good.message = good_msg
    good.save()

    # メッセージを設定
    messages.success(request, "メッセージにgoodしました。")
    return redirect(to="/sns")

アノテーション

@login_required(login_url="/admin/login")

ユーザー認証を行う。

login_urlログインページのURLを指定する。
今回はログインされないと自動的にログインページにリダイレクトする

ログインユーザーの取得

request.user

システムメッセージを使用

from django.contrib import messages
messages.success(request, "既にメッセージはGoodしています")

degug,info,success,warning,erroがある

絶対定時退勤絶対定時退勤

アプリを設計する

  1. 機能の洗い出し
  2. データベース設計
  3. 各ページの設計

アプリの作成

python manage.py startapp sns

アプリの登録

django_app\django_app\settings.py
# Application definition

INSTALLED_APPS = [
    "django.contrib.admin",
    "django.contrib.auth",
    "django.contrib.contenttypes",
    "django.contrib.sessions",
    "django.contrib.messages",
    "django.contrib.staticfiles",
    # 新規追加
    "hello",
    # SNS登録
    "sns",
]
絶対定時退勤絶対定時退勤

データベースを設計する

【ユーザー】
    Djangoのものを使用
【メッセージ】
    owner ID:投稿者
    content:コンテンツ
    good count:goodした数
    pub_date:投稿日時

【good】
    owner ID:投稿者
    message ID:goodしたメッセージID
    pub_date:goodした日時
    pub_date:投稿日時

モデルの作成

django_app\sns\models.py
from django.db import models
from django.contrib.auth.models import User

# Create your models here.


# Message クラス
class Message(models.Model):
    # 投稿者ID(Djangoのユーザーから引っ張ってくる)
    owner = models.ForeignKey(
        User,
        on_delete=models.CASCADE,
        related_name="messge_owner",
    )

    # 投稿したコンテンツ
    content = models.TextField(
        max_length=1000,
    )

    # goodカウント
    good_count = models.IntegerField(
        default=0,
    )

    # 投稿日時:自動で作成するように設定
    pub_date = models.DateTimeField(
        auto_now_add=True,
    )

    # データの設定
    class Meta:
        # 並び順はpub_dateの古いものから
        ordering = ("-pub_date",)


# goodクラス
class Good(models.Model):
    # 投稿者
    owner = models.ForeignKey(
        User,
        on_delete=models.CASCADE,
        related_name="good_owner",
    )

    # メッセージ
    message = models.ForeignKey(
        Message,
        on_delete=models.CASCADE,
    )

    # 投稿日
    pub_date = models.DateTimeField(
        auto_now_add=True,
    )

    # 表示文字列
    def __str__(self):
        return f'"{str(self.message)}"(by {str(self.ownew)})'

    # 設定
    class Meta:
        # 並び順はpub_dateの古いものから
        ordering = ("-pub_date",)

マイグレーション実行

(system) PS F:\Django_project\django_app> python manage.py makemigrations sns
Migrations for 'sns':
  sns\migrations\0001_initial.py
    + Create model Message
    + Create model Good

テーブルの登録

django_app\sns\admin.py
from django.contrib import admin
from .models import *

# Register your models here.
# テーブルの登録
admin.site.register(Message)
admin.site.register(Good)

# 管理ツールでユーザーの登録

python manage.py runserver

http://127.0.0.1:8000/admin/にアクセスする

絶対定時退勤絶対定時退勤

フォームの作成

django_app\sns\forms.py
from django import forms
from .models import *
from django.contrib.auth.models import User


# Messageのフォーム(使わないけど一応)
from django import forms
from .models import *
from django.contrib.auth.models import User


# Messageのフォーム(使わないけど一応)
class MessageForm(forms.ModelForm):
    class Meta:
        model = Message
        fields = [
            "owner",
            "content",
        ]


# goodフォーム
class GoodForm(forms.ModelForm):
    class Meta:
        model = Good
        fields = ["owner", "message"]


# 投稿フォーム
class PostForm(forms.Form):
    content = forms.CharField(
        max_length=500,
        widget=forms.Textarea(
            attrs={
                "class": "form-control",
                "row": 2,
            }
        ),
    )

    # インスタンスを初期化するメソッド
    def __init__(self, user, *args, **kwargs):
        super(PostForm, self).__init__(*args, **kwargs)

URLの設定

snsフォルダ内に「sns.py」を作成する

django_app\sns\urls.py
from django.urls import path
from . import views


urlpatterns = [
    path(
        "",
        views.index,
        name="index",
    ),
    path(
        "<int:page>",
        views.index,
        name="index",
    ),
    path(
        "post",
        views.post,
        name="post",
    ),
    path(
        "goods",
        views.goods,
        name="goods",
    ),
    path(
        "good/<int:good_id>",
        views.good,
        name="good",
    ),
]

プロジェクト登録

django_app\django_app\urls.py
from django.contrib import admin
from django.urls import path, include

# URL(アドレス)を管理する
urlpatterns = [
    path("admin/", admin.site.urls),
    path("hello/", include("hello.urls")),
    path("sns/", include("sns.urls")),
]

views.py

django_app\sns\views.py
from django.shortcuts import render
from django.shortcuts import redirect
from django.contrib.auth.models import User
from django.contrib import messages
from django.core.paginator import Paginator
from django.db.models import Q
from django.contrib.auth.decorators import login_required

from .models import Message, Good
from .forms import PostForm


# indexビュー関数
@login_required(login_url="/admin/login")
def index(request, page=1):
    # 1ページあたりの表示数
    max = 10
    form = PostForm(request.user)
    msgs = Message.objects.all()

    # ペネトレーションで指定ページを取得
    paginate = Paginator(msgs, max)
    page_items = paginate.get_page(page)

    params = {
        "login_user": request.user,
        "form": form,
        "contents": page_items,
    }

    return render(request, "sns/index.html", params)


# goodsのビュー関数
@login_required(login_url="/admin/login")
def goods(request):
    goods = Good.objects.filter(owner=request.user).all()

    params = {
        "login_user": request.user,
        "contents": goods,
    }
    return render(request, "sns/good.html", params)


@login_required(login_url="/admin/login")
def post(request):
    # POST送信時
    if request.method == "POST":

        # 送信内容の取得
        content = request.POST["content"]

        # Messageを作成、保存
        msg = Message()
        msg.owner = request.user
        msg.content = content
        msg.save()
        return redirect(to="/sns")

    # ページ取得
    else:
        # ログインユーザーのメッセージを全て取得
        messages = Message.objects.filter(owner=request.user).all()

        params = {
            "login_user": request.user,
            "contents": messages,
        }

        return render(request, "sns/post.html", params)


# goodボタンの処理
@login_required(login_url="/admin/login")
def good(request, good_id):
    # goodするMessageを取得
    good_msg = Message.objects.get(id=good_id)

    # 自分がメッセージにgoodした回数を調べる
    is_good = Good.objects.filter(
        owner=request.user,
        messages=good_msg,
    ).count()

    # 0より大きければgood済み
    if is_good > 0:
        # システムメッセージ
        messages.success(request, "既にメッセージはGoodしています")
        return redirect(to="/sns")

    # Messageのgoodを増やす
    good_msg.good_count += 1
    good_msg.save()

    # goodを作成して設定ー>保存
    good = Good()
    good.ownew = request.user
    good.message = good_msg
    good.save()

    # メッセージを設定
    messages.success(request, "メッセージにgoodしました。")
    return redirect(to="/sns")

アノテーション

@login_required(login_url="/admin/login")

ユーザー認証を行う。

login_urlログインページのURLを指定する。
今回はログインされないと自動的にログインページにリダイレクトする

ログインユーザーの取得

request.user

システムメッセージを使用

from django.contrib import messages
messages.success(request, "既にメッセージはGoodしています")

degug,info,success,warning,erroがある

絶対定時退勤絶対定時退勤

テンプレートの用意

django_app\sns\templates\snsを作成

layout.html:全体のレイアウトを作成するテンプレート

・全てのテンプレートの土台となるもの
・全てのページの共通部分
・title:タイトル表示
・header:ページのヘッター部分
・content:ページ中央のコンテンツエリア

django_app\sns\templates\sns\layout.html
{% load static %}
<!DOCTYPE html>
<html lang="jp">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <script src="https://cdn.jsdelivr.net/npm/@popperjs/core@2.11.8/dist/umd/popper.min.js" integrity="sha384-I7E8VVD/ismYTF4hNIPjVp/Zjvgyol6VFvRkX/vR+Vc4jQkC+hVqc2pM8ODewa9r" crossorigin="anonymous"></script>
    <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.min.js" integrity="sha384-0pUGZvbkm6XF6gxjEnlmuGrJXVbNuzT9qBBavbLwCsOGabYfZo0T0to5eqruptLy" crossorigin="anonymous"></script>
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH" crossorigin="anonymous">
    <title>{% block title %}{% endblock %}</title>
</head>
<body>
    <nav class="navbar fixed-top navbar-expand navbar-light bg-light">
        <ul style="width: 100%;" class="navbar-nav mr-auto">
            <li class="nav-item">
                <a href="{% url 'index' %}" class="nav-link">top</a>
            </li>
            <li class="nav-item">
                <a href="{% url 'post' %}" class="nav-link">post</a>
            </li>
            <li class="nav-item">
                <a href="{% url 'goods' %}" class="nav-link">good</a>
            </li>
            <li class="nav-item nav-link fw-bold text-primary">
                logined:"{{login_user}}"
            </li>
        </ul>
    </nav>

    <div class="container">
        <div>
            {% block header %}
            {% endblock %}
        </div>
        <div class="content">
            {% block content %}
            {% endblock %}
        </div>
        <div class="my-3 text-center">
            <span class="font-weight-bold">
                <a href="/admin/logout?next=/sns/" class="font-weight-bold">[ logout ]</a>
            </span>
            <span class="float-right">
                copyright 2025  *******
            </span>
        </div>
    </div>
</body>
</html>

index.html:indexページのレイアウト

継承元の設定

{% extends 'sns/layout.html' %}

システムメッセージ

{% if message %}
<div class="alert alert-primary alert-dismissible fade show" role="alert">
	{% for message in messages %}
		<p>{{message}}</p>
	{% endfor %}
	<button type="button" class="btn-close" data-bs-dismiss="alert"></button>
</div>
{% endif %}

###コード全体

django_app\sns\templates\sns\index.html
{% extends 'sns/layout.html' %}

{% block title %}
    Index
{% endblock %}

{% block header %}
    <hr>
    <h1 class="display-4 text-primary">SNS</h1>
    {% if message %}
        <div class="alert alert-primary alert-dismissible fade show" role="alert">
            {% for message in messages %}
                <p>{{message}}</p>
            {% endfor %}
            <button type="button" class="btn-close" data-bs-dismiss="alert"></button>
        </div>
    {% endif %}
{% endblock %}


{% block content %}
<form action="{% url 'post' %}" method="post">
    {% csrf_token %}
    {{form.as_p}}
    <button type="button" class="btn btn-primary">Post!</button>
</form>
<hr>
<table class="table mt-3">
    <tr><th>Message</th></tr>
    {% for item in contents %}
    <tr>
        <td>
            <p class="fs-4 my-0">{{item.content}}</p>
            <p class="my-0 text-end">
                <span class="fs-5">"{{item.owner}}"</span>
                <span class="fs-5">({{item.pub_date}})</span>
            </p>
            <p class="mt-1 fs-6 text-end">
                <span class="h6 text-primary">good={{item.good_count}}</span>
                <span class="float-right">
                    {% if item.owner != login_user %}
                    <a href="{% url 'good' item.id %}">
                        <button class="py-0 px-1 btn btn-outline-primary">good!</button>
                    </a>
                    {% endif %}
                </span>
            </p>
        </td>
    </tr>
    {% endfor %}
</table>

<ul class="pagination justify-content-center">
    {% if contents.has_previous %}
    <li class="page-item">
        <a href="/sns/" class="page-link">&laquo; first</a>
    </li>
    <li class="page-item">
        <a href="/sns/{{contents.previous_page_number}}" class="page-link">&laquo; prev</a>
    </li>
    {% else %}
    <li class="page-item">
        <a href="/sns/" class="page-link">&laquo; first</a>
    </li>
    <li class="page-item">
        <a class="page-link">&laquo; prev</a>
    </li>
    {% endif %}
    <li class="page-item">
        <a href="" class="page-link">{{contents.number}}/{{contents.paginator.num_pages}}</a>
    </li>

    {% if contents.has_next %}
    <li class="page-item">
        <a href="/sns/{{ contents.next_page_number }}" class="page-link">next &raquo;</a>
    </li>
    <li class="page-item">
        <a href="/sns/{{contents.paginator.num_pages}}" class="page-link">last &raquo;</a>
    </li>
    {% else %}
    <li class="page-item">
        <a href="" class="page-link">next &raquo;</a>
    </li>
    <li class="page-item">
        <a href="" class="page-link">last &raquo;</a>
    </li>
    {% endif %}
</ul>
{% endblock %}

post.html:Postページのレイアウト

django_app\sns\templates\sns\post.html
{% extends 'sns/layout.html' %}

{% block title %}
    Post
{% endblock %}

{% block header %}
<hr>
<h1 class="display-4 test-primary">Post</h1>
<p class="caption">※メッセージを投稿します</p>
{% endblock %}

{% block content %}
<table class="table mt-3">
    <tr>
        <th>Message</th>
    </tr>
    {% for item in contents %}
    <tr>
        <td>
            <p class="fs-5 my-0">{{item.content}}</p>
            <p class="fs-5 my-0">({{item.pub_date}})</p>
            <p class="text-end my-0 text-info">good={{item.good_count}}</p>
        </td>
    </tr>
    {% endfor %}
</table>
{% endblock %}

good.html:goodページのレイアウト

django_app\sns\templates\sns\good.html
{% extends 'sns/layout.html' %}

{% block title %}
Good
{% endblock %}

{% block header %}
<hr>
<h1 class="display-4 text-primary">Goods</h1>
<p class="caption">※Goodしたメッセージ</p>
{% endblock %}

{% block content %}
<table class="table mt-3">
    <tr>
        <th>Message</th>
    </tr>
    <tr>
        <td>
            {% for item in contents %}
            <p class="fs-5">{{item}}</p>
            {% endfor %}
        </td>
    </tr>
</table>
{% endblock %}