如何在Django Admin中要求内联?
我有一个管理界面,可以同时添加或编辑用户及其个人资料。
class ProfileInline(admin.StackedInline):
"""
Allows profile to be added when creating user
"""
model = Profile
class UserProfileAdmin(admin.ModelAdmin):
"""
Options for the admin interface
"""
inlines = [ProfileInline]
list_display = ['edit_obj', 'name', 'username', 'email', 'is_active',
'last_login', 'delete_obj']
list_display_links = ['username']
list_filter = ['is_active']
fieldsets = (
(None, {
'fields': ('first_name', 'last_name', 'email', 'username',
'is_active', 'is_superuser')}),
)
ordering = ['last_name', 'first_name']
search_fields = ['first_name', 'last_name']
admin.site.register(User, UserProfileAdmin)
现在的问题是,在添加用户时,我需要个人资料中的两个字段是必填的。但是,在线表单在没有输入内容时不会进行验证。有没有办法让这个在线表单变成必填,这样就不能留空呢?
7 个回答
你可能可以做到这一点,但需要在表单集和内联代码上动点手脚。
首先,我觉得在这种情况下,你希望表单集中始终只有一个表单,而不会有多个。所以你需要在你的 ProfileInline 中设置 max_num=1 和 extra=1。
你的核心问题是 BaseFormSet._construct_form 会将 empty_permitted=True 传递给每个“额外的”(即空的)表单。这个参数的意思是,如果表单没有变化,就跳过验证。你只需要找到一种方法,将 empty_permitted 设置为 False。
你可以 在你的内联中使用自己的 BaseInlineFormset 子类,这可能会有帮助。注意到 _construct_form 接受 **kwargs 参数,并允许你覆盖传递给每个表单实例的 kwargs,你可以在你的 Formset 子类中重写 _construct_forms,并在每次调用 _construct_form 时传递 empty_permitted=False。这样做的缺点是你依赖于内部 API(而且你需要重写 _construct_forms)。
另外,你也可以尝试重写 ProfileInline 的 get_formset 方法,在调用父类的 get_formset 之后,手动修改返回的表单集中的表单:
def get_formset(self, request, obj=None, **kwargs):
formset = super(ProfileInline, self).get_formset(request, obj, **kwargs)
formset.forms[0].empty_permitted = False
return formset
试着动手看看能做成什么!
现在使用Django 1.7,你可以使用一个叫做 min_num
的参数了。你不再需要使用 RequiredInlineFormSet
这个类了。
详情请查看 这个链接
class ProfileInline(admin.StackedInline):
"""
Allows profile to be added when creating user
"""
model = Profile
extra = 1
max_num = 1
min_num = 1 # new in Django 1.7
class UserProfileAdmin(admin.ModelAdmin):
"""
Options for the admin interface
"""
inlines = [ProfileInline]
...
admin.site.register(User, UserProfileAdmin)
我听了Carl的建议,做了一个比我在评论中提到的那个简陋实现要好得多的版本。下面是我的解决方案:
来自我的forms.py文件:
from django.forms.models import BaseInlineFormSet
class RequiredInlineFormSet(BaseInlineFormSet):
"""
Generates an inline formset that is required
"""
def _construct_form(self, i, **kwargs):
"""
Override the method to change the form attribute empty_permitted
"""
form = super(RequiredInlineFormSet, self)._construct_form(i, **kwargs)
form.empty_permitted = False
return form
还有admin.py文件:
class ProfileInline(admin.StackedInline):
"""
Allows profile to be added when creating user
"""
model = Profile
extra = 1
max_num = 1
formset = RequiredInlineFormSet
class UserProfileAdmin(admin.ModelAdmin):
"""
Options for the admin interface
"""
inlines = [ProfileInline]
list_display = ['edit_obj', 'name', 'username', 'email', 'is_active',
'last_login', 'delete_obj']
list_display_links = ['username']
list_filter = ['is_active']
fieldsets = (
(None, {
'fields': ('first_name', 'last_name', 'email', 'username',
'is_active', 'is_superuser')}),
(('Groups'), {'fields': ('groups', )}),
)
ordering = ['last_name', 'first_name']
search_fields = ['first_name', 'last_name']
admin.site.register(User, UserProfileAdmin)
这个实现完全符合我的需求,它让Profile的内联表单能够进行验证。所以,因为Profile表单中有必填字段,如果在内联表单中没有填写这些必填信息,它就会验证失败。