Opened 4 years ago

Closed 4 years ago

Last modified 4 years ago

#16693 closed Bug (invalid)

Unregistering ModelAdmin view and registering it again changing its contents is not realized when invoking it.

Reported by: heidar_rafn Owned by: nobody
Component: contrib.admin Version: 1.3
Severity: Normal Keywords:
Cc: Triage Stage: Unreviewed
Has patch: no Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no

Description

When trying to make a change to the list_per_page option of a ModelAdmin class instance,
it seems that the change is not activated on the fly.
I first "unregister" the old ModelAdmin class and then "register" a new one (which is actually created)
but when trying to invoke the view, the old one is used, it looks like it is cached somewhere and the url-mechanism
is not using the re-created view, but invokes the old one.

After some investigation, I managed to create a work around that demonstrates what might be a bug,
see the code snippets, especially the "changelist_view" function - if it is omitted,
the behavior I am describing happens.

Here are code snippets that demonstrate this:

# settings.py
...
FLIGHTADMININSTANCE = None
...
# myapp/admin.py
...
from django.conf import settings
from myapp.models import ConfigParameters
...
class FlightAdmin(admin.ModelAdmin):

    try:
        list_per_page = int(ConfigParameters.objects.get(name="FLIGHTADMIN_LIST_PER_PAGE").value)
    except:
        list_per_page = 5;
    ...

    def __init__(self, *args, **kwargs):
        super(FlightAdmin, self).__init__(*args, **kwargs)
        # store globally the object instance pointer
        settings.FLIGHTADMININSTANCE = self
        # following debug shows that the list_per_page is really changed
        print "FlightAdmin created", self, self.list_per_page

    def changelist_view(self, request, extra_context=None, **kwargs):
        # NOTE: following is to override some probably cached instance of the view 
        # and enables the changed view to be used instead of the first instance created
        # of the FlightAdmin class if this hook is not used
        return super(FlightAdmin, settings.FLIGHTADMININSTANCE).changelist_view(request, extra_context=extra_context)

...
admin.site.register(Flight, FlightAdmin)
...

def list_per_page_change(sender, instance, created, **kwargs):
    if instance.name == 'FLIGHTADMIN_LIST_PER_PAGE':
        # yes - the value is changing, change the FlightAdmin class accordingly
        admin.site.unregister(Flight)
        try:
            admin.site.register(Flight, FlightAdmin, list_per_page=int(instance.value))
        except:
            admin.site.register(Flight, FlightAdmin)

post_save.connect (list_per_page_change, sender=ConfigParameters)

Change History (2)

comment:1 Changed 4 years ago by aaugustin

  • Needs documentation unset
  • Needs tests unset
  • Patch needs improvement unset
  • Resolution set to invalid
  • Status changed from new to closed

You shouldn't modify settings at runtime — never. The docs couldn't be more clear: https://docs.djangoproject.com/en/dev/topics/settings/#altering-settings-at-runtime

Even if your code worked, the settings would only be updated in the current process. On a multiprocess webserver (anything but the built-in dev server) you will have different settings in each process, and you will obtain random results, depending on which process handles your request. On a threaded webserver, you would get race conditions between settings.FLIGHTADMININSTANCE = self and super(FlightAdmin, settings.FLIGHTADMININSTANCE), which is likely to break in horrible ways.

Finally, unregister is undocumented; there's no commitment on what it does.


To sum up, I'm sorry, but your code has such fundamental problems that I can't figure out if there's really a problem of Django. If you can demonstrate that Django doesn't behave according to its documentation or reasonable expectations, please reopen the ticket.

Version 0, edited 4 years ago by aaugustin (next)

comment:2 Changed 4 years ago by heidar_rafn

Thanks for the comments. My problem to solve was to allow the user to configure the
ModelAdmin.list_per_page option, but I obviously did not describe it well enough and I did not read the documentation thoroughly enough in order to find the easy solution.
This problem is actually very easy to solve with the documented "ModelAdmin.changelist_view(self, request, extra_context=None)" option like this:

    def changelist_view(self, request, extra_context=None, **kwargs):
        try:
            self.list_per_page = int(ConfigParameters.objects.get(name="FLIGHTADMIN_LIST_PER_PAGE").value)
        except:
            self.list_per_page = 5;
        return super(FlightAdmin, self).changelist_view(request, extra_context=extra_context)

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