初めてDjangoを触ってみていいなと思ったこと

# はじめに

Pythonの経験がほぼゼロの状態から、
なにかと評判の高い[Django](https://www.djangoproject.com/)というWebアプリケーション開発のフレームワークを触ってみました。

これまでに、Ruby on Rails, Nest.js, ASP.Net Core, Laravelあたりを触ったことがあるため、それらとなんとなく比較しながら、個人的にいいなと思った部分のみまとめます。

## 触ったもの

[公式チュートリアル](https://docs.djangoproject.com/en/3.1/intro/tutorial01/) を一通りやってみました。

### チュートリアルの内容

1. Part 1: Requests and responses
2. Part 2: Models and the admin site
3. Part 3: Views and templates
4. Part 4: Forms and generic views
5. Part 5: Testing
6. Part 6: Static files
7. Part 7: Customizing the admin site
8. Advanced Tutorials: How to write reusable apps
9. Advanced Tutorials: Writing your first patch for Django


### チュートリアルを終えたソースコード

https://github.com/yuichkun/django-tutorial

## いいなと思ったこと

### CLIのコマンドが豊富

Djangoが有効になっているPython仮装環境下において、

```sh
python manage.py {コマンド名}
```
で様々なコマンドを実行することができます。

有効なコマンドの例としては、

- `runserver` : サーバーの起動
- `test`: テストの実行
- `check` : ソースコードに問題がないかどうかチェック
- `shell`: `rails console` のような感じで、REPL環境でdjangoのモデルなどをいじれる
- `makemigration` / `migrate` : マイグレーション関連
- `sqlmigrate` : マイグレーションが実行する予定のSQLをプリントして確認できる
- `createsuperuser` : シェル上でインタラクティブにユーザー名・パスワードなどを入力するでユーザーが作れる。初期ユーザーの生成などに便利そう
![createsuperuser](https://i.gyazo.com/d3f8e321189f87e2f96f6192d6d4fd50.gif)

### 外部キーでリレーションを表現
```python:polls/models
from django.db import models


class Question(models.Model):
    question_text = models.CharField(max_length=200)
    pub_date = models.DateTimeField('date published')


class Choice(models.Model):
    question = models.ForeignKey(Question, on_delete=models.CASCADE)
    choice_text = models.CharField(max_length=200)
    votes = models.IntegerField(default=0)
```

この例だと、Choiceモデルに外部キーとして `question` を設定することでそれに基づいてリレーションが作られます。
外部キー制約の貼り忘れがなくていいなと思いました。

### 管理画面

これが個人的に1番いいなと思いました。

はじめは、「ブログサービスを作るわけでもないのに管理画面なんていらんやろ」ぐらいに思っていましたが、

![Screen Shot 2021-03-10 at 7.57.59.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/148589/3a9025fb-fbd2-38fd-8a3f-b0abde01d814.png)

上図のように、UI上で様々なモデルインスタンスの新規作成・編集などを簡単に行うことができます。
この例のように、Question has many Choices のようなリレーション関係の時に、
`Question` の生成画面で紐づく `Choice`インスタンスの生成も同時に生成できるようなUIのカスタマイズが非常に簡単で、素晴らしかったです。

### テストが楽

たとえば、モデルのテストであれば、

```python:model_tests.py
import datetime

from django.test import TestCase
from django.utils import timezone

from .models import Question


class QuestionModelTests(TestCase):

    def test_was_published_recently_with_future_question(self):
        """
        was_published_recently() returns False for questions whose pub_date
        is in the future.
        """
        time = timezone.now() + datetime.timedelta(days=30)
        future_question = Question(pub_date=time) # テスト用のモデルインスタンスの生成
        self.assertIs(future_question.was_published_recently(), False) # インスタンスのプロパティにアクセスしてアサーション
```

Viewのテストであれば

```python:view_tests.py
# テスト用のヘルパー関数
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)


class QuestionIndexViewTests(TestCase):
    def test_no_questions(self):
        """
        If no questions exist, an appropriate message is displayed.
        """
        response = self.client.get(reverse('polls:index')) # `/polls` にリクエストを投げる
        self.assertEqual(response.status_code, 200) # ステータスコードのチェック
        self.assertContains(response, "No polls are available.") # レンダーされたレスポンステキストのチェック
        self.assertQuerysetEqual(response.context['latest_question_list'], []) # コントローラーがテンプレートに渡している変数の中身のチェック
```

いずれにおいてもテストの実行時には、

1. テスト用のDBを生成
2. 各テストの実行前にDBを綺麗な状態に戻す
3. 各テストを実行する

ということを自動でやってくれます。

db cleaner的なものを自前で実装しなければならないフレームワークも結構多いので、これはかなり好印象でした。


## まとめ

「ん？これはどうなんだろう？」という部分がなかったわけでもないので、
それもまとめようかと検討したのですが、とはいえ実務でまだ使ったことがないので無知を晒しかねず、この記事ではポジティブな部分のみに留めました。

チュートリアルの所要時間は2時間程度?なので興味の湧いた方はぜひやってみましょう！