Opened 3 weeks ago

Last modified 3 weeks ago

#28831 new Cleanup/optimization

Document that InlineModelAdmin methods' obj argument is the parent object

Reported by: tonnzor Owned by: nobody
Component: Documentation Version: 2.0
Severity: Normal Keywords:
Cc: tonn81@… Triage Stage: Accepted
Has patch: no Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no

Description

When I use ModelAdmin.get_fieldsets, I receive current object. In my example that would be -- when I call AccountAdmin.get_fieldsets -- I receive Account. That enable me to generate different field sets for different cases.

BUT when I use InlineModelAdmin.get_fieldsets, I receive parent object. In my example that would be -- when I call
AccountInline.get_fieldsets -- I receive Customer object instead of `Account. That prevents me from configuring formsets to the account I have.

If I received Account, I could extract Customer from it. But if I receive Customer, I cannot adapt form for each row.

Also, it seems strange that class explicitly linked to Account receives Customer object as input.

Code:

# in models.py

class Customer(models.Model):
    num = models.IntegerField()


class Account(models.Model):
    ACCOUNT_TYPES = (
        (1, 'A'),
        (2, 'B'),
    )
    customer = models.ForeignKey(Customer)
    account_type = models.IntegerField(choices=ACCOUNT_TYPES)

    a = models.CharField(max_length=255, blank=True) # should be edited when type = "A"
    b = models.CharField(max_length=255, blank=True) # should be edited when type = "B"

# in admin.py

class AccountInline(admin.TabularInline):
    model = models.Account

    def get_fieldsets(self, request, obj=None):
        print(repr(obj)) # => <Customer>
        """
        if obj and obj.account_type == 1:
            return ((None, {'fields': ('account_type', 'a')}),)
        elif obj and obj.account_type == 2:
            return ((None, {'fields': ('account_type', 'b')}),)
        """
        return ((None, {'fields': ('account_type',)}),)

@admin.register(models.Customer)
class CustomerAdmin(admin.ModelAdmin):
    inlines = (AccountInline,)

@admin.register(models.Account)
class AccountAdmin(admin.ModelAdmin):
    def get_fieldsets(self, request, obj=None):
        print(repr(obj)) # => <Account>
        if obj and obj.account_type == 1:
            return ((None, {'fields': ('account_type', 'a')}),)
        elif obj and obj.account_type == 2:
            return ((None, {'fields': ('account_type', 'b')}),)
        return ((None, {'fields': ('account_type',)}),)

Change History (2)

comment:1 Changed 3 weeks ago by tonnzor

By the way, custom fields on inline admins receive correct object:

class AccountInline(admin.TabularInline):
    ...

    def type_verbose(self, obj):
         return "Account is {}".format(obj.get_account_type_display())

    type_verbose.short_description = "Account type"

comment:2 Changed 3 weeks ago by Tim Graham

Component: contrib.adminDocumentation
Summary: InlineModelAdmin.get_fieldsets should receive own object, not parentDocument that InlineModelAdmin methods' obj argument is the parent object
Triage Stage: UnreviewedAccepted
Type: BugCleanup/optimization

I don't believe changing the behavior is possible and of course it would also be backwards incompatible. Perhaps the documentation could clarify the current behavior.

Note: See TracTickets for help on using tickets.
Back to Top