我尝试过各种方法来实现这一目标.
我决定不要覆盖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中设置的初始值).
为什么这不起作用,是否有更好的方法来做到这一点?
我从我最近的一个项目中得到了一些示例代码,我相信这些代码可以帮到你.在此示例中,超级用户可以编辑每个字段,而其他人都排除了"描述"字段.
请注意,我认为您可以从中返回一个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)
我不知道为什么打印属性不会让你想要你刚刚分配(我猜可能这取决于你打印的位置,确切),但尝试覆盖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
这是我的解决方案:
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)
希望可以帮助
为了创建自定义管理表单,我们定义了一个可以用作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')