2017-08-07 100 views
9

我有一个模型,或多或少看起来像这样:Django REST框架 - 多个查找字段?

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/)。这是可能吗?如果是的话,我会怎么做呢?

回答

9

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。也许,作为另一个设计决策,您可能会考虑为资源定义“一条真正的路线”,并将其他定位器的“便捷”重定向添加到规范网址。