Djangoã¡ã¢(16) : ãã©ã¼ã APIã使ããã«ãã©ã¼ã ãä½æ
- ãã©ã¼ã ã表示ãããã¼ã¸ä½æ
- ãã©ã¼ã ä½æ
- ãã¥ã¼ã®å¦ç
- Topicä¸è¦§è¡¨ç¤º
- Topicä½æãã¿ã³è¿½å
- ã¾ã¨ã
A Complete Beginner's Guide to Djangoã®ãã¥ã¼ããªã¢ã«ãåèã«ãã©ã¼ã ãä½æãã¦ã¿ãã
ãã©ã¼ã ã表示ãããã¼ã¸ä½æ
Djangoã§ã¯ãã©ã¼ã APIã使ã£ã¦ãã©ã¼ã ãä½æããããç解ãæ·±ããããã«ã¾ãã¯ãã©ã¼ã APIã使ããã«ãã©ã¼ã ãä½æãã¦ã¿ããããã¦ããã®å¾ã§ãã©ã¼ã APIã使ã£ã¦ãã©ã¼ã ãä½æããã
ä»åä½æãããã©ã¼ã ã¯æ°ããTopicï¼Boardå
ã®ã¹ã¬ããï¼ã¨Postï¼Topicã«å¯¾ããè¿ä¿¡ã ããTopicä½ææã®ã¡ãã»ã¼ã¸ãå«ãï¼ãä½æãããã©ã¼ã ã§å®æå½¢ã¯ä¸å³ãå®éã¯èª°ãTopicã¨Postãä½æãããã管çãããã¦ã¼ã¶èªè¨¼çã«ã¤ãã¦ã¯å¾ã§èããã
æåã«ãã©ã¼ã ã表示ãããã¼ã¸ãä½æããããã«URLconfãä¿®æ£ãã¦new_topic
ã®è¡ã追å ããã
from django.contrib import admin from django.conf import settings from django.urls import path, include from boards import views urlpatterns = [ path('', views.home, name='home'), path('boards/<int:pk>/', views.board_topics, name='board_topics'), path('boards/<int:pk>/new/', views.new_topic, name='new_topic'), path('admin/', admin.site.urls), ]
次ã«boards/views.py
ã«new_topic()
ã追å ããã
from django.shortcuts import render, get_object_or_404 from .models import Board def new_topic(request, pk): board = get_object_or_404(Board, pk=pk) return render(request, 'new_topic.html', {'board': board})
ããã¦templates/new_topic.html
ã¨ãããã³ãã¬ã¼ããä½æããã
{% extends 'base.html' %} {% block title %}Start a New Topic{% endblock %} {% block breadcrumb %} <li class="breadcrumb-item"><a href="{% url 'home' %}">Boards</a></li> <li class="breadcrumb-item"><a href="{% url 'board_topics' board.pk %}">{{ board.name }}</a></li> <li class="breadcrumb-item active">New topic</li> {% endblock %} {% block content %} {% endblock %}
ããã§boards/1/new/
ã«ã¢ã¯ã»ã¹ããã¨ãã³ãããªã¹ãã表示ãããããã«ãªãã
new_topic
ç¨ã®ãã¹ãã追å ãã¦ãããåã«ä½æãããã¹ãã¨ã»ã¼åãã ãnew_topic
ã®importãå¿ããªããã¨ã
from django.urls import reverse, resolve from django.test import TestCase from .views import home, board_topics, new_topic from .models import Board class HomeTests(TestCase): # ... class BoardTopicsTests(TestCase): # ... class NewTopicTests(TestCase): def setUp(self): Board.objects.create(name='Django', description='Django board.') def test_new_topic_view_success_status_code(self): url = reverse('new_topic', kwargs={'pk': 1}) response = self.client.get(url) self.assertEquals(response.status_code, 200) def test_new_topic_view_not_found_status_code(self): url = reverse('new_topic', kwargs={'pk': 99}) response = self.client.get(url) self.assertEquals(response.status_code, 404) def test_new_topic_url_resolves_new_topic_view(self): view = resolve('/boards/1/new/') self.assertEquals(view.func, new_topic) def test_new_topic_view_contains_link_back_to_board_topics_view(self): new_topic_url = reverse('new_topic', kwargs={'pk': 1}) board_topics_url = reverse('board_topics', kwargs={'pk': 1}) response = self.client.get(new_topic_url) self.assertContains(response, 'href="{0}"'.format(board_topics_url))
ãã¹ããéããã¨ã確èªã
$ python manage.py test Creating test database for alias 'default'... System check identified no issues (0 silenced). ........... ---------------------------------------------------------------------- Ran 11 tests in 0.051s OK Destroying test database for alias 'default'...
ãã©ã¼ã ä½æ
ãã¼ã¸ãã§ããã®ã§ãã©ã¼ã ãä½æããã
templates/new_topic.html
ã®{% block content %}
å
ã以ä¸ã®ããã«ç·¨éããã
{% extends 'base.html' %} {% block title %}Start a New Topic{% endblock %} {% block breadcrumb %} <li class="breadcrumb-item"><a href="{% url 'home' %}">Boards</a></li> <li class="breadcrumb-item"><a href="{% url 'board_topics' board.pk %}">{{ board.name }}</a></li> <li class="breadcrumb-item active">New topic</li> {% endblock %} {% block content %} <form method="post"> {% csrf_token %} <div class="form-group"> <label for="id_subject">Subject</label> <input type="text" class="form-control" id="id_subject" name="subject"> </div> <div class="form-group"> <label for="id_message">Message</label> <textarea class="form-control" id="id_message" name="message" rows="5"></textarea> </div> <button type="submit" class="btn btn-success">Post</button> </form> {% endblock %}
ããã§Bootstrap 4ã®CSSã¯ã©ã¹ãé©ç¨ããããã©ã¼ã ã表示ãããã
æ°ããTopicãä½æããã®ã§<form method="post">
ã¨POSTã¡ã½ããã使ç¨ããããDjangoã§ã¯POSTã¡ã½ããã使ç¨ããå ´åã¯CSRF(Cross-site Request Forgery)対çã¨ãã¦CSRFãã¼ã¯ã³ã渡ãå¿
è¦ãããã
{% csrf_token %}
ããã®ã¿ã°ã§ä»¥ä¸ã®ãããªHTMLã«å¤æãããã
<input type='hidden' name='csrfmiddlewaretoken' value='a9tL0UDbdkCA5R372UD4zbUHH3qxx6hq2zcov43t5rhUDWQY9BRduzLfIHUmq5KB' />
ãã®ä»ãinputã¿ã°ã®nameå±æ§ã§æå®ããå¤ã¯ã
<input type="text" class="form-control" id="id_subject" name="subject"> <textarea class="form-control" id="id_message" name="message" rows="5"></textarea>
ãã¥ã¼å´ã§ä»¥ä¸ã®ããã«æå®ãããã¨ã§åç §ã§ããã
subject = request.POST['subject'] message = request.POST['message']
ãã¥ã¼ã®å¦ç
ãã©ã¼ã ã§å
¥åããããã¼ã¿ãåãåã£ã¦æ°ããTopicã¨Postãä½æãããã¥ã¼ã®å¦çãboards/views.py
ã«è¨è¿°ããã
from django.contrib.auth.models import User from django.shortcuts import render, redirect, get_object_or_404 from .models import Board, Topic, Post def new_topic(request, pk): board = get_object_or_404(Board, pk=pk) if request.method == 'POST': subject = request.POST['subject'] message = request.POST['message'] user = User.objects.first() # TODO: get the currently logged in user topic = Topic.objects.create( subject=subject, board=board, starter=user ) post = Post.objects.create( message=message, topic=topic, created_by=user ) return redirect('board_topics', pk=board.pk) # TODO: redirect to the created topic page return render(request, 'new_topic.html', {'board': board})
ãã©ã¼ã APIã使ãã°æªå
¥åãã§ãã¯ããmax_lengthãè¶
ããå ´åã®ããªãã¼ã·ã§ã³ãã§ããããä¸è¨ã®å¦çã¯å
¥åãé©åãªå ´åããèæ
®ããã¦ããªãã®ã§æ³¨æã
if request.method == 'POST':
ã®åå²ã¯POSTã¡ã½ããã®å ´åãã¤ã¾ããã©ã¼ã ã§å
¥åããã¦éä¿¡ãããå ´åã¯ãã®å¦çãéããä¸æ¹ãGETã¡ã½ããã ã£ãå ´åãã¤ã¾ããã©ã¦ã¶ã§æ®éã«ã¢ã¯ã»ã¹ããå ´åã¯ãã®å¦çã¯éããã«render()
ãå¼ã°ããã®ã§ãã©ã¼ã ã表示ããããã¨ã«ãªãã
ã¦ã¼ã¶èªè¨¼ã«ã¤ãã¦ã¯ã¾ã æ¤è¨ãã¦ããªãã®ã§User.objects.first()
ã§ä¸çªæåã®ã¦ã¼ã¶ï¼ãã®å ´åã¯admin
ã¦ã¼ã¶ï¼ãåå¾ãã¦ããã
Topic.objects.create
ã®board=board
ãPost.objects.create
ã®topic=topic
ã®ããã«ã¢ãã«ã§ForeignKey()
ãæå®ããç®æã¯ãã®ããã«ãã¦é¢é£ä»ããã
ã¾ããTopicã¨Postä¸è¦§ã表示ãããã¼ã¸ã¯ã¾ã ä½æãã¦ããªãã®ã§å¦çãå®äºãããboard_topics
ãã¼ã¸ã«ãªãã¤ã¬ã¯ãããããã«ããã
ãã¥ã¼ã®å¦çãè¨è¿°ããã®ã§Subjectã¨Messageã«å¤ãå ¥åããå¾ã§Postãã¿ã³ãã¯ãªãã¯ããã
ãã¼ã¸ããªãã¤ã¬ã¯ãããç»é²ã¯å®äºãã¦ããããã ããTopicä¸è¦§ã表示ããå¦çãæ¸ãã¦ããªãã®ã§ä½ã表示ãããªãã
Topicä¸è¦§è¡¨ç¤º
Topicä¸è¦§ã表示ããããã«templates/topics.html
ãç·¨éããã
{% extends 'base.html' %} {% block title %} {{ board.name }} - {{ block.super }} {% endblock %} {% block breadcrumb %} <li class="breadcrumb-item"><a href="{% url 'home' %}">Boards</a></li> <li class="breadcrumb-item active">{{ board.name }}</li> {% endblock %} {% block content %} <table class="table"> <thead class="thead-dark"> <tr> <th>Topic</th> <th>Starter</th> <th>Replies</th> <th>Views</th> <th>Last Update</th> </tr> </thead> <tbody> {% for topic in board.topics.all %} <tr> <td>{{ topic.subject }}</td> <td>{{ topic.starter.username }}</td> <td>0</td> <td>0</td> <td>{{ topic.last_updated }}</td> </tr> {% endfor %} </tbody> </table> {% endblock %}
ããã§å
ã»ã©ç»é²ããTopicã表示ãããããã«ãªãã
Boardã¨Topicã¯1対å¤ã®é¢ä¿ã®ãããBoardã«ã¯è¤æ°ã®Topicãé¢é£ä»ãããã¦ããããããã¯{% for topic in board.topics.all %}
ã®ããã«ãã¦åãåºããã¨ãã§ããï¼ãã³ãã¬ã¼ãè¨èªã§ã¯all()
ã§ã¯ãªãall
ã¨ãªãï¼ã
ã¾ããé¢é£ä»ãããã¦ããã¢ãã«ã®å±æ§ã«ã¯{{ topic.starter.username }}
ã®ããã«.
ã§ç¹ãã¦ã¢ã¯ã»ã¹ã§ããã
Topicä½æãã¿ã³è¿½å
ãã©ã¼ã ã¯ä½æã§ããã®ã§templates/topics.html
ãç·¨éãã¦Topicãä½æãããã¿ã³ã追å ããã
{% block content %} <div class="mb-4"> <a href="{% url 'new_topic' board.pk %}" class="btn btn-primary">New topic</a> </div> <table class="table"> <!-- ã³ã¼ãã¯çç¥ --> </table> {% endblock %}
ããã¦ããã®ãã¿ã³ãªã³ã¯ããã¹ãããããã«æ¢ã«ä½æãã¦ããtest_board_topics_view_contains_link_back_to_homepage()
ãä¸è¨ãã¹ãåã«ãªãã¼ã ãã¦assertContains()
ã追å ãã¦ããã
class BoardTopicsTests(TestCase): # ... def test_board_topics_view_contains_navigation_links(self): board_topics_url = reverse('board_topics', kwargs={'pk': 1}) homepage_url = reverse('home') new_topic_url = reverse('new_topic', kwargs={'pk': 1}) response = self.client.get(board_topics_url) self.assertContains(response, 'href="{0}"'.format(homepage_url)) self.assertContains(response, 'href="{0}"'.format(new_topic_url))
以ä¸ã®ããã«ãã©ã¼ã APIã使ããã«ãã©ã¼ã ãä½æãããã¨ã¯ã§ãããããªãã¼ã·ã§ã³ãªã©ãã§ãã¦ããªãããã次åã¯ãã©ã¼ã APIã使ã£ã¦ãã©ã¼ã ãä½æããã
ã¾ã¨ã
- POSTã¡ã½ããã§ã¯CSRF対çã¨ãã¦CSRFãã¼ã¯ã³ã渡ãå¿ è¦
{% csrf_token %}
ã§CSRFãã¼ã¯ã³ãçæ- ãã¥ã¼å´ã§ã¯inputã¿ã°ã®nameå±æ§ã®å¤ã
request.POST['subject']
ã®ããã«æå® - ãã³ãã¬ã¼ãè¨èªã§ã¯
{% for topic in board.topics.all %}
ã®ããã«ã«ã¼ã - é¢é£ä»ãããã¦ããã¢ãã«ã®å±æ§ã«ã¯
{{ topic.starter.username }}
ã®ããã«ã¢ã¯ã»ã¹