简体   繁体   English

Django Rest如何在模型方法上订购

[英]Django Rest how to order on a model method

Using Django Rest Framework is it possible to order on a model method? 使用Django Rest Framework是否可以对模型方法进行order I have tried it and DRF requires it to be field. 我已经尝试过了,DRF要求它必须在现场。 So gives the error: 因此给出错误:

Cannot resolve keyword 'distance' into field. 无法将关键字“距离”解析为字段。

View class ActivityListView(ListCreateView): 查看类ActivityListView(ListCreateView):

    queryset = model_activity.objects.all()
    serializer_class = ActivityListSerializer
    filter_backends = (OrderingFilter,)
    # default ordering
    ordering = ('distance')

Serializer 序列化器

class ActivityListSerializer(serializers.ModelSerializer):

    distance = serializers.SerializerMethodField('_get_distance')

    class Meta:
        model = model_activity
        fields = ('id', 'distance')

    def _get_distance(self, obj):
        return obj.get_distance(user=self.context['request'].user)

I think the answer is no, the OrderingFilter helps you to generate the queryset(essentially SQL). 我认为答案是否定的, OrderingFilter可帮助您生成queryset(本质上是SQL)。

but ordering by a model method means the django needs to load all the records from the database to the memory, then order it in the memory. 但是通过模型方法进行排序意味着django需要将所有记录从数据库加载到内存中,然后在内存中对其进行排序。

If you have a amount of records there, your scrips will extremely slow. 如果那里有大量记录,则您的笔录将非常慢。

can you implement it in a SQL function? 可以在SQL函数中实现它吗? so that you can annotate the value by SQL function, then order by it. 这样您就可以通过SQL函数注释该值,然后对其进行排序。

from django.db import models

class ActivityListView(ListCreateView):

    queryset = model_activity.objects.all()
    serializer_class = ActivityListSerializer
    filter_backends = (OrderingFilter,)
    # default ordering
    ordering = ('distance')

    def filter_queryset(self, queryset):
        cur_latitude, cur_longitude = self.get_cur_latitude_longitude()
        # add the distance field to sql dataset result, so that we can order by it
        queryset = queryset.annotate(
            distance=models.Func(cur_latitude, cur_longitude, 'latitude', 'longitude', function='get_distance')
        )

        return super(ActivityListView, self).filter_queryset(self, queryset)

and don't forget to create the sql function, here's a example for postgresql: 并且不要忘记创建sql函数,这是postgresql的示例:

CREATE OR REPLACE FUNCTION public.geodistance(alat float8, alng float8, blat float8, blng float8)
  RETURNS float8
AS
$BODY$
  SELECT
        case when $1 is null or $2 is null or $3 is null or $4 is null
        then 9999999
        else
            asin(
            sqrt(
                sin(radians($3-$1)/2)^2 +
                sin(radians($4-$2)/2)^2 *
                cos(radians($1)) *
                cos(radians($3))
            )
            ) * 7926.3352
        end
        AS distance;
$BODY$
LANGUAGE sql IMMUTABLE;

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM