LoginSignup
21
15

More than 5 years have passed since last update.

Django 1.11 LTS 主な変更点まとめ

Posted at

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. バージョン1.11より前のバージョンのサポートを切る。
  2. テストはpython -Wdで実行するようにして、Deprecating warningsが出るようにする。
  3. Deprecating warningsが出ていたら、出ないように修正する。

主な新機能

What’s new in Django 1.11の最初の3機能+その他の個人的に気になる機能について解説します。(それ以外の細かいのは数が多いので省略)

Class-based model indexes

モデルのインデックス指定は今までField.db_index、またはMeta.index_togetherを使っていましたが、1.11からはMeta.indexesにインデックスを表すクラスで指定できるようになりました。
以下が使用例です。

models.py
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クラスはどう書いていたか見てみましょう。

widgets_1_8.py
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での書き方を見てみましょう。

widgets.py
from django import forms


class RangeWidget(forms.Widget):
    template_name = 'forms/widgets/range.html'
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-toolbardebugsqlshellコマンドを使っています。データベースは公式ドキュメントと違ってSQLiteを使っていますが、投げられるクエリはだいたい同じです。

Subqueryの使用例

公式ドキュメント: https://docs.djangoproject.com/en/1.11/ref/models/expressions/#subquery-expressions
Pythonコード:
Subquery-python.jpg
クエリ:
Subquery-sql.jpg

Existsの使用例

公式ドキュメント: https://docs.djangoproject.com/en/1.11/ref/models/expressions/#exists-subqueries
Pythonコード:
Exists-python.jpg
クエリ:
Exists-sql.jpg

その他

個人的に気になる新機能

The Jinja2 template backend now supports context processors by setting the 'context_processors' option in OPTIONS.」(テンプレートバックエンドがJinja2でもcontext_processorsが使えるようになった)が気になっています。以前、1.8で検証した時には使えなかったのですが、これで気軽にJinja2を採用できそうです。


  1. もっとも、Python2.7のサポート期限は2020年までなので、Djangoでのサポートとは関係なく、そろそろPython3移行を検討するべきです。 

21
15
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
21
15