Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Modifing urlpatterns at runtime in Django

I'm developping a Django application that requires to load dynamic modules (at runtime). Now I'm able to upload (from client browser to server) "plugins" and register the plugin model in the database, etc. But I need a way to handle the urlpatterns for each plugin. Currently I've written a function in the "core" of the webapp that registers a model and (theoretically) adds the urlpatterns of the uploaded plugin to the webapp urls.py by including it. This function is:

def register_plugin_model(model,codename):
# Standard syncdb expects models to be in reliable locations,
# so dynamic models need to bypass django.core.management.syncdb.
# On the plus side, this allows individual models to be installed
# without installing the entire project structure.
# On the other hand, this means that things like relationships and
# indexes will have to be handled manually.
# This installs only the basic table definition.

if model is not None:
    style = color.no_style()
    cursor = connection.cursor()
    tables = connection.introspection.table_names()
    seen_models = connection.introspection.installed_models(tables)
    statements,trsh = connection.creation.sql_create_model(model, style, seen_models)
    for sql in statements:
        cursor.execute(sql)

# add urlpatterns
from django.conf.urls.defaults import patterns, url,include
from project.plugins.urls import urlpatterns
urlpatterns += patterns(url(r'^' + codename + '/' , include ( 'media.plugins.' + codename + '.urls' )))

Plugins are uploaded to "media/tmp" in tgz format and then extracted to "media/plugins/" where is the codename of the plugin, and the user uploaded plugins are managed by "project.plugins".

All plugins logic works fine, however when I try to include the uploaded plugin urls.py file into the webapp (project.plugins.urls) it takes no effect. I've printed the value of "project.plugins.urls.urlpatterns" and it's not modified after "urlpatterns += pat....".

Is there any way to do what I need?

Best regards

like image 832
user1302007 Avatar asked Mar 29 '12 22:03

user1302007


2 Answers

The problem you're facing, is that urlpatterns defined in your projects url.py file, and the urlpatterns defined in your register_plugin file are different variables. They are local to the module. Imagine the following scenario:

#math.py
pi = 3.14

#some_nasty_module.py
from math import pi
pi = 'for_teh_luls'

#your_module.py
from math import pi
pi * 2
>>> 'for_teh_lulsfor_teh_luls'
# wtf?

You're obviously not allowed to do this. What you're probably going to need to do, is ask the original urls.py to attempt to discover urls in your plugins folder.

# urls.py
urlpatterns += (...)

def load_plugin_urls():
    for module in get_plugin_modules():
        try:
            from module.urls import urlpatterns as u
            urlpatterns += u
        except:
            pass

Unfortunately, the webserver will need to recycle the process for this code to run, so uploading of plugins will only come into effect once that happens.

like image 156
Josh Smeaton Avatar answered Sep 23 '22 02:09

Josh Smeaton


The function that modifies urls.py and urls.py belong to the same module. I've solved it by adding an "empty pattern":

urlpatterns += patterns('',url(r'^' + codename + '/' , include ( 'media.plugins.' + codename + '.urls' )))

Now, it says:

BEFORE:
<RegexURLPattern plugins ^$>
<RegexURLPattern plugin_new ^new/$>
<RegexURLPattern plugin_profile ^profile/(?P<plugin>\w+)$>
AFTER
<RegexURLPattern plugins ^$>
<RegexURLPattern plugin_new ^new/$>
<RegexURLPattern plugin_profile ^profile/(?P<plugin>\w+)$>
<RegexURLResolver media.plugins.sampleplugin.urls (None:None) ^sampleplugin/>

But has you said, it doesn't take effect instantaneously :/

I've restarted the application without deleting *.pyc files, but changes didn't taken effect. What's the problem?

PD: the plugin urls.py file contains:

from django.conf.urls.defaults import patterns, url
from .views import index_view

urlpatterns = patterns( '' , url(r'^.*' , index_view ) )

Thanks for your reply

Best regards

like image 23
user1302007 Avatar answered Sep 20 '22 02:09

user1302007