JavaおじさんがPythonを使えるようになるまでの全記録（その15）

#Djangoのチュートリアル終了
一応[基本的なところ](https://docs.djangoproject.com/ja/2.1/intro/tutorial07/)までは終了した、と思う。

で、やっぱりこのチュートリアルで一番気になるのは「いやいや、viewもmodelもファイルが一枚岩じゃん、これじゃ分散開発に向いてなくね？」というところ。
さすがにviewとmodelとtestくらいは分割するべきじゃないの？ということで分割してみた。
なお、基本的な情報は[ここ](https://qiita.com/RyoMa_0923/items/c4ca5bd070e823403fdf)を参照しました。感謝。

たとえばtestsの分割後の状態はこんな感じ。

![2018-08-15 (2).png](https://qiita-image-store.s3.amazonaws.com/0/275064/8be2603c-25c8-3702-3b57-d18806ad7824.png)

testsの下にサブディレクトリとしてmodelとviewが切ってあってそこを参照するための``__init__.py``の中身がこんな感じになっている。

```tests/__init__.py
from polls.tests.model import *
from polls.tests.view import *
```

それぞれのディレクトリの``__init__.py``で各テストクラスを記述したファイルの参照を記述する。

```model/__init__.py
from polls.tests.model.questionTest import *
```

```view/__init__.py
from polls.tests.view.indexTest import *
from polls.tests.view.detailTest import *
from polls.tests.view.createModels import *
```

モジュール名とクラス名はわざと別にしてあったりする。

```view/indexTest.py
from django.test import TestCase
from django.urls import reverse

from polls.models import Question
from .createModels import create_question

class QuestionIndexViewTests(TestCase):
    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'], [])

    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.>']
        )

    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.>']
        )

    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.>']
        )
```

共通関数としてテスト用のModelであるQuestionのインスタンスを作るコードを分離して別ファイルへ。

```view/createModels.py
import datetime

from django.utils import timezone

from polls.models import 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)
```

実際``from ... import ...``の書き方に慣れてなくててこずったりしました。
もうだいたいわかった（気がする）けど。
要するにこういうことよね。

`` from {アプリケーション名|ライブラリ名}.{ディレクトリ名（.サブディレクトリ名）}.{モジュール名(=ファイル名)} import {クラス名|関数名}``

あと、``import *``の書き方は本当は邪道なんだろうけど、``__init__.py``の中でだけは許してほしいところ。ていうか``__init__.py``くらい自動生成してほしいんだけどPyCharmだったらできたりすんのかな。
え？自分で書け？ｗ

コードは[GitHub](https://github.com/KojiNagahara/DjangoApp)に置いてあったりします。あんまり面白みないけどね。

さて、こっからは排他制御とトランザクションの仕組みを見ないとね。
というわけでこの記事はここまで。