サイドバーの「Django ドキュメント検索」というプレースホルダの入った検索では、Django ドキュメント (Django 2.1) の公式サイト内を検索できます
Django チュートリアルの進め方 その 5 (2)

目次

はじめに

Django を学習するには、何はともあれ公式チュートリアル「はじめての Django アプリ作成」からスタートしてみるのが良いでしょう。しかし、いざチュートリアル通りに進めようとしても躓く場合も多いと思います。そこで、「チュートリアルの進め方」シリーズとして、チュートリアルに沿った作業を行いながら補足事項をまとめることにしました。チュートリアルで躓いた際のヒントとしてお使いください。

利用環境は Ubuntu、 Linux Mint を中心として説明しますが、 Windows についても補足します。

前回は、Django チュートリアルの進め方 その 5 (1) と題してはじめての Django アプリ作成、その 5の前半についてまとめました。

今回は、はじめての Django アプリ作成、その 5 の後半についてまとめました。

ビューをテストする

Django テストクライアント

シェルを開いてテスト環境をセットアップします。(setup_test_environment() の実行)

>>> from django.test.utils import setup_test_environment
>>> setup_test_environment()

次に、テストクライアントを作成します。

>>> from django.test import Client
>>> client = Client()

まず、ルート (http://localhost:8000/) にアクセスしてみます。

ブラウザでは下記のような画面になります。


404 エラー (今回は正常動作) になります。
シェルからのアクセスは下記のようになります。

>>> response = client.get('/')
Not Found: /
>>> response.status_code
404

Not Found (404 エラーに相当) になります。
次に、polls/index にアクセスします。ブラウザの表示画面とシェルのコマンドは下記のとおりです。

shell 上ではアドレスをハードコードせずに、 reverse('polls:index') としてアクセスします。

>>> from django.urls import reverse
>>> response = client.get(reverse('polls:index'))
>>> response.status_code
200

ステータスコード200 = 成功です。
表示内容を確認します。

>>> response.content
b'\n    <ul>\n    \n        <li><a href="/polls/1/">What&#39;s up?</a></li>\n    \n    </ul>\n'

コンテキストの内容 (テンプレートに渡した変数) を確認します。

>>> response.context['latest_question_list']
<QuerySet [<Question: What's up?>]>

 

ビューを改良する

Polls.IndexVew が未来日付を公開しないように修正します。

from django.utils import timezone
from django.http import HttpResponseRedirect
from django.shortcuts import get_object_or_404, render
from django.urls import reverse
from django.views import generic
from django.db.models import F

from .models import Choice, Question


class IndexView(generic.ListView):
    template_name = 'polls/index.html'
    context_object_name = 'latest_question_list'

    def get_queryset(self):
        """
        Return the last five published questions (not including those set to be
        published in the future).
        """
        return Question.objects.filter(
            pub_date__lte=timezone.now()
        ).order_by('-pub_date')[:5]
.
.

新しいビューをテストする

pools/tests.py にビューのテストを作成していきます。
まず、reverse を使うための import文を書きます。

from django.urls import reverse

次に、question を生成しやすいように create_question() 関数を定義します。

def create_question(question_text, days):
    """
    Create a question with the given `question_text` and published the
    given number of `days` offset to now (negative for questions published
    in the past, positive for questions that have yet to be published).
    """
    time = timezone.now() + datetime.timedelta(days=days)
    return Question.objects.create(question_text=question_text, pub_date=time)


question_text を質問項目とし、今日から days 後に公開する Question オブジェクトを生成する関数です。

このショートカット関数を使って、Question を作成してテストを行う事ができます。
テストケース QuestionIndexViewTests に下記メソッドを定義していきます。
まず、Question が存在しない場合のテストです。

def test_no_questions(self):
    """
    If no questions exist, an appropriate message is displayed.
    """
    response = self.client.get(reverse('polls:index'))
    self.assertEqual(response.status_code, 200)
    self.assertContains(response, "No polls are available.")
    self.assertQuerysetEqual(response.context['latest_question_list'], [])
assertContains

SimpleTestCase.assertContains(response, text, count=None, status_code=200, msg_prefix='', html=False)

Responseインスタンスが指定されたstatus_codeを生成し、text がレスポンスのコンテンツに含まれることを示す。

assertQuerysetEqual

TransactionTestCase.assertQuerysetEqual(qs, values, transform=repr, ordered=True, msg=None)

クエリセット qs が values のリストを返す事を示す。

次に過去 Question のテストです。

def test_past_question(self):
    """
    Questions with a pub_date in the past are displayed on the
    index page.
    """
    create_question(question_text="Past question.", days=-30)
    response = self.client.get(reverse('polls:index'))
    self.assertQuerysetEqual(
        response.context['latest_question_list'],
        ['<Question: Past question.>']
    )

未来の Question のテストも同様です。

def test_future_question(self):
    """
    Questions with a pub_date in the future aren't displayed on
    the index page.
    """
    create_question(question_text="Future question.", days=30)
    response = self.client.get(reverse('polls:index'))
    self.assertContains(response, "No polls are available.")
    self.assertQuerysetEqual(response.context['latest_question_list'], [])

未来の質問と過去の質問が共存する場合もテストします。

def test_future_question_and_past_question(self):
    """
    Even if both past and future questions exist, only past questions
    are displayed.
    """
    create_question(question_text="Past question.", days=-30)
    create_question(question_text="Future question.", days=30)
    response = self.client.get(reverse('polls:index'))
    self.assertQuerysetEqual(
        response.context['latest_question_list'],
        ['<Question: Past question.>']
    )

過去の質問だけが2つある場合をテストします。

def test_two_past_questions(self):
    """
    The questions index page may display multiple questions.
    """
    create_question(question_text="Past question 1.", days=-30)
    create_question(question_text="Past question 2.", days=-5)
    response = self.client.get(reverse('polls:index'))
    self.assertQuerysetEqual(
        response.context['latest_question_list'],
        ['<Question: Past question 2.>', '<Question: Past question 1.>']
    )

 

DetailView のテスト

DetailView も未来日付を表示しないようにします。DetailView にも get_queryset() メソッドを定義してクエリセットを制限します。

class DetailView(generic.DetailView):
    model = Question
    template_name = 'polls/detail.html'

    def get_queryset(self):
        """
        Excludes any questions that aren't published yet.
        """
        return Question.objects.filter(pub_date__lte=timezone.now())

DetailView のテストを追加します。

class QuestionDetailViewTests(TestCase):
    def test_future_question(self):
        """
        The detail view of a question with a pub_date in the future
        returns a 404 not found.
        """
        future_question = create_question(question_text='Future question.', days=5)
        url = reverse('polls:detail', args=(future_question.id,))
        response = self.client.get(url)
        self.assertEqual(response.status_code, 404)

    def test_past_question(self):
        """
        The detail view of a question with a pub_date in the past
        displays the question's text.
        """
        past_question = create_question(question_text='Past Question.', days=-5)
        url = reverse('polls:detail', args=(past_question.id,))
        response = self.client.get(url)
        self.assertContains(response, past_question.question_text)

 

参考

低価格なのに高速・多機能・高セキュリティ 月額400円(税別)から最大容量100GB WordPress専用高速サーバー Z.com WP
おすすめの記事