首页 > 解决方案 > Django admin:继承基类字段,以便在保存时设置模型的字段

问题描述

我有模型CakeBakedCake有一个外键Cake并包含一个created_utc日期时间类型的字段。

假设我有模型,,,,CupCake每个模型都有一个外键字段LemonCake,因为它们共享此行为和许多其他行为,它们都继承自同一个基类。CheeseCakebaked_cakeBakedCakeBaseModel

现在在 , , 的 Django 管理界面中,CupCake我们希望显示s 而不是s 的列表,因此该列表更短且更容易从中选择。因此,我们宁愿显示s 的列表,然后一旦用户选择了 a ,我们使用当前的日期时间和业务逻辑来设置适当的保存时。LemonCakeCheeseCakeCakeBakedCakecakecakebaked_caked

演示代码:

# --- models.py

class Cake(models.Model):
    name = models.CharField("Bar name", max_length=200, unique=True)

class BakedCake(models.Model):
    cake = models.ForeignKey(Cake, on_delete=models.PROTECT)
    created_utc = models.DateTimeField()

class BaseModel(models.Model):
    baked_cake = models.ForeignKey(BakedCake, on_delete=models.PROTECT)
    # -- Lots of other common business logic here --

class CupCake(BaseModel):
    custom_field = models.CharField("Example1", max_length=200, unique=True)

class LemonCake(BaseModel):
    other_field = models.BooleanField("Example2", default=True, )

class CheeseCake(BaseModel):
    another_field = SmallFloatField("Example3", )

# --- admin.py

class BaseAdmin(admin.ModelAdmin):
    def get_form(self, request, obj=None, **kwargs):
        form = super().get_form(request, obj, **kwargs)  # This form object does not have .fields attribute
        form.fields = [x for x in form.fields if x != 'baked_cake']
        form.fields += 'cake'
        return form

@admin.register(CupCake)
class CupCakeAdmin(BaseAdmin):
    pass

@admin.register(LemonCake)
class LemonCakeAdmin(BaseAdmin):
    pass

@admin.register(CheeseCake)
class CheeseCakeAdmin(BaseAdmin):
    pass

不幸的是,该对象form.fields不存在。form如何替换基ModelAdmin类的字段,使其派生类也继承这些更改?

概括

我要做的不是在管理界面中显示原始模型的字段,而是显示另一个模型的备用字段,然后在保存时使用业务逻辑来选择适当的原始字段。这需要在多个模型中发生,因此从基本模型继承逻辑。

注意:使用 Django 3

标签: pythondjangodjango-admin

解决方案


这种模型管理类的设置绝对有效(至少在 Django 3.1 中)

from django.contrib import admin
from django import forms
from .models import Cake


class AbstractModelAdmin(admin.ModelAdmin):
    def get_baked_cake_instance(self, cake):
        return "something"

    def get_form(self, request, obj=None, change=False, **kwargs):
        form = forms.modelform_factory(self.model, exclude=("baked_cake",))
        form.base_fields["cake"] = forms.ModelChoiceField(queryset=Cake.objects.all())
        return form

    def save_form(self, request, form, change):
        model_instance = form.save(commit=False)
        model_instance.baked_cake = self.get_baked_cake_instance(form.cleaned_data["cake"])
        return model_instance

然后,注册你的模型,

admin.site.register(CupCake, AbstractModelAdmin)
admin.site.register(LemonCake, AbstractModelAdmin)
admin.site.register(CheeseCake, AbstractModelAdmin)

示例截图

示例截图

注意:不要忘记get_baked_cake_instance(...)用你的逻辑完成方法!!!


推荐阅读