Opened 13 years ago

Closed 13 years ago

Last modified 13 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 by Aymeric Augustin, 13 years ago

Resolution: invalid
Status: newclosed

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 13 years ago by Aymeric Augustin (next)

comment:2 by heidar_rafn, 13 years ago

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