From 3dddbc0f2380d2654e66c8df4bb40d5e1d42af98 Mon Sep 17 00:00:00 2001 From: Tomek Paczkowski Date: Sat, 23 Feb 2013 15:50:33 +0100 Subject: [PATCH] Fixed #19816: pre-evaluate queryset on m2m set In ReverseManyRelatedObjectsDescriptor.__set__, evaluate possible queryset to avoid problems when clear() would touch data this queryset returns. --- django/db/models/fields/related.py | 3 +++ tests/regressiontests/m2m_regress/tests.py | 15 ++++++++++++++- 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/django/db/models/fields/related.py b/django/db/models/fields/related.py index bea88ba3377..01b8a550d17 100644 --- a/django/db/models/fields/related.py +++ b/django/db/models/fields/related.py @@ -904,6 +904,9 @@ class ReverseManyRelatedObjectsDescriptor(object): raise AttributeError("Cannot set values on a ManyToManyField which specifies an intermediary model. Use %s.%s's Manager instead." % (opts.app_label, opts.object_name)) manager = self.__get__(instance) + # clear() can change expected output of 'value' queryset, we force evaluation + # of queryset before clear; ticket #19816 + value = tuple(value) manager.clear() manager.add(*value) diff --git a/tests/regressiontests/m2m_regress/tests.py b/tests/regressiontests/m2m_regress/tests.py index 3dc1d2417c2..90aab5e2a57 100644 --- a/tests/regressiontests/m2m_regress/tests.py +++ b/tests/regressiontests/m2m_regress/tests.py @@ -5,7 +5,7 @@ from django.test import TestCase from django.utils import six from .models import (SelfRefer, Tag, TagCollection, Entry, SelfReferChild, - SelfReferChildSibling, Worksheet, RegressionModelSplit) + SelfReferChildSibling, Worksheet, RegressionModelSplit, Line) class M2MRegressionTests(TestCase): @@ -96,3 +96,16 @@ class M2MRegressionTests(TestCase): # causes a TypeError in add_lazy_relation m1 = RegressionModelSplit(name='1') m1.save() + + def test_m2m_filter(self): + worksheet = Worksheet.objects.create(id=1) + line_hi = Line.objects.create(name="hi") + line_bye = Line.objects.create(name="bye") + + worksheet.lines = [line_hi, line_bye] + hi = worksheet.lines.filter(name="hi") + + worksheet.lines = hi + self.assertEquals(1, worksheet.lines.count()) + self.assertEquals(1, hi.count()) +