Django REST框架 - 多个查找字段?

Posted

技术标签:

【中文标题】Django REST框架 - 多个查找字段?【英文标题】:Django REST framework - multiple lookup fields? 【发布时间】:2018-01-15 08:20:14 【问题描述】:

我有一个或多或少看起来像这样的模型:

class Starship(models.Model):
    id = models.UUIDField(default=uuid4, editable=False, primary_key=True)
    name = models.CharField(max_length=128)
    hull_no = models.CharField(max_length=12, unique=True)

我有一个不起眼的StarshipDetailSerialiserStarshipListSerialiser(我想最终显示不同的字段,但现在它们是相同的),它们都是serializers.ModelSerializer 的子类。它有一个 HyperlinkedIdentityField 引用回 (UU)ID,使用与原始 HyperlinkedIdentityField 非常相似但能够规范化和处理 UUID 的自制类:

class StarshipListSerializer(HyperlinkedModelSerializer):
uri = UUIDHyperlinkedIdentityField(view_name='starships:starship-detail', format='html')

    class Meta:
         model = Starship
         fields = ('uri', 'name', 'hull_no')

最后,有一个列表视图(ListAPIView)和一个详细视图,如下所示:

class StarshipDetail(APIView):
    """
    Retrieves a single starship by UUID primary key.
    """

    def get_object(self, pk):
        try:
            return Starship.objects.get(pk=pk)
        except Starship.DoesNotExist:
            raise Http404

    def get(self, request, pk, format=None):
        vessel = self.get_object(pk)
        serializer = StarshipDetailSerialiser(vessel, context='request': request)
        return Response(serializer.data)

详细视图的 URL 架构当前正在根据 UUID 调用视图:

...
url(r'vessels/id/(?P<pk>[0-9A-Fa-f\-]+)/$', StarshipDetail.as_view(), name='starship-detail'),
...

我现在希望用户不仅可以通过 UUID 还可以通过船体编号导航和找到同一艘船,例如vessels/id/abcde1345...and so on.../vessels/hull/H1025/ 将能够解析到同一个实体。理想情况下,无论是从 ID 还是船体编号到达详细视图,在列表中也略有改动的序列化程序应该能够将 ID 超链接到基于 ID 的链接和船体超链接到基于船体编号的链接 (vessels/hull/H1025/)。这是可能吗?如果是这样,我会怎么做?

【问题讨论】:

【参考方案1】:

1。添加新路线

# in urls.py

urlpatterns = [
    ...,
    url(r'vessels/id/(?P<pk>[0-9A-Fa-f\-]+)/$', StarshipDetail.as_view(), name='starship-detail-pk'),
    url(r'vessels/hull/(?P<hull_no>[0-9A-Za-z]+)/$', StarshipDetail.as_view(), name='starship-detail-hull'),
]

根据需要调整 hull_no 的正则表达式。请注意,我为每条路线指定了不同的名称,starship-detail-pkstarship-detail-hull

2。在序列化器中添加 hull 字段

# in serializers.py

class StarshipListSerialiser(HyperlinkedModelSerializer):
    uri = UUIDHyperlinkedIdentityField(view_name='starship-detail-pk', format='html')
    hull_no = UUIDHyperlinkedIdentityField(view_name='starship-detail-hull', format='html', lookup_field='hull_no')

    class Meta:
         model = Starship
         fields = ('uri', 'name', 'hull_no')

3。修改视图,使其也可以基于 hull 解析对象

# in serializers.py

from django.shortcuts import get_object_or_404

from rest_framework.views import APIView, Response

from starwars.serializers import StarshipDetailSerialiser
from starwars.models import Starship


class StarshipDetail(APIView):

    def get(self, request, pk=None, hull_no=None, format=None):
        lookup = 'hull_no': hull_no if pk is None else 'pk': pk
        vessel = get_object_or_404(Starship, **lookup)
        serializer = StarshipDetailSerialiser(vessel, context='request': request)
        return Response(serializer.data)

这应该足以让您使用详细视图:

最后一点,您应该知道,同一资源在两个不同的 URL 上可用不是 RESTful 的,就像这样。也许,作为替代设计决策,您可能想考虑为资源定义“一条真正的路线”,并添加从其他定位器到规范 URL 的“便利”重定向。

【讨论】:

以上是关于Django REST框架 - 多个查找字段?的主要内容,如果未能解决你的问题,请参考以下文章

无法使用 Django REST 框架从多个选择元素中发布 JSON 数据

通过django rest框架序列化器添加外键数据

django rest框架错误需要一个字段

如何在 django rest 框架中定义列表字段?

Django REST 框架:使用相关字段创建/更新对象

django rest框架中的只写,只读字段