Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Django - Overriding get_form to customize admin forms based on request

I've tried various methods to achieve this.

I decided against overriding formfield_for_dbfield as it doesn't get a copy of the request object and I was hoping to avoid the thread_locals hack.

I settled on overriding get_form in my ModelAdmin class and tried the following:

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)

When I print fieldsets or declared_fieldsets from within get_form I get None (or whatever I set as an initial value in PageOptions).

Why doesn't this work and is there a better way to do this?

like image 495
Andy Baker Avatar asked Mar 26 '09 22:03

Andy Baker


2 Answers

I have some sample code from a recent project of mine that I believe may help you. In this example, super users can edit every field, while everyone else has the "description" field excluded.

Note that I think it's expected that you return a Form class from get_form, which could be why yours was not working quite right.

Here's the example:

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)
like image 109
Ryan Duffield Avatar answered Oct 05 '22 11:10

Ryan Duffield


I have no idea why printing the property doesn't give you want you just assigned (I guess may be that depends on where you print, exactly), but try overriding get_fieldsets instead. The base implementation looks like this:

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()})]

I.e. you should be able to just return your tuples.

EDIT by andybak. 4 years on and I found my own question again when trying to do something similar on another project. This time I went with this approach although modified slightly to avoid having to repeat fieldsets definition:

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
like image 34
miracle2k Avatar answered Oct 05 '22 12:10

miracle2k