Python学習チャンネル by PyQ

Pythonのオンライン学習プラットフォームPyQのオフィシャルブログです

Django最新バージョンの、Django2.2について紹介します

f:id:kenken0326:20190814102739p:plain

執筆:清原弘貴 (id:hirokiky)、編集:kenken


Django2.2で追加される機能、変更点についてご存知ですか?
今回はDjango最新バージョンの、Django2.2について紹介します。

なお、すべての機能や変更を細かく紹介すると長くなるので、この記事では、Django2.2で追加される機能のメインとなるConstraintsに焦点をあてて説明します。このほかにも、いくつか気になる機能をピックアップして紹介します。

リリースの概要

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引数など)は引き続き設定する必要があります。

ただし、UniqueConstraintconditionオプションなしで使う場合はバリデーションのチェックも行ってくれます。

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をまるごと持っていたのが懐かしいです)
  • テスト時のClientが、 content_type="application/json"を指定すると、data=に渡した値を自動でJSONへ変換するようになりました(これも便利です!)
  • データベースキャッシュバックエンドを使う際に、 cache.set(…)cache.get(…)のキーへ文字列以外を渡すとエラーになってしまいました
    • cacheのキーは今までも文字列の指定が必須でした。けれども、どのバックエンドでも数値などをキーにしていても動作していました
    • Django 2.2よりDatabaseBackendを使っているときはエラーになりますのでご注意ください

blog.hirokiky.org

まとめ

Django 2.2はDjango2系で唯一のLTSなので、そこまで実験的な新機能はありません。
ですがConstraintsは良い機能ですし、細かい改善も多くされています。

今後もDjangoの進化に期待したいところです。
もしDjangoに新機能を提案したい場合や、バグの修正をしたい場合は以下のチュートリアルを参考にしてください。

docs.djangoproject.com

Copyright ©2017-2018 BeProud Inc. All rights reserved.