GSoC Task 1 -- Documenting an absurd behaviour in the InlineModelAdmin
About the task
So my first task was relatively quite simple. I had to read the code for the InlineModelAdmin, verify that they produce a certain kind of behaviour, and then finally document that fact. Sounds simple, right? But trust me it wasn’t that straight forward. I completed this task in around one to one and a half weeks.
My approach for the task
So the task was pretty straightforward, but the one milestone that I have to clear was to learn about the framework that Django used for their testing and documentation. So I started learning about Sphinx and Unit Testing. It took me around four to five days to get a decent knowledge about Sphinx so that I could move forward. After which I check whether the concerned raised by Artem Skoretskiy in ticket 28831 were valid and pushed a PR to document that fact.
Technical description of the problem
The user was trying to use ModelAdmin.get_fieldsets
and InlineModelAdmin.get_fieldsets
to retrieve the model instances, but the problem was that both of returned different objects. One returned the parent model object, and another returned the child model object, which the user requested to change.
For example cosider the following example:
# 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 admins.py
@admin.register(models.Customer)
class AccountInline(admin.TabularInline):
model = models.Account
def get_fieldsets(self, request, obj=None):
print(repr(obj))
return ((None, {'fields': ('account_type',)}),)
class CustomerAdmin(admin.ModelAdmin):
inlines = (AccountInline,)
@admin.register(models.Account)
class AccountAdmin(admin.ModelAdmin):
def get_fieldsets(self, request, obj=None):
print(repr(obj))
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',)}),)
When you use ModelAdmin.get_fieldsets
, you will receive current object. In my example that would be, when you call AccountAdmin.get_fieldsets
, you will receive Account.
But when you use InlineModelAdmin.get_fieldsets
, you will receive parent object. In my example that would be, i.e. when you call AccountInline.get_fieldsets
you receive Customer
object instead of Account
. This may prevent one from retireving the Account object
But changing the behaviour of the get_fieldsets
method would have resulted in a failure of the backward compatibility of the framework. So it was decided that it’s worth a documentation note in the docs.