Made the database master router tolerant of router definitions that omit individual routing methods.
git-svn-id: http://code.djangoproject.com/svn/django/trunk@12304 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
parent
b0d218e9e2
commit
c8873bbba7
|
@ -103,9 +103,13 @@ class ConnectionRouter(object):
|
||||||
def _route_db(self, model, **hints):
|
def _route_db(self, model, **hints):
|
||||||
chosen_db = None
|
chosen_db = None
|
||||||
for router in self.routers:
|
for router in self.routers:
|
||||||
chosen_db = getattr(router, action)(model, **hints)
|
try:
|
||||||
if chosen_db:
|
chosen_db = getattr(router, action)(model, **hints)
|
||||||
return chosen_db
|
if chosen_db:
|
||||||
|
return chosen_db
|
||||||
|
except AttributeError:
|
||||||
|
# If the router doesn't have a method, skip to the next one.
|
||||||
|
pass
|
||||||
try:
|
try:
|
||||||
return hints['instance']._state.db or DEFAULT_DB_ALIAS
|
return hints['instance']._state.db or DEFAULT_DB_ALIAS
|
||||||
except KeyError:
|
except KeyError:
|
||||||
|
@ -117,14 +121,22 @@ class ConnectionRouter(object):
|
||||||
|
|
||||||
def allow_relation(self, obj1, obj2, **hints):
|
def allow_relation(self, obj1, obj2, **hints):
|
||||||
for router in self.routers:
|
for router in self.routers:
|
||||||
allow = router.allow_relation(obj1, obj2, **hints)
|
try:
|
||||||
if allow is not None:
|
allow = router.allow_relation(obj1, obj2, **hints)
|
||||||
return allow
|
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
|
return obj1._state.db == obj2._state.db
|
||||||
|
|
||||||
def allow_syncdb(self, db, model):
|
def allow_syncdb(self, db, model):
|
||||||
for router in self.routers:
|
for router in self.routers:
|
||||||
allow = router.allow_syncdb(db, model)
|
try:
|
||||||
if allow is not None:
|
allow = router.allow_syncdb(db, model)
|
||||||
return allow
|
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
|
return True
|
||||||
|
|
|
@ -99,7 +99,7 @@ routing scheme.
|
||||||
Database routers
|
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)
|
.. 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 router has no opinion. This method can be used to determine
|
||||||
the availability of a model on a given database.
|
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:
|
.. _topics-db-multi-db-hints:
|
||||||
|
|
||||||
Hints
|
Hints
|
||||||
|
|
|
@ -674,6 +674,11 @@ class AuthRouter(object):
|
||||||
return False
|
return False
|
||||||
return None
|
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):
|
class RouterTestCase(TestCase):
|
||||||
multi_db = True
|
multi_db = True
|
||||||
|
|
||||||
|
@ -724,6 +729,37 @@ class RouterTestCase(TestCase):
|
||||||
self.assertTrue(router.allow_syncdb('other', User))
|
self.assertTrue(router.allow_syncdb('other', User))
|
||||||
self.assertFalse(router.allow_syncdb('other', Book))
|
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):
|
def test_database_routing(self):
|
||||||
marty = Person.objects.using('default').create(name="Marty Alchin")
|
marty = Person.objects.using('default').create(name="Marty Alchin")
|
||||||
|
|
Loading…
Reference in New Issue