Skip to content

Commit e3bd4b9

Browse files
adrienbrunettomchristie
authored andcommitted
Fix #1811: take limit_choices_to into account with FK (#6371)
* Fix issue1811: take limit_choices_to into account with FK * Issue 1811: Add tests to illustrate issue * Filter queryset only if limit_choices_to exists * Move test_relations_with_limited_querysets file within test_relations_pk * move limit_choices_to logic from relations.py to utils/field_mapping.py * move limit_choices_to above other check to avoid conflicts
1 parent 9c408b2 commit e3bd4b9

File tree

3 files changed

+33
-4
lines changed

3 files changed

+33
-4
lines changed

rest_framework/utils/field_mapping.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -249,6 +249,10 @@ def get_relation_kwargs(field_name, relation_info):
249249
if to_field:
250250
kwargs['to_field'] = to_field
251251

252+
limit_choices_to = model_field and model_field.get_limit_choices_to()
253+
if limit_choices_to:
254+
kwargs['queryset'] = kwargs['queryset'].filter(**limit_choices_to)
255+
252256
if has_through_model:
253257
kwargs['read_only'] = True
254258
kwargs.pop('queryset', None)

tests/models.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,13 @@ class ForeignKeySource(RESTFrameworkModel):
5252
on_delete=models.CASCADE)
5353

5454

55+
class ForeignKeySourceWithLimitedChoices(RESTFrameworkModel):
56+
target = models.ForeignKey(ForeignKeyTarget, help_text='Target',
57+
verbose_name='Target',
58+
limit_choices_to={"name__startswith": "limited-"},
59+
on_delete=models.CASCADE)
60+
61+
5562
# Nullable ForeignKey
5663
class NullableForeignKeySource(RESTFrameworkModel):
5764
name = models.CharField(max_length=100)

tests/test_relations_pk.py

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,10 @@
55

66
from rest_framework import serializers
77
from tests.models import (
8-
ForeignKeySource, ForeignKeyTarget, ManyToManySource, ManyToManyTarget,
9-
NullableForeignKeySource, NullableOneToOneSource,
10-
NullableUUIDForeignKeySource, OneToOnePKSource, OneToOneTarget,
11-
UUIDForeignKeyTarget
8+
ForeignKeySource, ForeignKeySourceWithLimitedChoices, ForeignKeyTarget,
9+
ManyToManySource, ManyToManyTarget, NullableForeignKeySource,
10+
NullableOneToOneSource, NullableUUIDForeignKeySource, OneToOnePKSource,
11+
OneToOneTarget, UUIDForeignKeyTarget
1212
)
1313

1414

@@ -38,6 +38,12 @@ class Meta:
3838
fields = ('id', 'name', 'target')
3939

4040

41+
class ForeignKeySourceWithLimitedChoicesSerializer(serializers.ModelSerializer):
42+
class Meta:
43+
model = ForeignKeySourceWithLimitedChoices
44+
fields = ("id", "target")
45+
46+
4147
# Nullable ForeignKey
4248
class NullableForeignKeySourceSerializer(serializers.ModelSerializer):
4349
class Meta:
@@ -360,6 +366,18 @@ class Meta(ForeignKeySourceSerializer.Meta):
360366
serializer.is_valid(raise_exception=True)
361367
assert 'target' not in serializer.validated_data
362368

369+
def test_queryset_size_without_limited_choices(self):
370+
limited_target = ForeignKeyTarget(name="limited-target")
371+
limited_target.save()
372+
queryset = ForeignKeySourceSerializer().fields["target"].get_queryset()
373+
assert len(queryset) == 3
374+
375+
def test_queryset_size_with_limited_choices(self):
376+
limited_target = ForeignKeyTarget(name="limited-target")
377+
limited_target.save()
378+
queryset = ForeignKeySourceWithLimitedChoicesSerializer().fields["target"].get_queryset()
379+
assert len(queryset) == 1
380+
363381

364382
class PKNullableForeignKeyTests(TestCase):
365383
def setUp(self):

0 commit comments

Comments
 (0)