2017年4月4日、Django 1.11 LTSがリリースされました!
今回のバージョンはLTS(Long Term Support=長期サポート)なので、非LTSバージョンよりサポート期間が長めになっています。サポート期間についての詳細は以下URL「Supported Versions」を確認してください。
https://www.djangoproject.com/download/
それでは、release notesに載っている主な変更点について解説します。
Python2サポートは1.11で最後
1.11はPython2をサポートする最後のバージョンです。次の2.0からはPython3のみサポートになります。
1.11のサポート期限は2020年4月までなので、それまでにはPython3への移行を終える必要があります。1
Deprecating warningsがデフォルトで無効に
Deprecating warningsがデフォルトで無効になりました。Python自体のデフォルトの挙動に合わせたとのことです。
これによって、1.11と1.8両方をサポートするサードパーティアプリケーションを開発する際、警告メッセージを回避するコードを書く必要がなくなりました。
今公開しているサードパーティアプリケーションのサポート対象に次回リリースされる2.0を含める場合、以下がDjango推奨の移行手順です。
- バージョン1.11より前のバージョンのサポートを切る。
- テストは
python -Wd
で実行するようにして、Deprecating warningsが出るようにする。 - Deprecating warningsが出ていたら、出ないように修正する。
主な新機能
What’s new in Django 1.11の最初の3機能+その他の個人的に気になる機能について解説します。(それ以外の細かいのは数が多いので省略)
Class-based model indexes
モデルのインデックス指定は今までField.db_index、またはMeta.index_togetherを使っていましたが、1.11からはMeta.indexesにインデックスを表すクラスで指定できるようになりました。
以下が使用例です。
from django.db import models
class Book(models.Model):
title = models.CharField(max_length=100)
author = models.CharField(max_length=100)
price = models.IntegerField()
class Meta:
indexes = [
models.Index(fields=['title', 'author']),
models.Index(fields=['price'], name='price_idx'), # インデックスに名前を付けられる
]
これによって、B-tree以外のインデックスを指定することが可能になりました。例えば、GinIndexクラスを使うことで、PostgreSQL
の独自機能であるGinインデックスを指定することができます。
Template-based widget rendering
オリジナルのWidgetクラスを作成する際、HTML部分をテンプレートに分けることができるようになりました。
どれだけ便利になったか確認するため、1.8のWidgetクラスはどう書いていたか見てみましょう。
from django import forms
from django.forms.utils import flatatt
from django.utils.encoding import force_text
from django.utils.html import format_html
class RangeWidget(forms.Widget):
def render(self, name, value, attrs=None):
final_attrs = self.build_attrs(attrs, name=name)
if value is None:
value = ''
if value != '':
final_attrs['value'] = force_text(value)
return format_html('<input type="range"{}>',
flatatt(final_attrs))
今まではHTML部分もrender
メソッドの中に書く必要があり、ちょっと読みにくいです。もっと複雑な仕様になるとスパゲッティコードになる可能性もあります。
次に、1.11での書き方を見てみましょう。
from django import forms
class RangeWidget(forms.Widget):
template_name = 'forms/widgets/range.html'
<input type="range" name="{{ widget.name }}"{% include "django/forms/widgets/attrs.html" %}{% if widget.value %} value="{{ widget.value }}"{% endif %}>
HTML部分が別ファイルに分かれたので、コードの見通しがかなり良くなりました。テンプレートの書き方はDjangoのソースコードのforms/templates/django/forms/widgets/
以下にあるhtmlファイルを見れば参考になります。
Subquery expressions
モデル操作時にサブクエリを使うことができるようになりました。
stackoverflowで「django subquery」 で検索すると結構前から需要がある機能のようですが、ようやく実装されました。
Pythonコードの何がどういうクエリになるか検証するために、ドキュメントのサンプルと同じモデルを作って、以下のような図を作ってみました。
検証にはdjango-debug-toolbarのdebugsqlshellコマンドを使っています。データベースは公式ドキュメントと違ってSQLiteを使っていますが、投げられるクエリはだいたい同じです。
Subqueryの使用例
公式ドキュメント: https://docs.djangoproject.com/en/1.11/ref/models/expressions/#subquery-expressions
Pythonコード:
クエリ:
Existsの使用例
公式ドキュメント: https://docs.djangoproject.com/en/1.11/ref/models/expressions/#exists-subqueries
Pythonコード:
クエリ:
その他
個人的に気になる新機能
「The Jinja2 template backend now supports context processors by setting the 'context_processors' option in OPTIONS.」(テンプレートバックエンドがJinja2でもcontext_processorsが使えるようになった)が気になっています。以前、1.8で検証した時には使えなかったのですが、これで気軽にJinja2を採用できそうです。
-
もっとも、Python2.7のサポート期限は2020年までなので、Djangoでのサポートとは関係なく、そろそろPython3移行を検討するべきです。 ↩