Django Rest Framework:按序列化器方法字段排序

3
我目前正在使用 Django REST framework 3.11.0 以及 Django 3.0.6。我对 DRF 还很新,不确定如何解决这个问题。我试图将排序应用于 SerializerMethodField 和枚举。我能够找到一些文档,说明我可以自己制作 OrderFilter,但我不知道该怎么做。是否有任何示例可供参考?以下是我的代码。
视图:
from rest_framework import generics
from V1.assets.models.asset_main import Asset
from V1.assets.serializers.asset_serializer import AssetSerializer
from rest_framework import filters
from django_filters.rest_framework import DjangoFilterBackend

class AssetsView(generics.ListCreateAPIView):
    queryset = Asset.objects.all()
    serializer_class = AssetSerializer
    filter_backends = [DjangoFilterBackend, filters.SearchFilter, filters.OrderingFilter]
    filter_fields = ['asset_type']
    search_fields = ['asset_type', 'asset_properties', 'current_employee_name'] 

模型
class AssetType(models.TextChoices):
    LAPTOP = 'LPT', _('Laptop')
    MOUSE = 'MSE', _('Mouse')
    MONITOR = 'MTR', _('Monitor')
    AC_ADAPTER = 'ADR', _('AC Adapter')
    TELEPHONE = 'TLP', _('Telephone')
    LOCK = 'LCK', _('Lock')
    HEADSET = 'HDS', _('Headset')

class Asset(CreatedModified):

    asset_type = models.CharField(
        max_length=3,
        choices=AssetType.choices,
        default=None
    )
    asset_properties = JSONField(default=dict)
    current_employee = models.ForeignKey(
        Employee,
        related_name='assets_current_employees', 
        related_query_name='assets_current_employee',
        default=None,
        on_delete=models.CASCADE,
        null=True,
        blank=True
    )

    class Meta:
        app_label = 'assets'
        default_related_name = 'assets'

    def __str__(self):
        return self.asset_type

序列化器

from V1.general.enums import AssetStatus, AssetType
from V1.accounts.models.employee_main import Employee

class AssetSerializer(serializers.ModelSerializer):

    current_employee_name = serializers.SerializerMethodField('get_full_name_from_employee')
    asset_type = serializers.CharField(source='get_asset_type_display')

    class Meta:
        model = Asset
        fields = (
            'id',
            'asset_type',
            'asset_properties',
            'current_employee',
            'current_employee_name'
        )
        extra_kwargs = {
            'asset_type': {
                'required': True, 
                'allow_blank': False
            }
        }

    def get_full_name_from_employee(self, asset):
        current_employee_name = asset.current_employee.first_name + ' ' + asset.current_employee.last_name
        return current_employee_name

我似乎无法按 current_employee_nameasset_type 排序。我应该怎么做才能允许对这两个字段进行排序?

1
我建议按照 ['current_employee__first_name', 'current_employee__last_name'] 进行排序。您可以在模型 Meta 上设置 ordering=[]。这样,您就可以在数据库中进行排序,避免在 Python 中进行可能会占用大量内存的操作。 - Johan Schiff
你不能在序列化器或模型中按照方法字段排序,排序是在数据库中进行的,但方法声明是在对象从数据库中检索出来后发生的。 - mahyar
总有一些方法可以解决它。在这种情况下,是一种困难的方式。但即使可能,也不是明智的选择。为了使其起作用,您需要将数据库中的所有排序值加载到Python中进行排序。如果将来有成千上万行数据,您的数据库仍然能够以有效的方式处理它们。Python不能做到。 - Johan Schiff
@JohanSchiff 但这样不会按全名排序,对吧?我能想到的最接近的解决方案是只按current_employee__first_name排序。这可能是在不创建自己的OrderFilter的情况下完成它的唯一方法。 - Vince Orio
@Vince 它将首先按照名字的顺序排序,其次是按照姓氏的顺序排序。这将产生与按全名排序相同的结果。 - Johan Schiff
1个回答

6
据我理解,您想通过当前员工姓名对“资产”进行排序。让我们以几个名字为例:
- Jean d'Artagnan (first_name: Jean, last_name: d'Artagnan) - Joe Plumber (first_name: Joe, last_name: Plumber) - Jonas Meyer (first_name: Jonas, last_name: Meyer)
如果我们先按“first_name”排序,然后按“last_name”排序,就可以实现相同的排序方式。如果有多个条目具有相同的“first_name”,则会按“last_name”进行排序。
要实现此操作,您只需在视图中指定“ordering_fields”。
class AssetsView(generics.ListCreateAPIView):
    filters = [filters.OrderingFilter]
    ordering_fields = ['current_employee.first_name', 'current_employee.last_name']

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接