在Django 1.11 admin中创建新对象时计算只读字段

在Django 1.11 admin中创建新对象时计算只读字段,django,django-admin,django-modeladmin,Django,Django Admin,Django Modeladmin,假设a为以下模型 # models.py class Person(models.Model): name = models.CharField(max_length=40) birthdate = models.DateField() age = models.CharField(max_length=3) # dont mind the type, this is just an example :) 所需的行为是,在用户创建新的Person对象时隐藏age字段,并

假设a为以下模型

# models.py
class Person(models.Model):
    name = models.CharField(max_length=40)
    birthdate = models.DateField()
    age = models.CharField(max_length=3) # dont mind the type, this is just an example :)
所需的行为是,在用户创建新的
Person
对象时隐藏
age
字段,并在用户提交表单时评估其值。此外,在admin中查看对象实例时,
age
字段应该可见

为了实现这一点,我创建了一个带有自定义
ModelForm
ModelAdmin
,如下所示

# admin.py
from django.contrib import admin
from django import forms
from .models import Person
from dateutil.relativedelta import relativedelta
import datetime

class PersonForm(forms.ModelForm):
    def clean(self):
        cleaned_data = super(PersonForm, self).clean()
        birthdate = cleaned_data.get('birthdate')
        cleaned_data['age'] = relativedelta(datetime.date.today(), birthdate).years
        return cleaned_data

class PersonAdmin(admin.ModelAdmin):
    form = PersonForm
    exclude = ('age',)

admin.site.register(Person, PersonAdmin)

但是,提交表单后,
age
字段不会填充,可能是因为它被排除在外。如果我删除了
排除
,则它可以工作,但表单显示的
年龄
字段不是所需的行为。

您可以使用
模型管理员
的方法代替自定义表单:

此外,您可能还可以使用:


或者您可以从表单中隐藏输入

# admin.py
from django.contrib import admin
from django import forms
from .models import Person
from dateutil.relativedelta import relativedelta
import datetime

class PersonForm(forms.ModelForm):
    age = forms.CharField(widget=forms.HiddenInput, required=False)
    def clean(self):
        cleaned_data = super(PersonForm, self).clean()
        birthdate = cleaned_data.get('birthdate')
        cleaned_data['age'] = relativedelta(datetime.date.today(), birthdate).years
        return cleaned_data
只有当对象为“无”(创建案例)时,才能使用该表单


你应该考虑一下是否真的需要一个年龄场。它需要在每个生日都有所改变。如果需要,最好通过从出生日期开始计算当前年龄的方法或属性提供。谢谢。查看对象实例时,
age
字段不可见。我将编辑我的问题以包含此内容。@Demetris正确,表单验证不会影响
age
字段。在管理中查看/编辑对象实例时,这不也会隐藏它吗?
 class PersonAdmin(admin.ModelAdmin):
    readonly_fields = ('age',)

    def save_model(self, request, obj, form, change):
        birthdate = form.cleaned_data.get('birthdate')
        age = relativedelta(datetime.date.today(), birthdate).years 
        obj.age = age
        super().save_model(request, obj, form, change)
# admin.py
from django.contrib import admin
from django import forms
from .models import Person
from dateutil.relativedelta import relativedelta
import datetime

class PersonForm(forms.ModelForm):
    age = forms.CharField(widget=forms.HiddenInput, required=False)
    def clean(self):
        cleaned_data = super(PersonForm, self).clean()
        birthdate = cleaned_data.get('birthdate')
        cleaned_data['age'] = relativedelta(datetime.date.today(), birthdate).years
        return cleaned_data
class PersonAdmin(admin.ModelAdmin):
    def get_form(self, request, obj=None, **kwargs):
        if not obj:
            kwargs['form'] = PersonForm
        return super().get_form(request, obj, **kwargs)

admin.site.register(Person, PersonAdmin)