Skip to content

Commit f03b141

Browse files
authored
Merge pull request #899 from tfranzel/fix_slugrelated
utilize queryset for SlugRelatedField #897
2 parents c0509c6 + 1957599 commit f03b141

File tree

5 files changed

+20
-8
lines changed

5 files changed

+20
-8
lines changed

drf_spectacular/openapi.py

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -666,8 +666,13 @@ def _map_serializer_field(self, field, direction, bypass_extensions=False):
666666
# read_only fields do not have a Manager by design. go around and get field
667667
# from parent. also avoid calling Manager. __bool__ as it might be customized
668668
# to hit the database.
669-
if getattr(field, 'queryset', None) is not None and not is_slug:
670-
model_field = field.queryset.model._meta.pk
669+
if getattr(field, 'queryset', None) is not None:
670+
if is_slug:
671+
model = field.queryset.model
672+
source = [field.slug_field]
673+
model_field = follow_field_source(model, source, default=models.TextField())
674+
else:
675+
model_field = field.queryset.model._meta.pk
671676
else:
672677
if isinstance(field.parent, serializers.ManyRelatedField):
673678
model = field.parent.parent.Meta.model
@@ -689,10 +694,8 @@ def _map_serializer_field(self, field, direction, bypass_extensions=False):
689694

690695
# estimates the relating model field and jumps to its target model PK field.
691696
# also differentiate as source can be direct (pk) or relation field (model).
692-
model_field = follow_field_source(model, source)
693-
if callable(model_field):
694-
# follow_field_source bailed with a warning. be graceful and default to str.
695-
model_field = models.TextField()
697+
# be graceful and default to string.
698+
model_field = follow_field_source(model, source, default=models.TextField())
696699

697700
# primary keys are usually non-editable (readOnly=True) and map_model_field correctly
698701
# signals that attribute. however this does not apply in the context of relations.

drf_spectacular/plumbing.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -572,7 +572,7 @@ def _follow_return_type(a_callable):
572572
return target_type
573573

574574

575-
def follow_field_source(model, path, emit_warnings=True):
575+
def follow_field_source(model, path, default=None, emit_warnings=True):
576576
"""
577577
a model traversal chain "foreignkey.foreignkey.value" can either end with an actual model field
578578
instance "value" or a model property function named "value". differentiate the cases.
@@ -594,7 +594,7 @@ def follow_field_source(model, path, emit_warnings=True):
594594

595595
def dummy_property(obj) -> str: # type: ignore
596596
pass # pragma: no cover
597-
return dummy_property
597+
return default or dummy_property
598598

599599

600600
def follow_model_field_lookup(model, lookup):

tests/test_fields.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,9 @@ def get_field_method_object(self, obj) -> dict:
194194
field_related_slug = serializers.SlugRelatedField(
195195
read_only=True, source='field_foreign', slug_field='url',
196196
) # type: ignore
197+
field_related_slug_queryset = serializers.SlugRelatedField(
198+
source='field_foreign', slug_field='url', queryset=Aux.objects.all()
199+
) # type: ignore
197200
field_related_slug_many = serializers.SlugRelatedField(
198201
many=True, read_only=True, source='field_m2m', slug_field='url',
199202
) # type: ignore

tests/test_fields.yml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,10 @@ components:
129129
format: uri
130130
description: URL identifier for Aux
131131
readOnly: true
132+
field_related_slug_queryset:
133+
type: string
134+
format: uri
135+
description: URL identifier for Aux
132136
field_related_slug_many:
133137
type: array
134138
items:
@@ -341,6 +345,7 @@ components:
341345
- field_related_hyperlink
342346
- field_related_slug
343347
- field_related_slug_many
348+
- field_related_slug_queryset
344349
- field_related_string
345350
- field_slug
346351
- field_smallint

tests/test_fields_response.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
}
2020
],
2121
"field_related_slug": "https://xkcd.com",
22+
"field_related_slug_queryset": "https://xkcd.com",
2223
"field_related_slug_many": [
2324
"https://xkcd.com"
2425
],

0 commit comments

Comments
 (0)