Ticket #11707: limit_ForeignKey.1.2.X.patch
File limit_ForeignKey.1.2.X.patch, 5.2 KB (added by , 13 years ago) |
---|
-
django/forms/models.py
diff -r 77515d829c8b django/forms/models.py
a b 882 882 yield (u"", self.field.empty_label) 883 883 if self.field.cache_choices: 884 884 if self.field.choice_cache is None: 885 self.field.choice_cache = [ 886 self.choice(obj) for obj in self.queryset.all() 887 ] 885 self.field.choice_cache = list(self.distinct_choices()) 888 886 for choice in self.field.choice_cache: 889 887 yield choice 890 888 else: 891 for obj in self.queryset.all(): 889 for choice in self.distinct_choices(): 890 yield choice 891 892 def distinct_choices(self): 893 """Yields a choice for each distinct object in the queryset. 894 895 If you use limit_choices_to you could have more than one results for a 896 single Instance. DISTINCT in the db won't work as expected so we do 897 the check here.""" 898 seen_choices = set() 899 for obj in self.queryset.all(): 900 if obj.pk not in seen_choices: 901 seen_choices.add(obj.pk) 892 902 yield self.choice(obj) 893 903 894 904 def __len__(self): … … 978 988 return None 979 989 try: 980 990 key = self.to_field_name or 'pk' 981 value = self.queryset.get(**{key: value}) 991 values = self.queryset.filter(**{key: value}) 992 # If you use limit_choices_to you could have more than one results 993 # for a single Instance. DISTINCT in the db won't work as expected 994 # so we do the check here. 995 if not values: 996 raise self.queryset.model.DoesNotExist 997 if len(values) == 1: 998 value = values[0] 999 else: 1000 pks = set(value.pk for value in values) 1001 if len(pks) == 1: 1002 value = values[0] 1003 else: 1004 raise self.queryset.model.MultipleObjectsReturned 982 1005 except (ValueError, self.queryset.model.DoesNotExist): 983 1006 raise ValidationError(self.error_messages['invalid_choice']) 984 1007 return value -
tests/regressiontests/model_fields/models.py
diff -r 77515d829c8b 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 77515d829c8b tests/regressiontests/model_fields/tests.py
a b 1 1 import datetime 2 2 import unittest 3 3 from decimal import Decimal 4 import re 4 5 5 6 import django.test 6 7 from django import forms 7 8 from django.db import models 8 9 from django.core.exceptions import ValidationError 9 10 10 from models import Foo, Bar, Whiz, BigD, BigS, Image, BigInt, Post, NullBooleanModel, BooleanModel11 from models import Foo, Bar, Baz, Whiz, BigD, BigS, Image, BigInt, Post, NullBooleanModel, BooleanModel 11 12 12 13 # If PIL available, do these tests. 13 14 if Image: … … 94 95 # This should not crash. That counts as a win for our purposes. 95 96 Foo.objects.filter(d__gte=100000000000) 96 97 98 class BazForm(forms.ModelForm): 99 class Meta: 100 model = Baz 101 97 102 class ForeignKeyTests(django.test.TestCase): 98 103 def test_callable_default(self): 99 104 """Test the use of a lazy callable for ForeignKey.default""" … … 101 106 b = Bar.objects.create(b="bcd") 102 107 self.assertEqual(b.a, a) 103 108 109 def test_distinct_choice_limit(self): 110 """Doesn't make sense to offer the same ForeignKey multiple times in a form""" 111 a = Foo.objects.create(a='a', d=Decimal("-1")) 112 b = Foo.objects.create(a='b', d=Decimal("1")) 113 Bar.objects.create(b='ah', a=a) 114 Bar.objects.create(b='aha', a=a) 115 Bar.objects.create(b='bla', a=b) 116 form = BazForm() 117 fk_field = str(form['foo']) 118 self.assertEqual(len(re.findall(r'value="%s"' % b.pk, fk_field)), 0) 119 self.assertEqual(len(re.findall(r'value="%s"' % a.pk, fk_field)), 1) 120 121 def test_distinct_choice_limit_save(self): 122 """Doesn't make sense to offer the same ForeignKey multiple times in a form""" 123 a = Foo.objects.create(a='a', d=Decimal("-1")) 124 b = Foo.objects.create(a='b', d=Decimal("1")) 125 Bar.objects.create(b='ah', a=a) 126 Bar.objects.create(b='aha', a=a) 127 Bar.objects.create(b='bla', a=b) 128 form = BazForm({'foo': a.pk, 'a': 'a'}) 129 self.assertTrue(form.is_valid()) 130 obj = form.save() 131 self.assertEqual(obj.foo.pk, a.pk) 132 104 133 class DateTimeFieldTests(unittest.TestCase): 105 134 def test_datetimefield_to_python_usecs(self): 106 135 """DateTimeField.to_python should support usecs"""