SNSの作成
アプリを設計する
- 機能の洗い出し
- データベース設計
- 各ページの設計
アプリの作成
python manage.py startapp sns
アプリの登録
# 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のものを使用
【メッセージ】
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
テーブルの登録
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/
にアクセスする
からユーザ追加をする
こんなかんじ
フォームの作成
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」を作成する
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",
),
]
プロジェクト登録
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
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がある
アプリを設計する
- 機能の洗い出し
- データベース設計
- 各ページの設計
アプリの作成
python manage.py startapp sns
アプリの登録
# 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:投稿日時
モデルの作成
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
テーブルの登録
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/
にアクセスする
フォームの作成
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」を作成する
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",
),
]
プロジェクト登録
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
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:ページ中央のコンテンツエリア
{% 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 %}
###コード全体
{% 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">« first</a>
</li>
<li class="page-item">
<a href="/sns/{{contents.previous_page_number}}" class="page-link">« prev</a>
</li>
{% else %}
<li class="page-item">
<a href="/sns/" class="page-link">« first</a>
</li>
<li class="page-item">
<a class="page-link">« 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 »</a>
</li>
<li class="page-item">
<a href="/sns/{{contents.paginator.num_pages}}" class="page-link">last »</a>
</li>
{% else %}
<li class="page-item">
<a href="" class="page-link">next »</a>
</li>
<li class="page-item">
<a href="" class="page-link">last »</a>
</li>
{% endif %}
</ul>
{% endblock %}
post.html:Postページのレイアウト
{% 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ページのレイアウト
{% 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 %}