在 Django 1.11 admin 中创建新对象时评估只读字段
Evaluate a readonly field upon creating a new object in Django 1.11 admin
假设以下模型
# 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
字段,并在用户提交表单时评估其值。此外,在管理员中查看对象实例时,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
字段不会被填充,可能是因为它被排除在外了。如果我删除 exclude
然后它工作,但表单显示 age
字段,这不是所需的行为。
您可以使用 ModelAdmin
的 save_model
方法代替自定义表单:
class PersonAdmin(admin.ModelAdmin):
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)
def get_exclude(self, request, obj=None):
if not obj:
return ('age',)
return self.exclude
你也可以使用 readonly_fields
:
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
仅当对象为 none(创建案例)时才可以使用该表格。
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)
假设以下模型
# 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
字段,并在用户提交表单时评估其值。此外,在管理员中查看对象实例时,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
字段不会被填充,可能是因为它被排除在外了。如果我删除 exclude
然后它工作,但表单显示 age
字段,这不是所需的行为。
您可以使用 ModelAdmin
的 save_model
方法代替自定义表单:
class PersonAdmin(admin.ModelAdmin):
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)
def get_exclude(self, request, obj=None):
if not obj:
return ('age',)
return self.exclude
你也可以使用 readonly_fields
:
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
仅当对象为 none(创建案例)时才可以使用该表格。
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)