Ticket #13240: add_remove_querysets.diff

File add_remove_querysets.diff, 5.8 KB (added by gabrielhurley, 5 years ago)
  • django/db/models/fields/related.py

     
    411411
    412412            def add(self, *objs):
    413413                for obj in objs:
    414                     if not isinstance(obj, self.model):
     414                    if isinstance(obj, QuerySet) and obj.model == self.model:
     415                        for queried_obj in obj.all():
     416                            setattr(queried_obj, rel_field.name, instance)
     417                            queried_obj.save()
     418                    elif not isinstance(obj, self.model):
    415419                        raise TypeError("'%s' instance expected" % self.model._meta.object_name)
    416                     setattr(obj, rel_field.name, instance)
    417                     obj.save()
     420                    else:
     421                        setattr(obj, rel_field.name, instance)
     422                        obj.save()
    418423            add.alters_data = True
    419424
    420425            def create(self, **kwargs):
     
    435440                def remove(self, *objs):
    436441                    val = getattr(instance, rel_field.rel.get_related_field().attname)
    437442                    for obj in objs:
     443                        if isinstance(obj, QuerySet) and obj.model == self.model:
     444                            for queried_obj in obj.all():
     445                                # We'll pass over non-related objects in the QuerySet silently
     446                                if getattr(queried_obj, rel_field.attname) == val:
     447                                    setattr(queried_obj, rel_field.name, None)
     448                                    queried_obj.save()
    438449                        # Is obj actually part of this descriptor set?
    439                         if getattr(obj, rel_field.attname) == val:
     450                        elif getattr(obj, rel_field.attname) == val:
    440451                            setattr(obj, rel_field.name, None)
    441452                            obj.save()
    442453                        else:
     
    548559                           raise ValueError('Cannot add "%r": instance is on database "%s", value is on database "%s"' %
    549560                                               (obj, self.instance._state.db, obj._state.db))
    550561                        new_ids.add(obj.pk)
     562                    elif isinstance(obj, QuerySet) and obj.model == self.model:
     563                        new_ids.update(set(obj.values_list("id", flat=True)))
    551564                    elif isinstance(obj, Model):
    552565                        raise TypeError("'%s' instance expected" % self.model._meta.object_name)
    553566                    else:
     
    584597                for obj in objs:
    585598                    if isinstance(obj, self.model):
    586599                        old_ids.add(obj.pk)
     600                    elif isinstance(obj, QuerySet) and obj.model == self.model:
     601                        old_ids.update(set(obj.values_list("id", flat=True)))
    587602                    else:
    588603                        old_ids.add(obj)
    589604                # Remove the specified objects from the join table
  • docs/ref/models/relations.txt

     
    3333.. method:: QuerySet.add(obj1, [obj2, ...])
    3434
    3535    Adds the specified model objects to the related object set.
     36   
     37    .. versionchanged:: 1.2
     38   
     39    The ``add()`` method can now accept ``QuerySet`` objects as well.
    3640
    3741    Example::
    3842
     
    8488    without being added to another. In the above example, removing ``e`` from
    8589    ``b.entry_set()`` is equivalent to doing ``e.blog = None``, and because the
    8690    ``blog`` ``ForeignKey`` doesn't have ``null=True``, this is invalid.
     91   
     92    .. versionchanged:: 1.2
     93   
     94    The ``remove()`` method can now accept ``QuerySet`` objects as well.
    8795
    8896.. method:: QuerySet.clear()
    8997
  • tests/modeltests/many_to_many/models.py

     
    6161# Adding a second time is OK
    6262>>> a2.publications.add(p3)
    6363
     64# Adding and removing using QuerySets works too
     65>>> p4 = Publication(id=None, title='Science Times')
     66>>> p4.save()
     67>>> a2.publications.add(Publication.objects.filter(title__contains="Science"))
     68>>> a2.publications.all()
     69[<Publication: Science News>, <Publication: Science Times>, <Publication: Science Weekly>, <Publication: The Python Journal>]
     70>>> a2.publications.remove(Publication.objects.filter(title__contains="Times"))
     71>>> p4.delete()
     72
    6473# Adding an object of the wrong type raises TypeError
    6574>>> a2.publications.add(a1)
    6675Traceback (most recent call last):
  • tests/modeltests/many_to_one/models.py

     
    7979...
    8080TypeError: 'Article' instance expected
    8181
     82>>> r3 = Reporter(first_name='Eric', last_name='James', email='eric@example.com')
     83>>> r3.save()
     84>>> a3 = Article.objects.create(headline="Human interest story", reporter=r, pub_date=datetime(2010, 3, 04))
     85>>> a4 = Article.objects.create(headline="Eric's story", reporter=r, pub_date=datetime(2010, 3, 14))
     86>>> new_articles = Article.objects.filter(pub_date__year=2010, pub_date__month=3)
     87>>> r3.article_set.add(new_articles)
     88>>> r3.article_set.all()
     89[<Article: Eric's story>, <Article: Human interest story>]
     90>>> new_articles.delete()
     91>>> r3.delete()
     92
    8293>>> r.article_set.all()
    8394[<Article: John's second story>, <Article: This is a test>]
    8495>>> r2.article_set.all()
Back to Top