Skip to content

Commit

Permalink
[1.2.X] Fixed #14471 -- Corrected a regression in the use of methods …
Browse files Browse the repository at this point in the history
…on custom managers on related querysets. Thanks to Lucky for the report.

Backport of r14389 from trunk.

git-svn-id: http://code.djangoproject.com/svn/django/branches/releases/1.2.X@14390 bcc190cf-cafb-0310-a4f2-bffc1f526a37
  • Loading branch information
freakboy3742 committed Oct 28, 2010
1 parent 3a679cc commit 29ea1be
Show file tree
Hide file tree
Showing 3 changed files with 40 additions and 5 deletions.
8 changes: 4 additions & 4 deletions django/db/models/fields/related.py
Expand Up @@ -420,15 +420,15 @@ def add(self, *objs):
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):
# Update kwargs with the related object that this
# 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.
Expand Down Expand Up @@ -517,15 +517,15 @@ def create(self, **kwargs):
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

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:
Expand Down
15 changes: 14 additions & 1 deletion tests/regressiontests/multiple_database/models.py
Expand Up @@ -30,7 +30,21 @@ def __unicode__(self):
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)
Expand Down Expand Up @@ -60,4 +74,3 @@ class UserProfile(models.Model):

class Meta:
ordering = ('flavor',)

22 changes: 22 additions & 0 deletions tests/regressiontests/multiple_database/tests.py
Expand Up @@ -890,6 +890,28 @@ def test_subquery(self):
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
Expand Down

0 comments on commit 29ea1be

Please sign in to comment.