[英]Django Rest Ordering custom
我正在使用 django rest 框架,我想使用自定義方法進行訂購。
所以,當我調用這個 url 例如: http://127.0.0.1:8000/api/sets/?ordering=partMissing
可以調用自定義方法,因為我想用代碼段缺少的零件數進行訂購。 我計算了多對多字段中部分的總和。
我有非常簡單的 POC,它應該允許您實施更復雜的解決方案。
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
:
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
models.py
和serializers.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
:
from rest_framework import serializers
from ordering_test.models import Test
class TestSerializer(serializers.ModelSerializer):
class Meta:
model = Test
fields = ('test', 'test1')
快樂編碼!
我認為 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
然后您可以輕松地按您想要的任何字段進行排序: example.com/api/mymodel/?order_by=partMissing
。
在我的例子,我用了一個固定的模式場,但你可以改變你的訂購方式filter_order_by
的方法CustomOrderingFilter
。 只需將其更改為您想要的邏輯,但請確保使用.filter(=queryset.values_list('id', flat=True))
以確保正在使用設置的其他過濾器。
您可以使用FilterSet
進行注釋,然后使用OrderingFilter
進行相應的排序。 作為一個優勢,您可以使用OrderingField
語法,並且仍然可以同時按多個字段進行排序。
/api/?annotate_related={id}&order=subscribed
/api/?annotate_related={id}&order=-subscribed
/api/?annotate_related={id}&order=-subscribed,-modified
過濾器集:
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))
視圖集:
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.