2017-08-07 145 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。也許,作爲另一個設計決策,您可能會考慮爲資源定義「一條真正的路線」,並將其他定位器的「便捷」重定向添加到規範網址。