初めて触ったDjangoで役立った機能

# はじめに
42Tokyoの学生です。
42の課題でDjangoを触る機会があったので、個人的に役に立った機能をまとめてみました。
本記事はあくまでも紹介レベルなので、詳細を知りたい方は別の記事や公式ドキュメントを参照してください。


## ミドルウエア
**ミドルウエア**という言葉で調べると、たいていOSとアプリケーションの中間のソフトという意味で出てきますが、Djangoにおいては**クライアント側の送信したデータ**に対して、受信時および送信時に実行できる処理を表します。

つまり、Viewで行う**処理の前後**に、リクエストデータ・レスポンスデータに対して何らかの処理をすることができます。

今回の課題ではデフォルトの状態から以下のものを追加しました。

### [LoginRequiredMiddleware](https://docs.djangoproject.com/ja/5.1/ref/middleware/#django.contrib.auth.middleware.LoginRequiredMiddleware)
Djangoで管理するすべてのページに対して、**ログインしていなければアクセスできない**ようにします。これを利用しなければ、次のように@login_requiredでデコレートしなければなりません。
```python
@login_required
def view_test(request):
    pass

#class viewの時は下記のようにする
@method_decorator(login_required, name="dispatch")
class ViewTest(TemplateView):
    pass
```

すべてのviewに対して書かなければならないので面倒ですし書き忘れも発生します。
しかし、LoginRequiredMiddlewareを使えば上記のようなに@login_requiredを書く必要がなく、デフォルトでユーザーがログインしていない限りアクセスできなくなります。

注意点として、login画面もlogin指定な限りアクセスできなくなるので、そういう場合は次のように@login_not_requiredでデコレートします
```python
@login_not_required
def login_test(request):
    pass

#class viewの時は下記のようにする
@method_decorator(login_not_required, name="dispatch")
class LoginTest(TemplateView):
    pass
```


### [LocaleMiddleware](https://docs.djangoproject.com/ja/5.1/ref/middleware/#module-django.middleware.locale)
多言語機能のために利用しています。
言語の切り替えを簡単に実装できます。


### 
## ミドルウエアのカスタマイズ
あまり推奨されるやり方ではないのかもしれませんが、既存のミドルウエアをカスタマイズして差し替えることもできます。差し替えは、settings.pyを変更することで実施できます。

### [SessionMiddleware](https://docs.djangoproject.com/ja/5.1/ref/middleware/#module-django.contrib.sessions.middleware)のカスタマイズ
```settings.py
#既存のものをコメントアウトし、カスタマイズしたものに差し替える
MIDDLEWARE = [
# "django.contrib.sessions.middleware.SessionMiddleware"
  "accounts.middleware.CustomSessionMiddleware"
]
```
こちらを実施した理由はJWTをセッションIDに差し替えるためです。
詳細はこちらを参照してください。
https://qiita.com/hsano43/items/509544025882f852aa62

### UserActionLoggingMiddleware
こちらは新規に作成したミドルウエアです。
詳細は語りませんが、ユーザーからのリクエストデータをすべて保持するための作成しました。

# [テンプレート](https://docs.djangoproject.com/ja/5.1/ref/templates/)
ざっくりいうとサーバー側でHTMLを作成する機能です。
ただHTMLを書くだけでなく、View側の処理を反映させることができます。

例えば次のようなHTMLコードがあるとします。
```html
<div>{{tournament.name}}</div>
<div>{{tournament.organizer}}</div>
```

View側の実装は次のようにします。
```python
    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context["tournament"] = {
            "name": _("テストトーナメント"),
            "organizer": _("主催者1"),
        }
        return context
```
すると、クライアント側では次のようなHTMLデータを受け取ることができます
```html
<div>テストトーナメント</div>
<div>主催者1</div>
```

ほかにも、includeを利用して関数のようにhtmlを使いまわすこともできます。
(card.htmlはここでは省略していますがBootstrapのCardを利用しています）
```html
          {% for tournament in tournaments %}
          {% include 'tournament/card.html' with tournament=tournament attr=attr %} 
          {% endfor %}
```
実際にページを開くと次のようになります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/338221/f33be8de-aa81-16c8-ce09-c82dd7d798ab.png)

ここでやっていることは、tournamentsは**View側で定義したList**で、その**個数分**だけcard.htmlを作成していることになります。もちろん、リストの内部データはすべて異なるので、異なるカードが表示されることになります。


ほかにもif~elseで処理を分岐したり、多言語に対応させたりできます。

## [認証機能](https://docs.djangoproject.com/ja/5.1/topics/auth/customizing/)
デフォルトのままだと課題要件がクリアできなかったのでいろいろと変更しました。
ドキュメントにも書いてありますが、デフォルトでも十分に使えます。
カスタマイズの詳細は、以前に書きました。
https://qiita.com/hsano43/items/afc6dfcfae06ca8f112c

## Django以外の機能
Djangoの機能ではないですが、RedisとCeleryは大変役に立ちました。

### Redis
有効期限を設定すれば自動で消去してくれるので一時的なデータ保持に有効でした。
redisがなければ定期的に削除するか、あるいは一時データの保存サイズが大きくなったら自動で削除するなど、面倒な処理をしなければなりませんでした。


### Celery
非同期タスクを簡単に扱うことができるようになりました。
なぜ必要なのかというと、クライアントからリクエストが来た際、サーバーは当然レスポンスを返します。この時、ある処理を5分後に実行したいとすると、同期処理の場合は5分待たなければレスポンスを返すことができません。これを防ぐために、5分待つ処理を非同期にする必要があります。

Celeryはその非同期処理を実施してくれるライブラリになります。
また、cronのように定期実行もすることができるので、こちらも役に立ちました。

# まとめ
以上がDjangoどころかWeb開発も初めての自分が、42の課題に対して活用したDjangoの機能になります。

ミドルウエアは最初何のためのものかよくわかりませんでしたが、レスポンスデータをViewで処理する前後に様々な処理を加えることができて便利でしたし、テンプレートも同様に最初はただのHTMLを書いていただけでしたが、一度利点に気づくと活用方法がいくつも出てきて役に立ちました。

自分が知らない役立つ機能はおそらくまだまだあると思うので、また機会があれば探してみたいと思います