Sajjad Ahmed Shaaz
Sajjad Ahmed Shaaz

Reputation: 93

DJango admin read_only fields

Below is my admin.py file:

# readonly_fields=['product_images']
def product_images(self, obj):
    return mark_safe(
        f'''
            <img class='product' src="{obj.product_image.url}">
            <img class='product' src="{obj.product_back_image.url}">
            <img class='product' src="{obj.product_pack_image.url}">
            <img class='product' src="{obj.product_detailed_image.url}">
        '''
    )


def get_form(self, request, obj=None, **kwargs):
    # Proper kwargs are form, fields, exclude, formfield_callback
    if obj: # obj is not None, so this is a change page
        kwargs['exclude'] = ['product_image', 'product_back_image', 'product_pack_image', 'product_detailed_image']
        # self.readonly_fields=['product_images']
    else: # obj is None, so this is an add page
        kwargs['exclude'] = ['product_image_link', 'product_back_image_link', 'product_pack_image_link', 'product_detailed_image_link']
               
    return super(ProductAdmin, self).get_form(request, obj, **kwargs)

The problem is with the first line, if I uncomment it I get an error as below: enter image description here

Is there any work around for the same?

Upvotes: 0

Views: 158

Answers (1)

tim-mccurrach
tim-mccurrach

Reputation: 6815

The problem

The issue here is that get_form doesn't expect exclude in kwargs. Under the hood it creates it's own exclude by adding the readonly fields to the result of get_exclude.

This gets overwritten by the exclude in kwargs however when get_form does this:

        defaults = {
            ...
            'exclude': exclude,
            ...
            **kwargs,
        }

The Solution

Use the get_exclude hook instead of get_form. It's designed for exactly this situation. Something like this should do the trick:

class YourAdmin(admin.ModelAdmin):

    readonly_fields= ("product_images",)

    def product_images(self, obj):
        # do stuff
        return something

    def get_exclude(self, request, obj=None):
        """
        Hook for specifying exclude.
        """
        if obj: # obj is not None, so this is a change page
            return ['product_image', 'product_back_image', 'product_pack_image', 'product_detailed_image']
        else: # obj is None, so this is an add page
            return ['product_image_link', 'product_back_image_link', 'product_pack_image_link', 'product_detailed_image_link']
               

Upvotes: 1

Related Questions