【保存の手間を激減】Django adminでモデルフィールドを自動生成: prepopulated_fields超解説


admin.ModelAdmin.prepopulated_fields は、Django 管理画面において、あるモデルフィールドの値を別のモデルフィールドの値に基づいて自動的に生成・設定するための機能です。

利点

  • ユーザーインターフェースの改善
  • データの一貫性の向上
  • データ入力の効率化

使い方

admin.ModelAdmin クラスの prepopulated_fields 属性に、生成対象フィールドと参照元フィールドをタプル形式で指定します。

from django.contrib import admin

class MyModelAdmin(admin.ModelAdmin):
    prepopulated_fields = {
        'slug': ('title',)
    }

上記の例では、slug フィールドの値を title フィールドの値に基づいて自動的に生成します。

詳細

  • 生成アルゴリズムをカスタマイズすることもできます。
  • 生成アルゴリズムは、Django の標準ライブラリである django.contrib.admin.utils モジュールに定義されています。
  • 参照元フィールドは、複数指定することもできます。
  • 生成対象フィールドは、文字列型、日付型、時間型など、様々な型に対応できます。

以下の例は、title フィールドの値を小文字にして、ハイフンで区切った文字列を slug フィールドに自動的に生成するものです。

from django.contrib import admin
from django.template.defaultfilters import slugify

class MyModelAdmin(admin.ModelAdmin):
    prepopulated_fields = {
        'slug': (lambda obj: slugify(obj.title),)
    }

注意点

  • データの整合性を保つには、適切なデータ検証を行う必要があります。
  • prepopulated_fields は、あくまで補助的な機能です。
  • prepopulated_fields を使用する場合は、パフォーマンスへの影響を考慮する必要があります。
  • prepopulated_fields は、Django の標準機能以外にも、様々なライブラリで拡張されています。

admin.ModelAdmin.prepopulated_fields は、Django 管理画面において、データ入力の効率化、データの一貫性の向上、ユーザーインターフェースの改善に役立つ機能です。



モデル定義

from django.db import models

class Author(models.Model):
    name = models.CharField(max_length=255)
    email = models.EmailField()

class Book(models.Model):
    title = models.CharField(max_length=255)
    slug = models.SlugField(max_length=255, unique=True)
    author = models.ForeignKey(Author, on_delete=models.CASCADE)
    pub_date = models.DateField()
    description = models.TextField()
from django.contrib import admin
from .models import Author, Book

class AuthorAdmin(admin.ModelAdmin):
    pass

class BookAdmin(admin.ModelAdmin):
    prepopulated_fields = {
        'slug': ('title',)
    }

admin.site.register(Author, AuthorAdmin)
admin.site.register(Book, BookAdmin)
  • BookAdmin: Book モデルの管理画面クラスです。 prepopulated_fields 属性を使用して、slug フィールドの値を title フィールドの値に基づいて自動的に生成します。
  • AuthorAdmin: Author モデルの管理画面クラスです。
  • Book モデル: タイトル、スラグ、著者、出版日、説明を持つ書籍を表します。
  • Author モデル: 名前とメールアドレスを持つ著者を表します。

この例は、基本的な使い方を示しています。 prepopulated_fields は、様々な状況に合わせて柔軟に利用することができます。

  • 参照元フィールドを複数指定する
prepopulated_fields = {
    'slug': ('title', 'author__name'),
}
  • 生成アルゴリズムをカスタマイズする
from django.template.defaultfilters import slugify

def generate_slug(obj):
    return slugify(obj.title) + '-' + slugify(obj.author.name)

prepopulated_fields = {
    'slug': (generate_slug,)
}
  • unique_for_date, unique_for_field などを使用する


代替手段の選択肢

  1. シグナルとレシーバーを使用する

    モデル保存時にシグナルを送信し、レシーバーで生成処理を行う方法です。 柔軟性が高く、複雑なロジックにも対応できますが、コード量が増え、煩雑になる可能性があります。

from django.db.models.signals import post_save
from django.dispatch import receiver

@receiver(post_save, sender=Book)
def generate_slug(sender, instance, **kwargs):
    instance.slug = slugify(instance.title)
    instance.save()
  1. フォームの clean メソッドを使用する

    フォームの clean メソッドをオーバーライドし、生成処理を行う方法です。 シンプルで分かりやすいですが、prepopulated_fields の機能ほど汎用性はありません。

from django.contrib import admin
from .models import Book

class BookAdmin(admin.ModelAdmin):
    form = BookModelForm

class BookModelForm(forms.ModelForm):
    def clean_slug(self):
        if not self.instance.slug:
            self.instance.slug = slugify(self.cleaned_data['title'])
        return self.cleaned_data['slug']
  1. JavaScriptを使用する

    JavaScript で動的にフィールドの値を更新する方法です。 フロントエンドでの処理が必要になりますが、柔軟性とユーザー体験の向上に繋げることができます。

$(document).ready(function() {
    $('#title').on('input', function() {
        var slug = $(this).val().replace(/ /g, '-').toLowerCase();
        $('#slug').val(slug);
    });
});

それぞれの利点と欠点

方法利点欠点
シグナルとレシーバー柔軟性が高いコード量が増える、煩雑になる
フォームの clean メソッドシンプル、分かりやすい汎用性が低い
JavaScript柔軟性が高い、ユーザー体験が向上フロントエンドでの処理が必要

状況に応じて、最も適切な方法を選択する必要があります。

  • ユーザー体験を重視する場合: JavaScript がおすすめです。
  • 柔軟性が必要な場合: シグナルとレシーバーがおすすめです。
  • シンプルな要件の場合: フォームの clean メソッドがおすすめです。
  • 保守性: シグナルとレシーバーは、コードが煩雑になりやすいため、保守性が低くなる可能性があります。
  • 処理速度: JavaScript は、他の方法よりも処理速度が遅くなる可能性があります。