Opened 7 years ago

Closed 7 years ago

Last modified 7 years ago

#28262 closed Bug (fixed)

ModelAdmin.lookup_allowed() incorrectly raises DisallowedModelAdminLookup lookup with reverse relation to origin model

Reported by: Michal Dabski Owned by: Paulo
Component: contrib.admin Version: 1.11
Severity: Release blocker Keywords: admin, lookup_allowed
Cc: commonzenpython@… Triage Stage: Accepted
Has patch: yes Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no

Description (last modified by Tim Graham)

Consider the following models:

from django.db import models
from django.contrib.auth.models import User

class AuditSession(models.Model):
    auditor = models.ForeignKey(User, on_delete=models.CASCADE)

class Institution(models.Model):
    name = models.CharField(max_length=100)

    def __str__(self):
        return self.name

class Auditor(models.Model):
    user = models.OneToOneField(User, on_delete=models.CASCADE)
    institution = models.ForeignKey(Institution, on_delete=models.CASCADE, null=True, blank=True)

And the following filter in audit session admin:

from django.contrib import admin

from .models import AuditSession, Institution, Auditor

@admin.register(AuditSession)
class AuditSessionAdmin(admin.ModelAdmin):
    list_filter = (
        ('auditor__auditor__institution'),
    )

admin.site.register((Institution, Auditor))

As of Django version 1.9 up to the latest release 1.11.1, the above lookup will raise server error when used by raising DisallowedModelAdminLookup (Filtering by auditor__auditor__institution__id__exact not allowed). This is because the lookup uses reverse relation between User and Auditor model.

This lookup passes checks and only crashes when user tries to use the filter. I could not find the reasoning behind the implementation of lookup_allowed and why it would forbid using reverse relations. Nor could I find any documentation for this change in 1.9 release notes.
I have recently upgraded from django 1.8 where this lookup worked perfectly fine.

Change History (7)

comment:1 by Tim Graham, 7 years ago

Component: Uncategorizedcontrib.admin
Description: modified (diff)

I can reproduce the issue with some caveats. I used models.Model instead of BaseModel as you didn't provide a definition for that. I'm not sure if that difference matters.

I bisected the behavior change to c2e70f02653519db3a49cd48f5158ccad7434d25 which is odd because that commit shouldn't change behavior. However, before that commit (on 1.8), I get the error (admin.E116) The value of 'list_filter[0]' refers to 'auditor__auditor__institution', which does not refer to a Field. Afterward that commit, I see the DisallowedModelAdminLookup exception in this ticket's description.

comment:2 by Michal Dabski, 7 years ago

Description: modified (diff)

comment:3 by Tim Graham, 7 years ago

Description: modified (diff)
Severity: NormalRelease blocker
Summary: Using lookup with autocreated fields crashes django adminModelAdmin.lookup_allowed() incorrectly raises DisallowedModelAdminLookup lookup with reverse relation to origin model
Triage Stage: UnreviewedAccepted

Correction: 8f30556329b64005d63b66859a74752a0b261315 is the commit where the regression appeared. I'm updating the description with a copy/paste version of the models/admin that I used.

comment:4 by Paulo, 7 years ago

Owner: changed from nobody to Paulo
Status: newassigned

Thanks for the update Tim.
I'll take a stab at a fix.

comment:5 by Paulo, 7 years ago

Cc: commonzenpython@… added
Has patch: set

comment:6 by Tim Graham <timograham@…>, 7 years ago

Resolution: fixed
Status: assignedclosed

In b7f99f8:

Fixed #28262 -- Fixed incorrect DisallowedModelAdminLookup when a nested reverse relation is in list_filter.

comment:7 by Tim Graham <timograham@…>, 7 years ago

In 834d57b4:

[1.11.x] Fixed #28262 -- Fixed incorrect DisallowedModelAdminLookup when a nested reverse relation is in list_filter.

Backport of b7f99f84bcc4a06114ac31174840efab0aef7602 from master

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