我尝试了各种方法来实现这一目标。
我决定不覆盖formfield_for_dbfield,因为它没有得到请求对象的副本,我希望避免使用thread_locals hack。
我决定在我的ModelAdmin类中覆盖get_form并尝试以下操作:
class PageOptions(admin.ModelAdmin):
def get_form(self, request, obj=None, **kwargs):
if request.user.is_superuser:
self.fieldsets = ((None, {'fields': ('title','name',),}),)
else:
self.fieldsets = ((None, {'fields': ('title',),}),)
return super(PageOptions,self).get_form(request, obj=None, **kwargs)
当我从get_form中打印fieldsets或declared_fieldsets时,我得到None(或者我在PageOptions中设置的初始值)。
为什么这不起作用,是否有更好的方法来做到这一点?
答案 0 :(得分:22)
我从我最近的一个项目中得到了一些示例代码,我相信这些代码可以帮到你。在此示例中,超级用户可以编辑每个字段,而其他所有人都排除了“描述”字段。
请注意,我认为您需要从Form
返回get_form
课程,这可能就是您的工作不正常的原因。
以下是示例:
class EventForm(forms.ModelForm):
class Meta:
model = models.Event
exclude = ['description',]
class EventAdminForm(forms.ModelForm):
class Meta:
model = models.Event
class EventAdmin(admin.ModelAdmin):
def get_form(self, request, obj=None, **kwargs):
if request.user.is_superuser:
return EventAdminForm
else:
return EventForm
admin.site.register(models.Event, EventAdmin)
答案 1 :(得分:9)
我不知道为什么打印属性并不会让你想要你刚刚分配(我猜这可能取决于你打印的位置,确切地说),但是请尝试覆盖get_fieldsets
。基本实现如下所示:
def get_fieldsets(self, request, obj=None): if self.declared_fieldsets: return self.declared_fieldsets form = self.get_formset(request).form return [(None, {'fields': form.base_fields.keys()})]
即。你应该能够归还你的元组。
由andybak编辑。 4年后,当我尝试在另一个项目上做类似的事情时,我再次发现了自己的问题。这次我采用了这种方法,虽然略有修改,以避免重复字段集定义:
def get_fieldsets(self, request, obj=None):
# Add 'item_type' on add forms and remove it on changeforms.
fieldsets = super(ItemAdmin, self).get_fieldsets(request, obj)
if not obj: # this is an add form
if 'item_type' not in fieldsets[0][1]['fields']:
fieldsets[0][1]['fields'] += ('item_type',)
else: # this is a change form
fieldsets[0][1]['fields'] = tuple(x for x in fieldsets[0][1]['fields'] if x!='item_type')
return fieldsets
答案 2 :(得分:6)
这是我的解决方案:
class MyModelAdmin(admin.ModelAdmin):
def get_form(self, request, obj=None, **kwargs):
if request.user.is_superuser:
self.exclude = ()
else:
self.exclude = ('field_to_exclude',)
return super(MyModelAdmin, self).get_form(request, obj=None, **kwargs)
希望可以提供帮助
答案 3 :(得分:6)
为了创建自定义管理表单,我们定义了一个可用作mixin的新类。这种方法非常灵活:
ModelAdmin:定义包含所有字段的字段集
ModelForm:缩小显示的字段
FlexibleModelAdmin:覆盖ModelAdmin的get_fieldsets方法;返回仅包含管理表单中定义的字段的简化字段集
class FlexibleModelAdmin(object):
'''
adds the possibility to use a fieldset as template for the generated form
this class should be used as mix-in
'''
def _filterFieldset(self, proposed, form):
'''
remove fields from a fieldset that do not
occur in form itself.
'''
allnewfields = []
fields = form.base_fields.keys()
fieldset = []
for fsname, fdict in proposed:
newfields = []
for field in fdict.get('fields'):
if field in fields:
newfields.append(field)
allnewfields.extend(newfields)
if newfields:
newentry = {'fields': newfields}
fieldset.append([fsname, newentry])
# nice solution but sets are not ordered ;)
# don't forget fields that are in a form but were forgotten
# in fieldset template
lostfields = list(set(fields).difference(allnewfields))
if len(lostfields):
fieldset.append(['lost in space', {'fields': lostfields}])
return fieldset
def get_fieldsets(self, request, obj=None):
'''
Hook for specifying fieldsets for the add form.
'''
if hasattr(self, 'fieldsets_proposed'):
form = self.get_form(request, obj)
return self._filterFieldset(self.fieldsets_proposed, form)
else:
return super(FlexibleModelAdmin, self).get_fieldsets(request, obj)
在管理模型中,您可以定义fieldsets_proposed作为模板并包含所有字段。
class ReservationAdmin(FlexibleModelAdmin, admin.ModelAdmin):
list_display = ['id', 'displayFullName']
list_display_links = ['id', 'displayFullName']
date_hierarchy = 'reservation_start'
ordering = ['-reservation_start', 'vehicle']
exclude = ['last_modified_by']
# considered by FlexibleModelAdmin as template
fieldsets_proposed = (
(_('General'), {
'fields': ('vehicle', 'reservation_start', 'reservation_end', 'purpose') # 'added_by'
}),
(_('Report'), {
'fields': ('mileage')
}),
(_('Status'), {
'fields': ('active', 'editable')
}),
(_('Notes'), {
'fields': ('note')
}),
)
....
def get_form(self, request, obj=None, **kwargs):
'''
set the form depending on the role of the user for the particular group
'''
if request.user.is_superuser:
self.form = ReservationAdminForm
else:
self.form = ReservationUserForm
return super(ReservationAdmin, self).get_form(request, obj, **kwargs)
admin.site.register(Reservation, ReservationAdmin)
在模型表单中,您现在可以定义要排除/包含的字段。 mixin-class的get_fieldset()确保只返回表单中定义的字段。
class ReservationAdminForm(ModelForm):
class Meta:
model = Reservation
exclude = ('added_by', 'last_modified_by')
class ReservationUserForm(BaseReservationForm):
class Meta:
model = Reservation
fields = ('vehicle', 'reservation_start', 'reservation_end', 'purpose', 'note')
答案 4 :(得分:4)
不要更改self属性的值,因为它不是线程安全的。你需要使用任何钩子来覆盖这些值。
答案 5 :(得分:1)
就我而言,使用Django 2.1,您可以执行以下操作
在forms.py
中class ObjectAddForm(forms.ModelForm):
class Meta:
model = Object
exclude = []
class ObjectChangeForm(forms.ModelForm):
class Meta:
model = Object
exclude = []
然后在admin.py
中from your.app import ObjectAddForm, ObjectChangeForm
class ObjectAdmin(admin.ModelAdmin):
....
def get_form(self, request, obj=None, **kwargs):
if obj is None:
kwargs['form'] = ObjectAddForm
else:
kwargs['form'] = ObjectChangeForm
return super().get_form(request, obj, **kwargs)
答案 6 :(得分:0)
您可以制作fieldsets
和form
属性并让它们发出信号以获得所需的表单/字段集。
答案 7 :(得分:0)
您可以为此目的使用get_fields或get_fieldset方法