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

时间:2017-08-07 22:59:09

标签: python django rest django-rest-framework

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

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非常相似的home-brew类,但具有规范化和处理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 个答案:

答案 0 :(得分:11)

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。在序列化程序

中添加外壳字段
# 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。修改视图,以便它也可以基于外壳

解析对象
# 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)

这应该足以让你进入详细视图:

drf screencap

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