執筆:清原弘貴 (id:hirokiky)、編集:kenken
Django2.2で追加される機能、変更点についてご存知ですか?
今回はDjango最新バージョンの、Django2.2について紹介します。
なお、すべての機能や変更を細かく紹介すると長くなるので、この記事では、Django2.2で追加される機能のメインとなるConstraintsに焦点をあてて説明します。このほかにも、いくつか気になる機能をピックアップして紹介します。
リリースの概要
- 名称:Django
- リリースバージョン:Django 2.2
- 開始日:April 1, 2019
- ドキュメントURL:https://docs.djangoproject.com/en/2.2/releases/2.2/
Django2.2に限らない話ですが、アップデートの際はBackwords Incompatible Changes(後方互換製のない変更)に十分注意してください。
Constraints: モデルの値をデータベースで制限する機能
モデルの各フィールドの値に、データベースレベルでの制限を付けられる機能が追加されました。
以下のようにMetaオプションを追加することで制限をかけられます。
この例では下記の例に出てくるage
フィールドに「18以上の値でなければならない」という制限を付けています。
from django.db import models class Customer(models.Model): age = models.IntegerField() class Meta: constraints = [ models.CheckConstraint(check=models.Q(age__gte=18), name='age_gte_18'), ]
Constraintsの設定方法は?
モデルのMetaオプションにconstraints
をリストで設定します。
リストには models.CheckConstraint
を使って制限を指定します。check=
引数にQ
オブジェクトを渡すことで、制限の条件を指定できます。
UniqueConstraintsも使えます
models.UniqueConstraints
は一意制約(データの重複を防ぐための制約)をつけるために使います。
複数のフィールドを組み合わせた一意制約としたり、ある条件の場合と組み合わせた一意制約を付与できます。 Constraints reference | Django documentation | Django
以下の例では、「下書き(DRAFT)」状態のArticleは1ユーザーに付き1つしか作れないように制限しています。
class Article(...): user = models.ForeignKey(...) status = models.CharField(...) class Meta: constraints = [ UniqueConstraint(fields=['user'], condition=Q(status='DRAFT'), name='unique_draft_user'), ]
条件(condition=
オプション) を使わず複数フィールドでの一意制約をつけるのは、現状の unique_together
Metaオプションと同じ機能になります。将来的にこのunique_together
オプションは廃止される予定です。
Model Meta options | Django documentation | Django
ConstraintsはValidatorsとは違うもの?
ConstraintsはValidatorsと別物です。
Djangoのバリデーターは値の保存前にアプリケーション側で値をチェックするものです。けれどもConstraintsはデーターベース上で制限するものです。 Constraintsに反する値を保存しようとすると、IntegrityErrorが発生します。
Constraintsを設定してもモデルフォーム
などには反映されないので、バリデーター(validators
引数など)は引き続き設定する必要があります。
ただし、UniqueConstraint
をcondition
オプションなしで使う場合はバリデーションのチェックも行ってくれます。
Constraintsはどんな悩みを解決するもの?
不正な値がデーターベース上へ入らないようにしてくれます。 不正な値が入ってしまうと、アプリケーション上で想定しないバグを誘発したり、脆弱性につながるおそれがあります。
今まではバリデーターで入力を制限していましたが、こんな悩みがありました。
- バリデーターにはちゃんと設定しているけど、設定を忘れると怖い。値の安全のためにデーターベースレベルで制限したい
- 連携しているシステムが直接データーベースにアクセスして、良くない値を保存しないか心配
Constraintsを設定するとデーターベースレベルで入力を制限してくれるのでより安心です。
私個人的にはモデル設計とデータの制限は厳しくしたほうが良いと考えているので、この新機能はかなり嬉しいです。
Django 2.2はLTS
Django2.2はLongTermSupport(長期間サポート、LTSとも呼ばれる)になるリリースです。
予定ではDjango2系で唯一のLTSになりますので、Django2.2にアップグレードできればひとまずは安心できると思います(2022年4月までサポートされます)。
https://www.djangoproject.com/download/
小さめの変更
小さめの変更もいくつかピックアップしてご紹介します。 すべての変更を網羅しているわけではありませんので、ご注意ください。
migrate --plan
オプションの追加- マイグレートで実行される予定のマイグレーションファイル一覧が分かります
- 実行前にどのようなマイグレーションが実行されるか、どんなSQLが発行されるかを確認する際に便利です
request.headers
の追加- リクエストのヘッダーを簡単に取得できるようになりました
request.META
と違い、HTTP_
をつける必要がなくなり、大文字・小文字どちらでも取得できるようになりました(便利ですね!)
sqlparse
への依存が追加- Djangoの依存パッケージに
sqlparse
が追加されました pytz
に続いて2つ目の依存パッケージになります- 今までDjangoは依存パッケージがないことに強いこだわりがありました。最近は必須なパッケージであれば依存することもあるようですね(DjangoがPython3対応時に
utils
以下でsix
をまるごと持っていたのが懐かしいです)
- Djangoの依存パッケージに
- テスト時のClientが、
content_type="application/json"
を指定すると、data=
に渡した値を自動でJSONへ変換するようになりました(これも便利です!) - データベースキャッシュバックエンドを使う際に、
cache.set(…)
やcache.get(…)
のキーへ文字列以外を渡すとエラーになってしまいましたcache
のキーは今までも文字列の指定が必須でした。けれども、どのバックエンドでも数値などをキーにしていても動作していました- Django 2.2よりDatabaseBackendを使っているときはエラーになりますのでご注意ください
まとめ
Django 2.2はDjango2系で唯一のLTSなので、そこまで実験的な新機能はありません。
ですがConstraintsは良い機能ですし、細かい改善も多くされています。
今後もDjangoの進化に期待したいところです。
もしDjangoに新機能を提案したい場合や、バグの修正をしたい場合は以下のチュートリアルを参考にしてください。