Fixed #11707 - limit_choices_to on a ForeignKey can render duplicate options in formfield

Thanks to Chris Wesseling for the report and patch.

git-svn-id: http://code.djangoproject.com/svn/django/trunk@15607 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
Luke Plant 2011-02-21 14:03:59 +00:00
parent 470d9b2602
commit 6902824ac2
3 changed files with 24 additions and 2 deletions

View File

@ -910,7 +910,7 @@ class ForeignKey(RelatedField, Field):
db = kwargs.pop('using', None) db = kwargs.pop('using', None)
defaults = { defaults = {
'form_class': forms.ModelChoiceField, 'form_class': forms.ModelChoiceField,
'queryset': self.rel.to._default_manager.using(db).complex_filter(self.rel.limit_choices_to), 'queryset': self.rel.to._default_manager.using(db).complex_filter(self.rel.limit_choices_to).distinct(),
'to_field_name': self.rel.field_name, 'to_field_name': self.rel.field_name,
} }
defaults.update(kwargs) defaults.update(kwargs)

View File

@ -29,6 +29,11 @@ class Bar(models.Model):
b = models.CharField(max_length=10) b = models.CharField(max_length=10)
a = models.ForeignKey(Foo, default=get_foo) a = models.ForeignKey(Foo, default=get_foo)
class Baz(models.Model):
a = models.CharField(max_length=5)
#Only Foos related to Bars starting with 'a'
foo = models.ForeignKey(Foo, limit_choices_to=models.Q(bar__b__startswith='a'))
class Whiz(models.Model): class Whiz(models.Model):
CHOICES = ( CHOICES = (
('Group 1', ( ('Group 1', (

View File

@ -1,5 +1,6 @@
import datetime import datetime
from decimal import Decimal from decimal import Decimal
import re
from django import test from django import test
from django import forms from django import forms
@ -8,7 +9,7 @@ from django.db import models
from django.db.models.fields.files import FieldFile from django.db.models.fields.files import FieldFile
from django.utils import unittest from django.utils import unittest
from models import Foo, Bar, Whiz, BigD, BigS, Image, BigInt, Post, NullBooleanModel, BooleanModel, Document from models import Foo, Bar, Baz, Whiz, BigD, BigS, Image, BigInt, Post, NullBooleanModel, BooleanModel, Document
# If PIL available, do these tests. # If PIL available, do these tests.
if Image: if Image:
@ -95,6 +96,10 @@ class DecimalFieldTests(test.TestCase):
# This should not crash. That counts as a win for our purposes. # This should not crash. That counts as a win for our purposes.
Foo.objects.filter(d__gte=100000000000) Foo.objects.filter(d__gte=100000000000)
class BazForm(forms.ModelForm):
class Meta:
model = Baz
class ForeignKeyTests(test.TestCase): class ForeignKeyTests(test.TestCase):
def test_callable_default(self): def test_callable_default(self):
"""Test the use of a lazy callable for ForeignKey.default""" """Test the use of a lazy callable for ForeignKey.default"""
@ -102,6 +107,18 @@ class ForeignKeyTests(test.TestCase):
b = Bar.objects.create(b="bcd") b = Bar.objects.create(b="bcd")
self.assertEqual(b.a, a) self.assertEqual(b.a, a)
def test_distinct_choice_limit(self):
"""Doesn't make sense to offer the same ForeignKey multiple times in a form"""
a = Foo.objects.create(a='a', d=Decimal("-1"))
b = Foo.objects.create(a='b', d=Decimal("1"))
bar_a = Bar.objects.create(b='ah', a=a)
bar_b = Bar.objects.create(b='aha', a=a)
bar_b = Bar.objects.create(b='bla', a=b)
form = BazForm()
fk_field = str(form['foo'])
self.assertEqual(len(re.findall(r'value="2"', fk_field)), 0)
self.assertEqual(len(re.findall(r'value="1"', fk_field)), 1)
class DateTimeFieldTests(unittest.TestCase): class DateTimeFieldTests(unittest.TestCase):
def test_datetimefield_to_python_usecs(self): def test_datetimefield_to_python_usecs(self):
"""DateTimeField.to_python should support usecs""" """DateTimeField.to_python should support usecs"""