Ticket #11707: limit_ForeignKey.1.3.X.patch
File limit_ForeignKey.1.3.X.patch, 5.2 KB (added by , 13 years ago) |
---|
-
django/forms/models.py
diff -r 1d6c8709466a django/forms/models.py
a b 873 873 yield (u"", self.field.empty_label) 874 874 if self.field.cache_choices: 875 875 if self.field.choice_cache is None: 876 self.field.choice_cache = [ 877 self.choice(obj) for obj in self.queryset.all() 878 ] 876 self.field.choice_cache = list(self.distinct_choices()) 879 877 for choice in self.field.choice_cache: 880 878 yield choice 881 879 else: 882 for obj in self.queryset.all(): 880 for choice in self.distinct_choices(): 881 yield choice 882 883 def distinct_choices(self): 884 """Yields a choice for each distinct object in the queryset. 885 886 If you use limit_choices_to you could have more than one results for a 887 single Instance. DISTINCT in the db won't work as expected so we do 888 the check here.""" 889 seen_choices = set() 890 for obj in self.queryset.all(): 891 if obj.pk not in seen_choices: 892 seen_choices.add(obj.pk) 883 893 yield self.choice(obj) 884 894 885 895 def __len__(self): … … 969 979 return None 970 980 try: 971 981 key = self.to_field_name or 'pk' 972 value = self.queryset.get(**{key: value}) 982 values = self.queryset.filter(**{key: value}) 983 # If you use limit_choices_to you could have more than one results 984 # for a single Instance. DISTINCT in the db won't work as expected 985 # so we do the check here. 986 if not values: 987 raise self.queryset.model.DoesNotExist 988 if len(values) == 1: 989 value = values[0] 990 else: 991 pks = set(value.pk for value in values) 992 if len(pks) == 1: 993 value = values[0] 994 else: 995 raise self.queryset.model.MultipleObjectsReturned 973 996 except (ValueError, self.queryset.model.DoesNotExist): 974 997 raise ValidationError(self.error_messages['invalid_choice']) 975 998 return value -
tests/regressiontests/model_fields/models.py
diff -r 1d6c8709466a tests/regressiontests/model_fields/models.py
a b 29 29 b = models.CharField(max_length=10) 30 30 a = models.ForeignKey(Foo, default=get_foo) 31 31 32 class Baz(models.Model): 33 a = models.CharField(max_length=5) 34 #Only Foos related to Bars starting with 'a' 35 foo = models.ForeignKey(Foo, limit_choices_to=models.Q(bar__b__startswith='a')) 36 32 37 class Whiz(models.Model): 33 38 CHOICES = ( 34 39 ('Group 1', ( -
tests/regressiontests/model_fields/tests.py
diff -r 1d6c8709466a tests/regressiontests/model_fields/tests.py
a b 1 1 import datetime 2 2 from decimal import Decimal 3 import re 3 4 4 5 from django import test 5 6 from django import forms … … 8 9 from django.db.models.fields.files import FieldFile 9 10 from django.utils import unittest 10 11 11 from models import Foo, Bar, Whiz, BigD, BigS, Image, BigInt, Post, NullBooleanModel, BooleanModel, Document12 from models import Foo, Bar, Baz, Whiz, BigD, BigS, Image, BigInt, Post, NullBooleanModel, BooleanModel, Document 12 13 13 14 # If PIL available, do these tests. 14 15 if Image: … … 95 96 # This should not crash. That counts as a win for our purposes. 96 97 Foo.objects.filter(d__gte=100000000000) 97 98 99 100 class BazForm(forms.ModelForm): 101 class Meta: 102 model = Baz 103 104 98 105 class ForeignKeyTests(test.TestCase): 99 106 def test_callable_default(self): 100 107 """Test the use of a lazy callable for ForeignKey.default""" … … 102 109 b = Bar.objects.create(b="bcd") 103 110 self.assertEqual(b.a, a) 104 111 112 def test_distinct_choice_limit(self): 113 """Doesn't make sense to offer the same ForeignKey multiple times in a form""" 114 a = Foo.objects.create(a='a', d=Decimal("-1")) 115 b = Foo.objects.create(a='b', d=Decimal("1")) 116 Bar.objects.create(b='ah', a=a) 117 Bar.objects.create(b='aha', a=a) 118 Bar.objects.create(b='bla', a=b) 119 form = BazForm() 120 fk_field = str(form['foo']) 121 self.assertEqual(len(re.findall(r'value="%s"' % b.pk, fk_field)), 0) 122 self.assertEqual(len(re.findall(r'value="%s"' % a.pk, fk_field)), 1) 123 124 def test_distinct_choice_limit_save(self): 125 """Doesn't make sense to offer the same ForeignKey multiple times in a form""" 126 a = Foo.objects.create(a='a', d=Decimal("-1")) 127 b = Foo.objects.create(a='b', d=Decimal("1")) 128 Bar.objects.create(b='ah', a=a) 129 Bar.objects.create(b='aha', a=a) 130 Bar.objects.create(b='bla', a=b) 131 form = BazForm({'foo': a.pk, 'a': 'a'}) 132 self.assertTrue(form.is_valid()) 133 obj = form.save() 134 self.assertEqual(obj.foo.pk, a.pk) 135 105 136 class DateTimeFieldTests(unittest.TestCase): 106 137 def test_datetimefield_to_python_usecs(self): 107 138 """DateTimeField.to_python should support usecs"""