different fields for add and change pages in admin

Viewed 15391

I have a django app with the following class in my admin.py:

class SoftwareVersionAdmin(ModelAdmin):
    fields = ("product", "version_number", "description",
      "media", "relative_url", "current_version")
    list_display = ["product", "version_number", "size",
      "current_version", "number_of_clients", "percent_of_clients"]
    list_display_links = ("version_number",)
    list_filter = ['product',]

I want to have these fileds for add page but different fields for change page. How can I do that?

10 Answers

This specific code did not work for me. I simply change it a little:

if obj: # obj is not None, so this is a change page
        #kwargs['exclude'] = ['owner']
        self.fields = ['id', 'family_name', 'status', 'owner']
    else: # obj is None, so this is an add page
        #kwargs['fields'] = ['id', 'family_name', 'status']
        self.fields = ['id', 'family_name', 'status']
    return super(YourAdmin, self).get_form(request, obj, **kwargs)

An easy way is to use fieldsets for the Change Page and add_fieldsets for the Add Page.

With more modern Django versions (3.2 at the time of writing), you can override some methods from BaseModelAdmin to achieve having different fields on the "change" and the "add" model admin page:

class BaseModelAdmin(metaclass=forms.MediaDefiningClass):
    """Functionality common to both ModelAdmin and InlineAdmin."""
    
    # ...

    def get_exclude(self, request, obj=None):
        """
        Hook for specifying exclude.
        """
        return self.exclude

    def get_fields(self, request, obj=None):
        """
        Hook for specifying fields.
        """
        if self.fields:
            return self.fields
        # _get_form_for_get_fields() is implemented in subclasses.
        form = self._get_form_for_get_fields(request, obj)
        return [*form.base_fields, *self.get_readonly_fields(request, obj)]

    def get_fieldsets(self, request, obj=None):
        """
        Hook for specifying fieldsets.
        """
        if self.fieldsets:
            return self.fieldsets
        return [(None, {'fields': self.get_fields(request, obj)})]

    def get_readonly_fields(self, request, obj=None):
        """
        Hook for specifying custom readonly fields.
        """
        return self.readonly_fields

For example, to add some read-only fields on the change page (obj exists), but not on the add page:

class MyModelAdmin(admin.ModelAdmin):
    
    # Readonly_fields only on change page
    def get_readonly_fields(self, request, obj=None):
        if obj:  # obj is not None, so this is a change page
            return 'field_1', 'field_2'
        return ()  # obj is None, so this is the add page
Related