Skip to content

Commit 1f693c3

Browse files
Fix dotted source ordering (#5533)
* replaced '.' for '__' in dotted ordering sources * Add test for non-dotted source.
1 parent 7261ae6 commit 1f693c3

File tree

2 files changed

+45
-1
lines changed

2 files changed

+45
-1
lines changed

rest_framework/filters.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -199,7 +199,7 @@ def get_default_valid_fields(self, queryset, view, context={}):
199199
raise ImproperlyConfigured(msg % self.__class__.__name__)
200200

201201
return [
202-
(field.source or field_name, field.label)
202+
(field.source.replace('.', '__') or field_name, field.label)
203203
for field_name, field in serializer_class(context=context).fields.items()
204204
if not getattr(field, 'write_only', False) and not field.source == '*'
205205
]

tests/test_filters.py

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -312,6 +312,7 @@ class OrderingFilterModel(models.Model):
312312

313313
class OrderingFilterRelatedModel(models.Model):
314314
related_object = models.ForeignKey(OrderingFilterModel, related_name="relateds", on_delete=models.CASCADE)
315+
index = models.SmallIntegerField(help_text="A non-related field to test with", default=0)
315316

316317

317318
class OrderingFilterSerializer(serializers.ModelSerializer):
@@ -320,6 +321,19 @@ class Meta:
320321
fields = '__all__'
321322

322323

324+
class OrderingDottedRelatedSerializer(serializers.ModelSerializer):
325+
related_text = serializers.CharField(source='related_object.text')
326+
related_title = serializers.CharField(source='related_object.title')
327+
328+
class Meta:
329+
model = OrderingFilterRelatedModel
330+
fields = (
331+
'related_text',
332+
'related_title',
333+
'index',
334+
)
335+
336+
323337
class DjangoFilterOrderingModel(models.Model):
324338
date = models.DateField()
325339
text = models.CharField(max_length=10)
@@ -484,6 +498,36 @@ class OrderingListView(generics.ListAPIView):
484498
{'id': 2, 'title': 'yxw', 'text': 'bcd'},
485499
]
486500

501+
def test_ordering_by_dotted_source(self):
502+
503+
for index, obj in enumerate(OrderingFilterModel.objects.all()):
504+
OrderingFilterRelatedModel.objects.create(
505+
related_object=obj,
506+
index=index
507+
)
508+
509+
class OrderingListView(generics.ListAPIView):
510+
serializer_class = OrderingDottedRelatedSerializer
511+
filter_backends = (filters.OrderingFilter,)
512+
queryset = OrderingFilterRelatedModel.objects.all()
513+
514+
view = OrderingListView.as_view()
515+
request = factory.get('/', {'ordering': 'related_object__text'})
516+
response = view(request)
517+
assert response.data == [
518+
{'related_title': 'zyx', 'related_text': 'abc', 'index': 0},
519+
{'related_title': 'yxw', 'related_text': 'bcd', 'index': 1},
520+
{'related_title': 'xwv', 'related_text': 'cde', 'index': 2},
521+
]
522+
523+
request = factory.get('/', {'ordering': '-index'})
524+
response = view(request)
525+
assert response.data == [
526+
{'related_title': 'xwv', 'related_text': 'cde', 'index': 2},
527+
{'related_title': 'yxw', 'related_text': 'bcd', 'index': 1},
528+
{'related_title': 'zyx', 'related_text': 'abc', 'index': 0},
529+
]
530+
487531
def test_ordering_with_nonstandard_ordering_param(self):
488532
with override_settings(REST_FRAMEWORK={'ORDERING_PARAM': 'order'}):
489533
reload_module(filters)

0 commit comments

Comments
 (0)