Skip to content

Commit

Permalink
Fixed #13358 -- Ensured that db_manager() can be used to override dat…
Browse files Browse the repository at this point in the history
…abase routing on M2M, reverse FK and generic key queries. Thanks to Craig Kimerer for the report.

git-svn-id: http://code.djangoproject.com/svn/django/trunk@12993 bcc190cf-cafb-0310-a4f2-bffc1f526a37
  • Loading branch information
freakboy3742 committed Apr 16, 2010
1 parent 94a968c commit 2cd48ba
Show file tree
Hide file tree
Showing 3 changed files with 47 additions and 5 deletions.
9 changes: 6 additions & 3 deletions django/contrib/contenttypes/generic.py
Expand Up @@ -243,11 +243,12 @@ def __init__(self, model=None, core_filters=None, instance=None, symmetrical=Non
self.pk_val = self.instance._get_pk_val()

def get_query_set(self):
db = self._db or router.db_for_read(self.model, instance=self.instance)
query = {
'%s__pk' % self.content_type_field_name : self.content_type.id,
'%s__exact' % self.object_id_field_name : self.pk_val,
}
return superclass.get_query_set(self).using(self.instance._state.db).filter(**query)
return superclass.get_query_set(self).using(db).filter(**query)

def add(self, *objs):
for obj in objs:
Expand All @@ -259,13 +260,15 @@ def add(self, *objs):
add.alters_data = True

def remove(self, *objs):
db = router.db_for_write(self.model, instance=self.instance)
for obj in objs:
obj.delete(using=self.instance._state.db)
obj.delete(using=db)
remove.alters_data = True

def clear(self):
db = router.db_for_write(self.model, instance=self.instance)
for obj in self.all():
obj.delete(using=self.instance._state.db)
obj.delete(using=db)
clear.alters_data = True

def create(self, **kwargs):
Expand Down
4 changes: 2 additions & 2 deletions django/db/models/fields/related.py
Expand Up @@ -406,7 +406,7 @@ def create_manager(self, instance, superclass):

class RelatedManager(superclass):
def get_query_set(self):
db = router.db_for_read(rel_model, instance=instance)
db = self._db or router.db_for_read(rel_model, instance=instance)
return superclass.get_query_set(self).using(db).filter(**(self.core_filters))

def add(self, *objs):
Expand Down Expand Up @@ -480,7 +480,7 @@ def __init__(self, model=None, core_filters=None, instance=None, symmetrical=Non
raise ValueError("%r instance needs to have a primary key value before a many-to-many relationship can be used." % instance.__class__.__name__)

def get_query_set(self):
db = router.db_for_read(self.instance.__class__, instance=self.instance)
db = self._db or router.db_for_read(self.instance.__class__, instance=self.instance)
return superclass.get_query_set(self).using(db)._next_is_sticky().filter(**(self.core_filters))

# If the ManyToMany relation has an intermediary model,
Expand Down
39 changes: 39 additions & 0 deletions tests/regressiontests/multiple_database/tests.py
Expand Up @@ -1186,6 +1186,45 @@ def test_generic_key_cross_database_protection(self):
nyt = dive.reviews.create(source="New York Times", content_object=dive)
self.assertEquals(nyt._state.db, 'default')

def test_m2m_managers(self):
"M2M relations are represented by managers, and can be controlled like managers"
pro = Book.objects.using('other').create(pk=1, title="Pro Django",
published=datetime.date(2008, 12, 16))

marty = Person.objects.using('other').create(pk=1, name="Marty Alchin")
pro.authors = [marty]

self.assertEquals(pro.authors.db, 'other')
self.assertEquals(pro.authors.db_manager('default').db, 'default')
self.assertEquals(pro.authors.db_manager('default').all().db, 'default')

self.assertEquals(marty.book_set.db, 'other')
self.assertEquals(marty.book_set.db_manager('default').db, 'default')
self.assertEquals(marty.book_set.db_manager('default').all().db, 'default')

def test_foreign_key_managers(self):
"FK reverse relations are represented by managers, and can be controlled like managers"
marty = Person.objects.using('other').create(pk=1, name="Marty Alchin")
pro = Book.objects.using('other').create(pk=1, title="Pro Django",
published=datetime.date(2008, 12, 16),
editor=marty)

self.assertEquals(marty.edited.db, 'other')
self.assertEquals(marty.edited.db_manager('default').db, 'default')
self.assertEquals(marty.edited.db_manager('default').all().db, 'default')

def test_generic_key_managers(self):
"Generic key relations are represented by managers, and can be controlled like managers"
pro = Book.objects.using('other').create(title="Pro Django",
published=datetime.date(2008, 12, 16))

review1 = Review.objects.using('other').create(source="Python Monthly",
content_object=pro)

self.assertEquals(pro.reviews.db, 'other')
self.assertEquals(pro.reviews.db_manager('default').db, 'default')
self.assertEquals(pro.reviews.db_manager('default').all().db, 'default')

def test_subquery(self):
"""Make sure as_sql works with subqueries and master/slave."""
# Create a book and author on the other database
Expand Down

0 comments on commit 2cd48ba

Please sign in to comment.