15

我尝试了各种方法来实现这一点。

我决定不重写formfield_for_dbfield,因为它没有得到请求对象的副本,我希望避免被thread_locals黑客入侵。

get_form我决定在我的课堂上覆盖ModelAdmin并尝试以下方法:

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)

当我打印fieldsetsdeclared_fieldsets从内部get_form得到None(或我在 中设置为初始值的任何内容PageOptions)时。

为什么这不起作用,有没有更好的方法来做到这一点?

4

8 回答 8

24

我有一些来自我最近的项目的示例代码,我相信它们可能会对您有所帮助。在此示例中,超级用户可以编辑每个字段,而其他所有人都排除了“描述”字段。

请注意,我认为您应该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)
于 2009-03-31T21:51:59.563 回答
14

我不知道为什么打印该属性不会让您希望您刚刚分配(我想这可能取决于您打印的确切位置),但请尝试覆盖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()})]

即你应该能够只返回你的元组。

由安迪巴克编辑。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
于 2009-04-04T16:16:52.467 回答
8

这是我的解决方案:

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) 

希望能有所帮助

于 2009-11-19T14:16:34.303 回答
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 类的 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') 
于 2011-05-29T08:11:35.660 回答
4

不要更改 self 属性的值,因为它不是线程安全的。您需要使用任何挂钩来覆盖这些值。

于 2010-10-27T08:54:39.670 回答
2

就我而言,使用 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)
于 2019-02-12T12:13:21.870 回答
1

您可以为此目的使用 get_fields 或 get_fieldset 方法

于 2020-12-01T13:20:54.967 回答
0

您可以制作fieldsetsform属性并让它们发出信号以获取所需的表单/字段集。

于 2012-03-30T14:02:02.310 回答