Dragster
Dragster

Reputation: 95

Dynamic url routing in django

I have a RoutingUrl model which describes all the urls used on my site with the view (foreign key to the View model) that has to manage the url and some other routing information. The urls are continuously growing in size, and should also support the redirect. The models are more or less the following:

class RoutingUrl(models.Model):
    url = models.CharField(unique=True, verbose_name='routing url')
    crc_checksum = models.IntegerField(editable=False)
    redirect_to = models.ForeignKey('RoutingUrl', related_name='redirect_from', blank=True, null=True)
    view = models.ForeignKey(View, related_name='routing_urls')

    content_type = models.ForeignKey(ContentType)
    object_id = models.PositiveIntegerField()
    content_object = GenericForeignKey('content_type', 'object_id')

class View(models.Model):
    name = models.CharField()

The RoutingUrl has also a generic foreign key with the model containing information about the page to be rendered (different models has to be supported, this is the reason for the generic foreign key).

Now the question is: how to implement such a dynamic routing into django ? My feeling is that I have two options:

  1. I could create a middleware which will take care of dispatching the request to the right view by implementing the process_request method (and so before the urlpatterns are checked). Obviously such a middleware should be positioned at the bottom of the middleware stack, in order to maintain the functionality of other middlewares. This solution will thus bypass the Django routing system.
  2. Another option could be to add a single catch all urlpattern that matches everything, and then just write my own handler/dispatcher as a view. That handler implement the routing process and so will call the appropriate view and return its HttpResponse

Could you suggest me which of the two options is the best to implement such a routing ? Of course if there is a third, better option, don't hesitate to suggest it to me.

Upvotes: 2

Views: 3447

Answers (1)

Dragster
Dragster

Reputation: 95

Investigating a bit into the django middleware hooks, it become evident that the process_request is not the best candidate for implementing the routing functionality. Indeed, from the documentation:

It should return either None or an HttpResponse object. If it returns None, Django will continue processing this request, executing any other process_request() middleware, then, process_view() middleware, and finally, the appropriate view. If it returns an HttpResponse object, Django won’t bother calling any other request, view or exception middleware, or the appropriate view; it’ll apply response middleware to that HttpResponse, and return the result.

So an HttpResponse will break the middleware stack functionalities. It's more or less the same for the process_view, which will avoid the calls of the exception middlewares. At this point it seems more smart to adopt the second option...

The django-cms plugin confirm this intuition, as you could see from the source code of the urlpatterns definition:

from django.conf import settings
from django.conf.urls import url

from cms.apphook_pool import apphook_pool
from cms.appresolver import get_app_patterns
from cms.views import details

# This is a constant, really, but must live here due to import order
SLUG_REGEXP = '[0-9A-Za-z-_.//]+'

if settings.APPEND_SLASH:
    regexp = r'^(?P<slug>%s)/$' % SLUG_REGEXP
else:
    regexp = r'^(?P<slug>%s)$' % SLUG_REGEXP

if apphook_pool.get_apphooks():
    # If there are some application urls, use special resolver,
    # so we will have standard reverse support.
    urlpatterns = get_app_patterns()
else:
    urlpatterns = []

urlpatterns.extend([
    url(regexp, details, name='pages-details-by-slug'),
    url(r'^$', details, {'slug': ''}, name='pages-root'),
])

Upvotes: 1

Related Questions