2025年4月2日、Django 5.2がリリースされました。

Django 5.2リリースおめでとう!
公式サイトでのリリース情報は以下を参照してください。
Django 5.2 release notes | Django documentation | Django
Django 5.2はlong-term support(LTS)版です。サポート期限は2028年4月です。 各バージョンのサポート期限についての詳細は以下公式ドキュメント「Supported Versions」を参照してください。
それでは、以下で主な新機能について解説します。
Automatic models import in the shell
shellコマンド起動時にモデル定義が自動インポートされるようになりました。 Django拡張として人気があるdjango-extentionsの shell_plusコマンドの機能が公式に取り込まれたようなイメージです。
実際にshellコマンドを使っている様子は以下の動画を確認してください。
shellコマンドに--verbosity=2
オプションを付けると、どんなモデルがインポートされるか確認できます。
% ./manage.py shell --verbosity=2
8 objects imported automatically:
from example.models import Release
from books.models import Book
from django.contrib.sessions.models import Session
from django.contrib.contenttypes.models import ContentType
from django.contrib.auth.models import User, Group, Permission
from django.contrib.admin.models import LogEntry
Python 3.13.2 (main, Feb 4 2025, 14:51:09) [Clang 16.0.0 (clang-1600.0.26.6)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
(InteractiveConsole)
>>>
ちなみに、複数アプリケーションで同じ名前のモデルが存在している場合は、INSTALLED_APPS
の上の方に書かれたアプリケーションに属するモデルが優先的にインポートされるようです。
Composite Primary Keys
モデルの複合主キーがサポートされるようになりました。
複合主キーを定義するには、以下のように、pk
属性にdjango.db.models.CompositePrimaryKeyクラスを設定します。
from django.db import models
class Release(models.Model):
pk = models.CompositePrimaryKey("version", "name")
version = models.IntegerField()
name = models.CharField(max_length=20)
上記のモデルを定義した際に作られるテーブル定義をsqlmigrateコマンドで確認した結果は以下のとおりです。
BEGIN;
--
-- Create model Release
--
CREATE TABLE "example_release" ("version" integer NOT NULL, "name" varchar(20) NOT NULL, PRIMARY KEY ("version", "name"));
COMMIT;
PRIMARY KEY ("version", "name")
が出力されていることから、複合主キーが定義されていることがわかります。
Simplified override of BoundField
フォームクラスにカスタムフィールドを定義する方法が簡略化されました。 従来はField.get_bound_field()メソッドをオーバーライドする必要がありましたが1、5.2からは以下の方法がサポートされます。
BaseRenderer.bound_field_class(プロジェクトレベルで適用)
BaseRenderer.bound_field_classを使うと、プロジェクトレベルでカスタムフィールドを定義できます。
以下の書き方は、プロジェクト全体でフォームのフィールドを<p class="custom">...</p>
で囲います。
"""django52_example/settings.py"""
from django.forms.renderers import DjangoTemplates # DjangoTemplatesはBaseRendererのサブクラス
from django import forms
class CustomBoundField(forms.BoundField):
custom_class = "custom"
def css_classes(self, extra_classes=None):
result = super().css_classes(extra_classes)
if self.custom_class not in result:
result += f" {self.custom_class}"
return result.strip()
class CustomDjangoTemplate(DjangoTemplates):
bound_field_class = CustomBoundField
FORM_RENDERER = "django52_example.settings.CustomDjangoTemplate"
Form.bound_field_class(フォームレベルで適用)
Form.bound_field_classを使うと、 フォームレベルでカスタムフィールドを定義できます。
以下の書き方は、CustomForm
クラスに定義したフィールド全てを<p class="custom">...</p>
で囲います。
"""example/forms.py"""
from django import forms
class CustomBoundField(forms.BoundField):
custom_class = "custom"
def css_classes(self, extra_classes=None):
result = super().css_classes(extra_classes)
if self.custom_class not in result:
result += f" {self.custom_class}"
return result.strip()
class CustomForm(forms.Form):
bound_field_class = CustomBoundField
name = forms.CharField(
label="Your Name",
max_length=100,
required=False,
widget=forms.TextInput(attrs={"class": "name-input-class"}),
)
email = forms.EmailField(label="Your Email")
Field.bound_field_class(フィールドレベルで適用)
Field.bound_field_classを使うと、フィールドレベルでカスタムフィールドを定義できます。
以下の書き方は、CustomForm
クラスに定義したemail
フィールドのみを<p class="custom">...</p>
で囲います。
"""django52_example/settings.py"""
from django import forms
class CustomBoundField(forms.BoundField):
custom_class = "custom"
def css_classes(self, extra_classes=None):
result = super().css_classes(extra_classes)
if self.custom_class not in result:
result += f" {self.custom_class}"
return result.strip()
class CustomForm(forms.Form):
name = forms.CharField(
label="Your Name",
max_length=100,
required=False,
widget=forms.TextInput(attrs={"class": "name-input-class"}),
)
email = forms.EmailField(label="Your Email", bound_field_class=CustomBoundField)
Field.get_bound_field()
メソッドの使用例: https://docs.djangoproject.com/ja/5.1/ref/forms/api/#django.forms.Field.get_bound_field ↩︎