12

Is there a way to programmatically add URL Patterns to Django without having to restart the server?

Or is there a way force Django to reprocess/cache URL patterns ( the URLconf )?

Tom Neyland
  • 6,860
  • 2
  • 36
  • 52
  • 1
    Are you using `mod_wsgi`? If so, you can restart your app without restarting the entire Apache server. – S.Lott Feb 01 '11 at 18:58
  • @S.Lott for the production server yes, so this might work, how do you restart a specific app? Is there anything similar for the dev server? – Tom Neyland Feb 01 '11 at 19:01
  • @S.Lott, For 'dev server' I mean the buit-in development server that comes with Django, eg: python manage.py runserver. I may have misunderstood your first comment though, were you suggesting it is possible to restart a single Django App without restarting the other Apps, or were you suggesting you can restart Django/All apps without having to restart Apache? I'd need to do the former. – Tom Neyland Feb 01 '11 at 19:09
  • The built-in development server that comes with Django restarts itself when you make a code change. If you use `mod_wsgi`, the production server restarts itself when you touch the `wsgi` file. – S.Lott Feb 01 '11 at 19:25
  • @S.Lott, The changes are programmatic, so the source files do not change. I will read about wsgi and see if I can use it accomplish what I need. – Tom Neyland Feb 01 '11 at 19:29
  • 1
    "programmatic"? What can that possibly mean? The `urls.py` is read exactly once when Django starts up and cannot be re-read without restarting Django. – S.Lott Feb 01 '11 at 19:48
  • @S.Lott, programmatic, as in using python's type() to generate model classes, which is what I need the urls for. Classes that get generated using type() during the module import are working just fine, URLs and all, but if they are generated using the same functions post import, everything works as expected, except for URL handling. – Tom Neyland Feb 01 '11 at 20:09
  • This sounds like a you're doing too much of the wrong kind of metaprogramming. Dynamic models and Dynamic URL's usurps Django as the framework. Without considerably more details, I can only say that it sounds like you're using the tool incorrectly. If you want to write your own framework, don't use an existing framework. – S.Lott Feb 01 '11 at 20:16
  • @S.Lott, haha I realize that without further context it may seem odd ( with context maybe only marginally better). I was testing an idea tangentially related to Django-Eav, http://mvpdev.github.com/django-eav/ . – Tom Neyland Feb 01 '11 at 20:26
  • If you're building dynamic models based on EAV, you've really wandered quite far afield. Django gives you a great deal of flexibility. EAV adds to that. That's about the limit. If you want more flexibility than that, I suggest you discard Django and EAV and begin again from the beginning with MongoDB and WerkZeug. – S.Lott Feb 01 '11 at 20:28
  • @S.Lott, Not to sound crass, but that suggestion isn't practical, relevant to what I am doing, or at this point related to the question I asked. As I said earlier what I am working on is **already functional** in all aspects except for the irritation of having to restart Django to get URLs added- which isn't needed too often, and will be less when things are solidified. So to, 'discard Django and EAV (not using it) and begin again from the beginning' would be a bad decision. – Tom Neyland Feb 01 '11 at 20:50
  • @instanceofTom: Not to sound any more crass than I already have, but what you're doing sounds -- again -- like you're doing too much of the wrong kind of metaprogramming. The fact that elements work doesn't make it a good idea at all. – S.Lott Feb 01 '11 at 20:58
  • @S.Lott, I understand where you are coming from. However, this particular situation/app benefits from the metaprogramming, and there isn't a frightening quantity of it either. "The fact that elements work doesn't make it a good idea at all." Doesn't make it a bad idea either. What make an idea 'good' depends on the metrics you use to evaluate the it, in this case all of the metrics relevant to us (Performance and otherwise) are evaluating positively. http://code.djangoproject.com/wiki/AuditTrail shows an interesting application of the same type of meta-programming I am doing. – Tom Neyland Feb 01 '11 at 21:28
  • I don't know your intended usage, but if it's any help, you might want to check out [@kanu's answer to my question](http://stackoverflow.com/a/20439825/2387772) about dynamic proxy models management in the admin site. There's a way to create dynamic sub-views for usage within the admin site, which sounds like that uber-functionality you are looking for. Maybe you should look at how the admin makes it happen and do something similar in your own project – yuvi Jan 06 '14 at 14:26

4 Answers4

4

If you use gunicorn without code preloading, just send a HUP to the gunicorn master process, it will spawn new workers which load the new code, and gracefully shut down the old ones, without a single lost request!

rewritten
  • 16,280
  • 2
  • 47
  • 50
3

I tried something like this by hacking some things in django.core.urlresolvers – it worked for me but note that it's a hack. I don't still have the code, but I did something like this:

  1. Django typically uses urlresolvers.get_resolver() to get a RegexURLResolver which is responsible for resolving URLs. Passing None to this function gets your "root" URLConf.
  2. get_resolver() uses a cache, _resolver_cache, for loaded URLConfs.
  3. Resetting _resolver_cache should force Django to recreate a clean URLResolver.

Alternatively, you might try to unset the _urlconf_module attribute of the root RegexURLResolver, which should force Django to reload it (not sure about this though, it's possible that the module will be cached by Python).

from urlresolvers import get_resolver

delattr(get_resolver(None), '_urlconf_module')

Again, not guaranteed that this will work (I'm working from memory from code that I've obviously discarded for some reason). But django/core/urlresolvers.py is definitely the file you'll want to look at.

EDIT: Decided to experiment some with this and it didn't work...

EDIT2:

As I thought, your URL modules will be cached by Python. Simply reloading them as they change might work (using reload). If, your problem is that you're dynamically constructing urlpatterns based on some data which might change.

I tried reloading my root URLs (project.urls) and a suburl module (app.urls). That's all I had to do for the new URLs to be displayed by get_resolver(None).url_patterns

So the trick might be this simple: Manually reload your URL module.

vicvicvic
  • 6,025
  • 4
  • 38
  • 55
2

Here is your answer :

import sys
from django.conf import settings
from importlib import reload
from django.urls import clear_url_caches

urlconf = settings.ROOT_URLCONF
  if urlconf in sys.modules:
      clear_url_caches()
      reload(sys.modules[urlconf])
1

This seams also an elegant way to do it :

http://codeinthehole.com/writing/how-to-reload-djangos-url-config/

Simply do that to reload your root urls module :

reload_urlconf()
Pirhoo
  • 680
  • 8
  • 21