[英]Django Rest Ordering custom
I'm using django rest framework and I would like to order with a custom method.我正在使用 django rest 框架,我想使用自定义方法进行订购。
So, when I call this url for example: http://127.0.0.1:8000/api/sets/?ordering=partMissing所以,当我调用这个 url 例如: http://127.0.0.1:8000/api/sets/?ordering=partMissing
It's possible to call a custom method because I would like to order with the number of part missing by snippet.可以调用自定义方法,因为我想用代码段缺少的零件数进行订购。 I made count the sum of number of part in the many to many field.
我计算了多对多字段中部分的总和。
I have very simple POC, that should allow you to implement more sophisticated solution.我有非常简单的 POC,它应该允许您实施更复杂的解决方案。
views.py
: views.py
:
from rest_framework import viewsets
from ordering_test.models import Test
from ordering_test.ordering import MyCustomOrdering
from ordering_test.serializers import TestSerializer
class TestViewSet(viewsets.ModelViewSet):
queryset = Test.objects.all()
serializer_class = TestSerializer
filter_backends = (MyCustomOrdering,)
ordering.py
: ordering.py
:
from rest_framework.filters import OrderingFilter
class MyCustomOrdering(OrderingFilter):
allowed_custom_filters = ['testMethod']
def get_ordering(self, request, queryset, view):
"""
Ordering is set by a comma delimited ?ordering=... query parameter.
The `ordering` query parameter can be overridden by setting
the `ordering_param` value on the OrderingFilter or by
specifying an `ORDERING_PARAM` value in the API settings.
"""
params = request.query_params.get(self.ordering_param)
if params:
fields = [param.strip() for param in params.split(',')]
# care with that - this will alow only custom ordering!
ordering = [f for f in fields if f in self.allowed_custom_filters]
if ordering:
return ordering
# No ordering was included, or all the ordering fields were invalid
return self.get_default_ordering(view)
def filter_queryset(self, request, queryset, view):
ordering = self.get_ordering(request, queryset, view)
if ordering:
# implement a custom ordering here
ordering = ['-id']
if ordering:
return queryset.order_by(*ordering)
return queryset
The models.py
and serializers.py
are straightforward, but I will still include them here: models.py
和serializers.py
很简单,但我仍将在此处包含它们:
models.py
: models.py
:
from django.db import models
class Test(models.Model):
test = models.CharField(max_length=120)
test1 = models.CharField(max_length=120)
serializers.py
: serializers.py
:
from rest_framework import serializers
from ordering_test.models import Test
class TestSerializer(serializers.ModelSerializer):
class Meta:
model = Test
fields = ('test', 'test1')
Happy coding!快乐编码!
I think a much easier approach to opalczynski's solution would be to introduce a new field for custom ordering:我认为 opalczynski 解决方案的一个更简单的方法是为自定义排序引入一个新字段:
from django import forms
import django_filters
from rest_framework import serializers
from .models import MyModel
class MyModelSerializer(serializers.ModelSerializer):
class Meta:
model = MyModel
fields = ('field1',)
class CustomOrderingFilter(django_filters.FilterSet):
order_by = django_filters.BooleanFilter(
widget=forms.HiddenInput(),
method='filter_order_by',
)
class Meta:
model = MyModel
fields = [
'order_by'
]
def filter_order_by(self, queryset, name, value):
if value:
return self.Meta.model.objects.filter(
id__in=queryset.values_list('id', flat=True)
).order_by(value)
return queryset
class TestViewSet(viewsets.ModelViewSet):
queryset = MyModel.objects.all()
serializer_class = MyModelSerializer
filter_class = CustomOrderingFilter
Then you can easily order by any field you want like this: example.com/api/mymodel/?order_by=partMissing
.然后您可以轻松地按您想要的任何字段进行排序:
example.com/api/mymodel/?order_by=partMissing
。
In my example, I used a fixed model field, but you can change the way you order in the filter_order_by
method on the CustomOrderingFilter
.在我的例子,我用了一个固定的模式场,但你可以改变你的订购方式
filter_order_by
的方法CustomOrderingFilter
。 Just change it to the logic you want, but make sure to use the .filter(=queryset.values_list('id', flat=True))
to ensure that other filters that are set, are being used.只需将其更改为您想要的逻辑,但请确保使用
.filter(=queryset.values_list('id', flat=True))
以确保正在使用设置的其他过滤器。
You can use FilterSet
to annotate and then OrderingFilter
to order accordingly.您可以使用
FilterSet
进行注释,然后使用OrderingFilter
进行相应的排序。 As an advantage you may use the OrderingField
syntax and can still order by multiple fields ad the same time.作为一个优势,您可以使用
OrderingField
语法,并且仍然可以同时按多个字段进行排序。
/api/?annotate_related={id}&order=subscribed
/api/?annotate_related={id}&order=-subscribed
/api/?annotate_related={id}&order=-subscribed,-modified
FilterSet:过滤器集:
class YourFilterSet(FilterSet):
annotate_related = filters.NumberFilter(method="_annotate_related")
class Meta:
model = Model
def _annotate_related(self, queryset, key, value, *args, **kwargs):
# eg. annotate if user belongs to a certain category
return queryset.annotate(is_subscribed=Case(When(annotate_related__id=value, then=1), output_field=IntegerField(), default=0))
ViewSet:视图集:
class YourViewSet(ModelViewSet):
queryset = Model.objects.all()
filterset_class = YourFilterSet
filter_backends = [OrderingFilter, DjangoFilterBackend]
ordering_fields = [
"is_subscribed", # order by annotated field
]
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.