Login

Database Routing by URL

Author:
dcwatson
Posted:
May 25, 2010
Language:
Python
Version:
1.2
Tags:
multidb database router url
Score:
1 (after 1 ratings)

An example of how to select the "default" database based on the request URL instead of the model. The basic idea is that the middleware process_view (or process_request) function sets some context from the URL into thread local storage, and process_response deletes it. In between, any database operation will call the router, which checks for this context and returns an appropriate database alias.

In this snippet, it's assumed that any view in the system with a cfg keyword argument passed to it from the urlconf may be routed to a separate database. Take this urlconf for example:

url( r'^(?P<cfg>\w+)/account/$', 'views.account' )

The middleware and router will select a database whose alias is <cfg>, or "default" if none is listed in settings.DATABASES, all completely transparent to the view itself.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
import threading

request_cfg = threading.local()

class RouterMiddleware (object):
    def process_view( self, request, view_func, args, kwargs ):
        # Here you could do something with request.path instead.
        if 'cfg' in kwargs:
            request_cfg.cfg = kwargs['cfg']
    def process_response( self, request, response ):
        if hasattr( request_cfg, 'cfg' ):
            del request_cfg.cfg
        return response

class DatabaseRouter (object):
    def _default_db( self ):
        from django.conf import settings
        if hasattr( request_cfg, 'cfg' ) and request_cfg.cfg in settings.DATABASES:
            return request_cfg.cfg
        else:
            return 'default'
    def db_for_read( self, model, **hints ):
        return self._default_db()
    def db_for_write( self, model, **hints ):
        return self._default_db()

More like this

  1. default url routing and shortcut by vicalloy 5 years, 10 months ago
  2. Resolve URLs to view name by UloPe 6 years, 1 month ago
  3. Resolve URLs to view name and args/kwargs by fahhem 4 years, 5 months ago
  4. autocompleter with database query by bbolli 7 years, 9 months ago
  5. template tag for highlighting currently active page by adunar 6 years, 6 months ago

Comments

gijzelaerr (on July 18, 2014):

This really works well! I've enhanced it a bit, so it returns a 404 if the database doesn't exist and it adds the selected database to the context, see this gist:

https://gist.github.com/gijzelaerr/7a3130c494215a0dd9b2/

There is only one case where this doesn't work as intended, and that is when you are building queries outside of a page request. When you manually select a database with .using() this will be used, but when you follow references the database is reset to default. For example:

SomeTable.objects.using('dbname').first().othertable

For SomeTable the dbname database is used, but for OtherTable Django switches back default.

#

Please login first before commenting.