Permalink
Browse files

Made the database master router tolerant of router definitions that o…

…mit individual routing methods.

git-svn-id: http://code.djangoproject.com/svn/django/trunk@12304 bcc190cf-cafb-0310-a4f2-bffc1f526a37
  • Loading branch information...
1 parent b0d218e commit c8873bbba76bc52ab0766f98e8537b2fa66be71c @freakboy3742 freakboy3742 committed Jan 27, 2010
Showing with 62 additions and 10 deletions.
  1. +21 −9 django/db/utils.py
  2. +5 −1 docs/topics/db/multi-db.txt
  3. +36 −0 tests/regressiontests/multiple_database/tests.py
View
@@ -103,9 +103,13 @@ def _router_func(action):
def _route_db(self, model, **hints):
chosen_db = None
for router in self.routers:
- chosen_db = getattr(router, action)(model, **hints)
- if chosen_db:
- return chosen_db
+ try:
+ chosen_db = getattr(router, action)(model, **hints)
+ if chosen_db:
+ return chosen_db
+ except AttributeError:
+ # If the router doesn't have a method, skip to the next one.
+ pass
try:
return hints['instance']._state.db or DEFAULT_DB_ALIAS
except KeyError:
@@ -117,14 +121,22 @@ def _route_db(self, model, **hints):
def allow_relation(self, obj1, obj2, **hints):
for router in self.routers:
- allow = router.allow_relation(obj1, obj2, **hints)
- if allow is not None:
- return allow
+ try:
+ allow = router.allow_relation(obj1, obj2, **hints)
+ if allow is not None:
+ return allow
+ except AttributeError:
+ # If the router doesn't have a method, skip to the next one.
+ pass
return obj1._state.db == obj2._state.db
def allow_syncdb(self, db, model):
for router in self.routers:
- allow = router.allow_syncdb(db, model)
- if allow is not None:
- return allow
+ try:
+ allow = router.allow_syncdb(db, model)
+ if allow is not None:
+ return allow
+ except AttributeError:
+ # If the router doesn't have a method, skip to the next one.
+ pass
return True
@@ -99,7 +99,7 @@ routing scheme.
Database routers
----------------
-A database Router is a class that provides four methods:
+A database Router is a class that provides up to four methods:
.. method:: db_for_read(model, **hints)
@@ -141,6 +141,10 @@ A database Router is a class that provides four methods:
the router has no opinion. This method can be used to determine
the availability of a model on a given database.
+A router doesn't have to provide *all* these methods - it omit one or
+more of them. If one of the methods is omitted, Django will skip that
+router when performing the relevant check.
+
.. _topics-db-multi-db-hints:
Hints
@@ -674,6 +674,11 @@ def allow_syncdb(self, db, model):
return False
return None
+class WriteRouter(object):
+ # A router that only expresses an opinion on writes
+ def db_for_write(self, model, **hints):
+ return 'writer'
+
class RouterTestCase(TestCase):
multi_db = True
@@ -724,6 +729,37 @@ def test_syncdb_selection(self):
self.assertTrue(router.allow_syncdb('other', User))
self.assertFalse(router.allow_syncdb('other', Book))
+ def test_partial_router(self):
+ "A router can choose to implement a subset of methods"
+ dive = Book.objects.using('other').create(title="Dive into Python",
+ published=datetime.date(2009, 5, 4))
+
+ # First check the baseline behaviour
+
+ self.assertEquals(router.db_for_read(User), 'other')
+ self.assertEquals(router.db_for_read(Book), 'other')
+
+ self.assertEquals(router.db_for_write(User), 'default')
+ self.assertEquals(router.db_for_write(Book), 'default')
+
+ self.assertTrue(router.allow_relation(dive, dive))
+
+ self.assertTrue(router.allow_syncdb('default', User))
+ self.assertTrue(router.allow_syncdb('default', Book))
+
+ router.routers = [WriteRouter(), AuthRouter(), TestRouter()]
+
+ self.assertEquals(router.db_for_read(User), 'other')
+ self.assertEquals(router.db_for_read(Book), 'other')
+
+ self.assertEquals(router.db_for_write(User), 'writer')
+ self.assertEquals(router.db_for_write(Book), 'writer')
+
+ self.assertTrue(router.allow_relation(dive, dive))
+
+ self.assertFalse(router.allow_syncdb('default', User))
+ self.assertTrue(router.allow_syncdb('default', Book))
+
def test_database_routing(self):
marty = Person.objects.using('default').create(name="Marty Alchin")

0 comments on commit c8873bb

Please sign in to comment.