diff --git a/django/db/models/fields/related.py b/django/db/models/fields/related.py index 1634d7d974..954a338cf8 100644 --- a/django/db/models/fields/related.py +++ b/django/db/models/fields/related.py @@ -420,7 +420,7 @@ class ForeignRelatedObjectsDescriptor(object): def create(self, **kwargs): kwargs.update({rel_field.name: instance}) db = router.db_for_write(rel_model, instance=instance) - return super(RelatedManager, self).using(db).create(**kwargs) + return super(RelatedManager, self.db_manager(db)).create(**kwargs) create.alters_data = True def get_or_create(self, **kwargs): @@ -428,7 +428,7 @@ class ForeignRelatedObjectsDescriptor(object): # ForeignRelatedObjectsDescriptor knows about. kwargs.update({rel_field.name: instance}) db = router.db_for_write(rel_model, instance=instance) - return super(RelatedManager, self).using(db).get_or_create(**kwargs) + return super(RelatedManager, self.db_manager(db)).get_or_create(**kwargs) get_or_create.alters_data = True # remove() and clear() are only provided if the ForeignKey can have a value of null. @@ -517,7 +517,7 @@ def create_many_related_manager(superclass, rel=False): opts = through._meta raise AttributeError("Cannot use create() on a ManyToManyField which specifies an intermediary model. Use %s.%s's Manager instead." % (opts.app_label, opts.object_name)) db = router.db_for_write(self.instance.__class__, instance=self.instance) - new_obj = super(ManyRelatedManager, self).using(db).create(**kwargs) + new_obj = super(ManyRelatedManager, self.db_manager(db)).create(**kwargs) self.add(new_obj) return new_obj create.alters_data = True @@ -525,7 +525,7 @@ def create_many_related_manager(superclass, rel=False): def get_or_create(self, **kwargs): db = router.db_for_write(self.instance.__class__, instance=self.instance) obj, created = \ - super(ManyRelatedManager, self).using(db).get_or_create(**kwargs) + super(ManyRelatedManager, self.db_manager(db)).get_or_create(**kwargs) # We only need to add() if created because if we got an object back # from get() then the relationship already exists. if created: diff --git a/tests/regressiontests/multiple_database/models.py b/tests/regressiontests/multiple_database/models.py index e0be761ca0..ce71828700 100644 --- a/tests/regressiontests/multiple_database/models.py +++ b/tests/regressiontests/multiple_database/models.py @@ -30,7 +30,21 @@ class Person(models.Model): class Meta: ordering = ('name',) +# This book manager doesn't do anything interesting; it just +# exists to strip out the 'extra_arg' argument to certain +# calls. This argument is used to establish that the BookManager +# is actually getting used when it should be. +class BookManager(models.Manager): + def create(self, *args, **kwargs): + kwargs.pop('extra_arg', None) + return super(BookManager, self).create(*args, **kwargs) + + def get_or_create(self, *args, **kwargs): + kwargs.pop('extra_arg', None) + return super(BookManager, self).get_or_create(*args, **kwargs) + class Book(models.Model): + objects = BookManager() title = models.CharField(max_length=100) published = models.DateField() authors = models.ManyToManyField(Person) @@ -60,4 +74,3 @@ class UserProfile(models.Model): class Meta: ordering = ('flavor',) - diff --git a/tests/regressiontests/multiple_database/tests.py b/tests/regressiontests/multiple_database/tests.py index e5e9ff20fc..0993ecdd6d 100644 --- a/tests/regressiontests/multiple_database/tests.py +++ b/tests/regressiontests/multiple_database/tests.py @@ -891,6 +891,28 @@ class QueryTestCase(TestCase): except ValueError: pass + def test_related_manager(self): + "Related managers return managers, not querysets" + mark = Person.objects.using('other').create(name="Mark Pilgrim") + + # extra_arg is removed by the BookManager's implementation of + # create(); but the BookManager's implementation won't get called + # unless edited returns a Manager, not a queryset + mark.book_set.create(title="Dive into Python", + published=datetime.date(2009, 5, 4), + extra_arg=True) + + mark.book_set.get_or_create(title="Dive into Python", + published=datetime.date(2009, 5, 4), + extra_arg=True) + + mark.edited.create(title="Dive into Water", + published=datetime.date(2009, 5, 4), + extra_arg=True) + + mark.edited.get_or_create(title="Dive into Water", + published=datetime.date(2009, 5, 4), + extra_arg=True) class TestRouter(object): # A test router. The behaviour is vaguely master/slave, but the