【Django】簡単なSNSアプリを開発する⑥ ~CRUDモデルの作成~
スポンサードリンク
おはようございます。Shotaです。
今回も前回に引き続き、DjangoでSNSアプリを開発するための方法を解説していきます。
今回はCRUDモデルの作成について解説します。
▼前回の記事はコチラ
shotanukumizu-1000.hatenablog.com
▼初回の記事はコチラ
shotanukumizu-1000.hatenablog.com
CRUDモデルとは
実装
投稿内容の詳細表示(Read
)
まずはtemplate/index.html
に以下のコードを書いてください。
{% extends 'base.html' %} {% block title %} <title>投稿内容</title> {% endblock title %} {% block header %} <div class="container is-fullhd"> <div class="notification is-primary"> <h1><i class="fas fa-globe"></i>Sample SNS Application</h1> <h3>~仕事の仲間と気軽に交流を楽しみましょう!!~</h3> </div> </div> {% endblock header %} {% block content %} {% if user.is_authenticated %} <div class="container"> {% for item in object_list %} <div class="card"> <h5 class="card-header">投稿日 {{ item.created_at }}</h5> <h5 class="card-header">投稿者 {{ item.name }}</h5> <div class="card-body"> <span class="tag is-{{ item.tag }} is-large"> <h5 class="card-title">{{ item.title }}</h5> </span> <!---追加------> <a href="{% url 'detail' item.pk %}" class="button is-primary is-light"><i class="fas fa-info-circle"></i>詳細</a> </div> </div> {% endfor %} <a href="{% url 'logout' %}" class="button is-link">ログアウト</a> </div> {% else %} please login. <a href="{% url 'login' %}">ログイン</a> {% endif %} {% endblock content %}
次に、_app/views.py
にアクセスして以下のコードを書いてください。
▼書くコード
def detailfunc(request, pk): item = get_object_or_404(ArticleModel, pk=pk) return render(request, 'detail.html', {'item': item})
▼全体
#_app/views.py from .models import ArticleModel from django.db import IntegrityError from django.shortcuts import render, redirect from django.contrib.auth import authenticate, login, logout from django.contrib.auth.models import User from django.contrib.auth.decorators import login_required def signupfunc(request): if request.method == 'POST': username = request.POST['username'] password = request.POST['password'] try: user = User.objects.create_user(username, '', password) return render(request, 'login.html', {}) except IntegrityError: return render(request, 'signup.html', {'error': 'このユーザはすでに登録されています'}) return render(request, 'signup.html', {}) def loginfunc(request): if request.method == 'POST': username = request.POST['username'] password = request.POST['password'] user = authenticate(request, username=username, password=password) if user is not None: login(request, user) return redirect('index') else: return render(request, 'login.html', {}) return render(request, 'login.html', {}) @login_required def index_func(request): object_list = ArticleModel.objects.all() return render(request, 'index.html', {'object_list': object_list}) def logoutfunc(request): logout(request) return redirect('login') #追加 def detailfunc(request, pk): item = get_object_or_404(ArticleModel, pk=pk) return render(request, 'detail.html', {'item': item})
次に、詳細ページにアクセスできるように以下のコードを書いてください。
#_app/urls.py from django.urls import path from . import views urlpatterns = [ path('', views.index_func, name='index'), path('signup/', views.signupfunc, name='signup'), path('login/', views.loginfunc, name='login'), path('logout/', views.logoutfunc, name='logout'), path('detail/<int:pk>', views.detailfunc, name='detail'), #追加 ]
次に、DjangoのテンプレートにMarkdownを反映させるための処理を書きます。
_app
フォルダの下にtemplatetags
フォルダを作成して、markdown_extras.py
を作成し以下のコードを書いてください。
#_app/templatetags/markdown_extras.py from django import template from django.template.defaultfilters import stringfilter import markdown as md register = template.Library() @register.filter @stringfilter def markdown(val): return md.markdown(val, extensions=['markdown.extensions.fenced_code'])
これが終了したら、以下のコードを書いてデータベースに反映させてください。
$ python manage.py makemigrations $ python manage.py migrate
あとは、templates
フォルダにdetail.html
を作成して以下のコードを書いてください。
<!----templates/detail.html------> {% extends 'base.html' %} {% load markdown_extras %} {% block static %} <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.3.1/styles/github.min.css"> <script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.3.1/highlight.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.3.1/languages/plaintext.min.js"></script> <script>hljs.initHighlightingOnLoad();</script> {% endblock static %} {% block title %} <title>記事の詳細</title> <hr> {% endblock title %} {% block content %} {% if user.is_authenticated %} <div class="notification is-{{ item.tag }}"> <h2>{{ item.title }}</h2> <hr> <h4>投稿者:{{ item.name }}</h4> </div> <p>画像</p> <hr> <img src="{{ item.image.url }}" alt="投稿画像"> <p>内容</p> <p>{{ item.content|markdown|safe }}</p> <a href="{% url 'index' %}" class="button is-primary is-outlined">戻る</a> {% else %} Please Login {% endif %} {% endblock content %}
highlightjsをインストールしましょう。以下のコードを入力する(htmlのhead
要素に)だけで簡単に実装できます。
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.3.1/styles/github.min.css"> <script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.3.1/highlight.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.3.1/languages/plaintext.min.js"></script> <script>hljs.initHighlightingOnLoad();</script>
投稿内容の作成(Create
)
次に、記事を作成する機能を実装していきます。
まずはtemplates/index.html
に記事を作成するためのページにアクセスするためのボタンを作成しましょう。
{% extends 'base.html' %} {% block title %} <title>投稿内容</title> {% endblock title %} {% block header %} <div class="container is-fullhd"> <div class="notification is-primary"> <h1><i class="fas fa-globe"></i>Sample SNS Application</h1> <h3>~仕事の仲間と気軽に交流を楽しみましょう!!~</h3> </div> </div> {% endblock header %} {% block content %} {% if user.is_authenticated %} <div class="container"> <!---追加------> <a href="{% url 'create' %}" class="button is-link is-large"><i class="fas fa-plus"></i>投稿する</a> {% for item in object_list %} <div class="card"> <h5 class="card-header">投稿日 {{ item.created_at }}</h5> <h5 class="card-header">投稿者 {{ item.name }}</h5> <div class="card-body"> <span class="tag is-{{ item.tag }} is-large"> <h5 class="card-title">{{ item.title }}</h5> </span> <a href="{% url 'detail' item.pk %}" class="button is-primary is-light"><i class="fas fa-info-circle"></i>詳細</a> </div> </div> {% endfor %} <a href="{% url 'logout' %}" class="button is-link">ログアウト</a> </div> {% else %} please login. <a href="{% url 'login' %}">ログイン</a> {% endif %} {% endblock content %}
次に、_app/views.py
にアクセスして以下のコードを書いてください。
▼追加するコード
class ArticleCreate(CreateView): template_name = 'create.html' model = ArticleModel fields = {'title', 'content', 'image', 'name', 'tag'} success_url = reverse_lazy('index')
▼全体
#_app/views.py from .models import ArticleModel from django.urls import reverse_lazy from django.db import IntegrityError from django.shortcuts import get_object_or_404, render, redirect from django.contrib.auth import authenticate, login, logout from django.views.generic import CreateView, UpdateView from django.contrib.auth.models import User from django.contrib.auth.decorators import login_required def signupfunc(request): if request.method == 'POST': username = request.POST['username'] password = request.POST['password'] try: user = User.objects.create_user(username, '', password) return render(request, 'login.html', {}) except IntegrityError: return render(request, 'signup.html', {'error': 'このユーザはすでに登録されています'}) return render(request, 'signup.html', {}) def loginfunc(request): if request.method == 'POST': username = request.POST['username'] password = request.POST['password'] user = authenticate(request, username=username, password=password) if user is not None: login(request, user) return redirect('index') else: return render(request, 'login.html', {}) return render(request, 'login.html', {}) @login_required def index_func(request): object_list = ArticleModel.objects.all() return render(request, 'index.html', {'object_list': object_list}) def logoutfunc(request): logout(request) return redirect('login') def detailfunc(request, pk): item = get_object_or_404(ArticleModel, pk=pk) return render(request, 'detail.html', {'item': item}) #追加 class ArticleCreate(CreateView): template_name = 'create.html' model = ArticleModel fields = {'title', 'content', 'image', 'name', 'tag'} success_url = reverse_lazy('index')
次に、ルーティングを有効にするため_app/urls.py
にアクセスして以下のコードを書いてください。
#_app/urls.py from django.urls import path from . import views urlpatterns = [ path('', views.index_func, name='index'), path('signup/', views.signupfunc, name='signup'), path('login/', views.loginfunc, name='login'), path('logout/', views.logoutfunc, name='logout'), path('detail/<int:pk>', views.detailfunc, name='detail'), path('create/', views.ArticleCreate.as_view(), name='create'), #追加 ]
最後に、templates
フォルダにアクセスしてcreate.html
を作成し、以下のコードを書いてください。
{% extends 'base.html' %} {% block title %} <title>投稿の作成</title> {% endblock title %} {% block header %} <h1>投稿の作成</h1> <hr> {% endblock header %} {% block content %} {% if user.is_authenticated %} <form method="POST" enctype="multipart/form-data">{% csrf_token %} <p>title: <input type="text" name="title"></p> <div class="form-floating"> <textarea class="form-control" placeholder="Leave a comment here" id="floatingTextarea2" style="height: 200px" name="content"></textarea> <label for="floatingTextarea2">Contents</label> </div> <p><input type="file" name="image"></p> <input type="hidden" name="name" value="{{ user.username }}"> <select name="tag" id="choice"> <option value="danger">重要</option> <option value="warning">連絡</option> <option value="info">イベント</option> <option value="success">その他</option> </select> <input type="submit" value="作成する" class="button is-success is-light"> </form> {% else %} Please Login {% endif %} {% endblock content %}
これで投稿を作成する機能を実装できました。
投稿内容の編集(Update
)
まずは、_app/views.py
で以下のコードを書いてください。
#_app/views.py from .models import ArticleModel from django.urls import reverse_lazy from django.db import IntegrityError from django.shortcuts import get_object_or_404, render, redirect from django.contrib.auth import authenticate, login, logout from django.views.generic import CreateView, UpdateView from django.contrib.auth.models import User from django.contrib.auth.decorators import login_required def signupfunc(request): if request.method == 'POST': username = request.POST['username'] password = request.POST['password'] try: user = User.objects.create_user(username, '', password) return render(request, 'login.html', {}) except IntegrityError: return render(request, 'signup.html', {'error': 'このユーザはすでに登録されています'}) return render(request, 'signup.html', {}) def loginfunc(request): if request.method == 'POST': username = request.POST['username'] password = request.POST['password'] user = authenticate(request, username=username, password=password) if user is not None: login(request, user) return redirect('index') else: return render(request, 'login.html', {}) return render(request, 'login.html', {}) @login_required def index_func(request): object_list = ArticleModel.objects.all() return render(request, 'index.html', {'object_list': object_list}) def logoutfunc(request): logout(request) return redirect('login') def detailfunc(request, pk): item = get_object_or_404(ArticleModel, pk=pk) return render(request, 'detail.html', {'item': item}) class ArticleCreate(CreateView): template_name = 'create.html' model = ArticleModel fields = {'title', 'content', 'image', 'name', 'tag'} success_url = reverse_lazy('index') #追加 class ArticleUpdate(UpdateView): template_name = 'update.html' model = ArticleModel fields = {'title', 'content', 'image', 'name', 'tag'} success_url = reverse_lazy('index')
次に、ルーティングを設定するために以下のコードを書いてください。
#_app/urls.py from django.urls import path from . import views urlpatterns = [ path('', views.index_func, name='index'), path('signup/', views.signupfunc, name='signup'), path('login/', views.loginfunc, name='login'), path('logout/', views.logoutfunc, name='logout'), path('create/', views.ArticleCreate.as_view(), name='create'), path('update/<int:pk>', views.ArticleUpdate.as_view(), name='update'), #追加 path('detail/<int:pk>', views.detailfunc, name='detail'), ]
最後に、templates
フォルダにアクセスしてdetail.html
を作成し、以下のコードを書いてください。
{% extends 'base.html' %} {% block title %} <title>投稿の編集</title> <hr> {% endblock title %} {% block content %} {% if user.is_authenticated %} <form method="POST" enctype="multipart/form-data">{% csrf_token %} <p>title: <input type="text" name="title"></p> <div class="form-floating"> <textarea class="form-control" placeholder="Leave a comment here" id="floatingTextarea2" style="height: 200px" name="content"></textarea> <label for="floatingTextarea2">Contents</label> </div> <p><input type="file" name="image"></p> <input type="hidden" name="name" value="{{ user.username }}"> <select name="tag" id="choice"> <option value="danger">重要</option> <option value="warning">連絡</option> <option value="info">イベント</option> <option value="success">その他</option> </select> <input type="submit" value="update" class="button is-success is-light"> </form> {% else %} Please Login {% endif %} {% endblock content %}
これで投稿記事を編集する機能は完成です。
投稿内容の削除(Delete
)
最後に投稿内容を削除する機能を実装しましょう。
_app/views.py
にアクセスして、以下のコードを書いてください。
▼追加するコード
def deletefunc(request, pk): item = ArticleModel.objects.delete(pk=pk) return redirect('index')
▼全体
#_app/views.py from .models import ArticleModel from django.urls import reverse_lazy from django.db import IntegrityError from django.shortcuts import get_object_or_404, render, redirect from django.contrib.auth import authenticate, login, logout from django.views.generic import CreateView, UpdateView from django.contrib.auth.models import User from django.contrib.auth.decorators import login_required def signupfunc(request): if request.method == 'POST': username = request.POST['username'] password = request.POST['password'] try: user = User.objects.create_user(username, '', password) return render(request, 'login.html', {}) except IntegrityError: return render(request, 'signup.html', {'error': 'このユーザはすでに登録されています'}) return render(request, 'signup.html', {}) def loginfunc(request): if request.method == 'POST': username = request.POST['username'] password = request.POST['password'] user = authenticate(request, username=username, password=password) if user is not None: login(request, user) return redirect('index') else: return render(request, 'login.html', {}) return render(request, 'login.html', {}) @login_required def index_func(request): object_list = ArticleModel.objects.all() return render(request, 'index.html', {'object_list': object_list}) def logoutfunc(request): logout(request) return redirect('login') def detailfunc(request, pk): item = get_object_or_404(ArticleModel, pk=pk) return render(request, 'detail.html', {'item': item}) def deletefunc(request, pk): item = ArticleModel.objects.delete(pk=pk) return redirect('index') class ArticleCreate(CreateView): template_name = 'create.html' model = ArticleModel fields = {'title', 'content', 'image', 'name', 'tag'} success_url = reverse_lazy('index') class ArticleUpdate(UpdateView): template_name = 'update.html' model = ArticleModel fields = {'title', 'content', 'image', 'name', 'tag'} success_url = reverse_lazy('index')
次に、ルーティングを有効にするため_app/urls.py
にアクセスして以下のコードを書いてください。
#_app/urls.py from django.urls import path from . import views urlpatterns = [ path('', views.index_func, name='index'), path('signup/', views.signupfunc, name='signup'), path('login/', views.loginfunc, name='login'), path('logout/', views.logoutfunc, name='logout'), path('create/', views.ArticleCreate.as_view(), name='create'), path('update/<int:pk>', views.ArticleUpdate.as_view(), name='update'), path('detail/<int:pk>', views.detailfunc, name='detail'), path('delete/<int:pk>', views.deletefunc, name='delete'), #追加 ]
あとは、template/index.html
に記事を削除するためのボタンを付けて終了です。
{% extends 'base.html' %} {% block title %} <title>投稿内容</title> {% endblock title %} {% block header %} <div class="container is-fullhd"> <div class="notification is-primary"> <h1><i class="fas fa-globe"></i>Sample SNS Application</h1> <h3>~仕事の仲間と気軽に交流を楽しみましょう!!~</h3> </div> </div> {% endblock header %} {% block content %} {% if user.is_authenticated %} <div class="container"> <a href="{% url 'create' %}" class="button is-link is-large"><i class="fas fa-plus"></i>投稿する</a> {% for item in object_list %} <div class="card"> <h5 class="card-header">投稿日 {{ item.created_at }}</h5> <h5 class="card-header">投稿者 {{ item.name }}</h5> <div class="card-body"> <span class="tag is-{{ item.tag }} is-large"> <h5 class="card-title">{{ item.title }}</h5> </span> <a href="{% url 'detail' item.pk %}" class="button is-primary is-light"><i class="fas fa-info-circle"></i>詳細</a> {% if user.username == item.name %} <a href="{% url 'update' item.pk %}" class="button is-success is-light"><i class="fas fa-pen"></i>編集する</a> <!------追加--------> <a href="{% url 'delete' item.pk %}" class="button is-danger is-light"><i class="fas fa-trash-alt"></i>削除する</a> {% endif %} </div> </div> {% endfor %} <a href="{% url 'logout' %}" class="button is-link">ログアウト</a> </div> {% else %} please login. <a href="{% url 'login' %}">ログイン</a> {% endif %} {% endblock content %}
これで簡単なSNSアプリが完成しました!
おわりに
今回の記事では、DjangoでCRUDモデルを実装するための方法を解説しました。
今回の記事をもって、これでDjangoで簡単なSNSアプリを開発できるようになりました。
今回までの計6回の記事を参考に、Djangoでログイン機能付きのアプリやCRUDモデルの実装、SNSアプリケーションの仕組みについて理解を深めていただければ幸いです。
完成したソースコードは以下のリンクにアクセスすれば誰でも見られます。よければ参考にしてみてください。
今回の記事はこれで終了です。