Commit 8a724802 authored by Russell Keith-Magee's avatar Russell Keith-Magee
Browse files

Fixed #14471 -- Corrected a regression in the use of methods on custom...

Fixed #14471 -- Corrected a regression in the use of methods on custom managers on related querysets. Thanks to Lucky for the report.

git-svn-id: http://code.djangoproject.com/svn/django/trunk@14389 bcc190cf-cafb-0310-a4f2-bffc1f526a37
parent ded416bc
Loading
Loading
Loading
Loading
+4 −4
Original line number Diff line number Diff line
@@ -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:
+14 −1
Original line number Diff line number Diff line
@@ -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',)
+22 −0
Original line number Diff line number Diff line
@@ -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