Fixed #13668 -- Corrected database router methods invocation for ManyToMany fields without through models. Thanks craig.kimerer for the report and David Gouldin for the fix.
This also adds tests for r14857. git-svn-id: http://code.djangoproject.com/svn/django/trunk@15185 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
parent
fd12e3b218
commit
e1ede214e6
|
@ -555,7 +555,7 @@ def create_many_related_manager(superclass, rel=False):
|
||||||
raise TypeError("'%s' instance expected" % self.model._meta.object_name)
|
raise TypeError("'%s' instance expected" % self.model._meta.object_name)
|
||||||
else:
|
else:
|
||||||
new_ids.add(obj)
|
new_ids.add(obj)
|
||||||
db = router.db_for_write(self.through.__class__, instance=self.instance)
|
db = router.db_for_write(self.through, instance=self.instance)
|
||||||
vals = self.through._default_manager.using(db).values_list(target_field_name, flat=True)
|
vals = self.through._default_manager.using(db).values_list(target_field_name, flat=True)
|
||||||
vals = vals.filter(**{
|
vals = vals.filter(**{
|
||||||
source_field_name: self._pk_val,
|
source_field_name: self._pk_val,
|
||||||
|
@ -597,7 +597,7 @@ def create_many_related_manager(superclass, rel=False):
|
||||||
else:
|
else:
|
||||||
old_ids.add(obj)
|
old_ids.add(obj)
|
||||||
# Work out what DB we're operating on
|
# Work out what DB we're operating on
|
||||||
db = router.db_for_write(self.through.__class__, instance=self.instance)
|
db = router.db_for_write(self.through, instance=self.instance)
|
||||||
# Send a signal to the other end if need be.
|
# Send a signal to the other end if need be.
|
||||||
if self.reverse or source_field_name == self.source_field_name:
|
if self.reverse or source_field_name == self.source_field_name:
|
||||||
# Don't send the signal when we are deleting the
|
# Don't send the signal when we are deleting the
|
||||||
|
@ -618,7 +618,7 @@ def create_many_related_manager(superclass, rel=False):
|
||||||
model=self.model, pk_set=old_ids, using=db)
|
model=self.model, pk_set=old_ids, using=db)
|
||||||
|
|
||||||
def _clear_items(self, source_field_name):
|
def _clear_items(self, source_field_name):
|
||||||
db = router.db_for_write(self.through.__class__, instance=self.instance)
|
db = router.db_for_write(self.through, instance=self.instance)
|
||||||
# source_col_name: the PK colname in join_table for the source object
|
# source_col_name: the PK colname in join_table for the source object
|
||||||
if self.reverse or source_field_name == self.source_field_name:
|
if self.reverse or source_field_name == self.source_field_name:
|
||||||
# Don't send the signal when we are clearing the
|
# Don't send the signal when we are clearing the
|
||||||
|
|
|
@ -1791,3 +1791,56 @@ class SignalTests(TestCase):
|
||||||
b.authors.clear()
|
b.authors.clear()
|
||||||
self._write_to_default()
|
self._write_to_default()
|
||||||
self.assertEqual(receiver._database, "other")
|
self.assertEqual(receiver._database, "other")
|
||||||
|
|
||||||
|
class AttributeErrorRouter(object):
|
||||||
|
"A router to test the exception handling of ConnectionRouter"
|
||||||
|
def db_for_read(self, model, **hints):
|
||||||
|
raise AttributeError
|
||||||
|
|
||||||
|
def db_for_write(self, model, **hints):
|
||||||
|
raise AttributeError
|
||||||
|
|
||||||
|
class RouterAttributeErrorTestCase(TestCase):
|
||||||
|
multi_db = True
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
self.old_routers = router.routers
|
||||||
|
router.routers = [AttributeErrorRouter()]
|
||||||
|
|
||||||
|
def tearDown(self):
|
||||||
|
router.routers = self.old_routers
|
||||||
|
|
||||||
|
def test_attribute_error(self):
|
||||||
|
"Check that the AttributeError from AttributeErrorRouter bubbles up"
|
||||||
|
dive = Book()
|
||||||
|
dive.title="Dive into Python"
|
||||||
|
dive.published = datetime.date(2009, 5, 4)
|
||||||
|
self.assertRaises(AttributeError, dive.save)
|
||||||
|
|
||||||
|
class ModelMetaRouter(object):
|
||||||
|
"A router to ensure model arguments are real model classes"
|
||||||
|
def db_for_write(self, model, **hints):
|
||||||
|
if not hasattr(model, '_meta'):
|
||||||
|
raise ValueError
|
||||||
|
|
||||||
|
class RouterM2MThroughTestCase(TestCase):
|
||||||
|
multi_db = True
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
self.old_routers = router.routers
|
||||||
|
router.routers = [ModelMetaRouter()]
|
||||||
|
|
||||||
|
def tearDown(self):
|
||||||
|
router.routers = self.old_routers
|
||||||
|
|
||||||
|
def test_m2m_through(self):
|
||||||
|
b = Book.objects.create(title="Pro Django",
|
||||||
|
published=datetime.date(2008, 12, 16))
|
||||||
|
|
||||||
|
p = Person.objects.create(name="Marty Alchin")
|
||||||
|
# test add
|
||||||
|
b.authors.add(p)
|
||||||
|
# test remove
|
||||||
|
b.authors.remove(p)
|
||||||
|
# test clear
|
||||||
|
b.authors.clear()
|
||||||
|
|
Loading…
Reference in New Issue