当前位置:  开发笔记 > 编程语言 > 正文

Django - 覆盖get_form以根据请求自定义管理表单

如何解决《Django-覆盖get_form以根据请求自定义管理表单》经验,为你挑选了4个好方法。

我尝试过各种方法来实现这一目标.

我决定不要覆盖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中设置的初始值).

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



1> Ryan Duffiel..:

我从我最近的一个项目中得到了一些示例代码,我相信这些代码可以帮到你.在此示例中,超级用户可以编辑每个字段,而其他人都排除了"描述"字段.

请注意,我认为您可以从中返回一个Formget_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)



2> miracle2k..:

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



3> Mauro De Gio..:

这是我的解决方案:

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) 

希望可以帮助



4> 小智..:

为了创建自定义管理表单,我们定义了一个可以用作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') 

推荐阅读
低调pasta_730
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有