Yesterday I ranted a bit about how to insert extra GET parameters in the django change list page without having the admin blow up when it was not able to recognise them as filters. I’m using this for building a custom menu that uses GET parameters to fold / unfold a submenu. The menu is context aware so I can’t do this by looking up the path, ie. several submenu points can like to /admin/auth/user/, usually just with different filter parameters.
I haven’t been able to find a nice solution for this, but here is a dirty one. As always I find myself using middlewares when something takes a nasty turn. The idea is to put the information in GET parameters, but use a middleware to actually find the special parameters and insert them on the request object. A context processor can then later give template the variables. I’m controlling which parameters we should fetch with a simple settings tuple:
#!/usr/bin/python/
ADMIN_GET_VARS = (
('submenu', None),
)
In my case I have only defined the submenu parameter, but you could take as many as you’ll like. The second element in the tuple (The None after “submenu”) is a default value that will be used if the GET parameter is not present. The middleware looks like this:
#!/usr/bin/python/
from django.conf import settings
class ForwardGetMiddleware:
def process_request(self, request):
new_get = request.GET.copy()
custom_vars = {}
if hasattr(settings, "ADMIN_GET_VARS"):
for name, default in settings.ADMIN_GET_VARS:
custom_vars[name] = new_get.get(name, default)
try:
del new_get[name]
except KeyError:
pass
request.ADMIN_GET_VARS = custom_vars
request.GET = new_get
Here is something important. We need to remove the get parameter from the request.GET as it will otherwise make the admin blow up. It’s therefore important that you don’t use parameter names that will clash with the admin. I’m considering introducing a prefix on every parameter to leave the admin alone. The context processor is very simple due to the way we build the middleware:
#!/usr/bin/python/
def admin_get_vars(request):
return getattr(request, "ADMIN_GET_VARS", {} )
So there it is in a very basic stage. It’s possible to introduce more advanced settings to enable finer control with when this functionality kicks in, but it’s already a hack, so I don’t think there is any need for it. Also, one might consider trying to limit this to specific urls to improve performance and limit the number of side effects this might have.










