2013-06-27 34 views
18

Tôi không thể tìm thấy bất kỳ thông tin nào về cách đạt được điều này trong hướng dẫn tại trang web khung REST Django và tôi chưa quản lý để tìm thấy nó trong tài liệu, mặc dù tôi chắc chắn rằng nó có một nơi nào đó.Cách triển khai phân cấp tài nguyên (ví dụ:/cha mẹ/<id>/trẻ em) trong Khung REST Django

Tôi muốn issues là nguồn phụ huynh và pages để trở nên con cái để /issues/1/pages trả về tất cả các trang web có issue_id của 1.

Có cách nào tốt để đạt được điều này sử dụng các khung nhìn dựa lớp chung chung?

Đây là những gì tôi có cho đến nay.

restAPI/urls.py:

from django.conf.urls import patterns, url 
from rest_framework.urlpatterns import format_suffix_patterns 
from restAPI import views 

urlpatterns = patterns('', 
    url(r'^issues/$', views.IssueList.as_view()), 
    url(r'^issues/(?P<pk>[0-9]+)/$', views.IssueDetail.as_view()), 


    url(r'^issues/(?P<issue_id>[0-9]+)/pages/$', views.PageList.as_view()),  
    url(r'^pages/(?P<pk>[0-9]+)/$', views.PageDetail.as_view()), 
) 

urlpatterns = format_suffix_patterns(urlpatterns) 

restAPI/models.py:

from django.db import models 

class Issue(models.Model): 
    created = models.DateTimeField(auto_now_add=True) 
    revision = models.IntegerField(default = 1) 
    issue_date = models.DateTimeField(auto_now_add=True) 
    issue_image_url = models.CharField(max_length=100) 

class Page(models.Model): 
    created = models.DateTimeField(auto_now_add=True) 
    page_number = models.IntegerField() 
    standard_page_url = models.CharField(max_length=100, default='') 
    large_page_url = models.CharField(max_length=100, default='') 
    thumbnail_url = models.CharField(max_length=100, default='') 

    issue = models.ForeignKey(Issue, related_name="pages") 

    class Meta: 
     ordering = ('page_number',) 

restAPI/serializers.py:

from rest_framework import serializers 
from restAPI.models import Page, Issue 

class IssueSerializer(serializers.ModelSerializer): 
    class Meta: 
     model = Issue 
     fields = ('id', 'created', 'revision', 'issue_date', 'issue_image_url') 

class PageSerializer(serializers.ModelSerializer):  
    class Meta: 
     model = Page 
     fields = ('id', 'created', 'page_number', 'standard_page_url', 'large_page_url', 'thumbnail_url') 

restAPI/views.py:

from restAPI.models import Page, Issue 
from restAPI.serializers import PageSerializer, IssueSerializer 
from rest_framework import mixins 
from rest_framework import generics 

class IssueList(mixins.ListModelMixin, 
        mixins.CreateModelMixin, 
        generics.GenericAPIView): 
    queryset = Issue.objects.all() 
    serializer_class = IssueSerializer 

    def get(self, request, *args, **kwargs): 
     return self.list(request, *args, **kwargs) 

    def post(self, request, *args, **kwargs): 
     return self.create(request, *args, **kwargs) 

class IssueDetail(mixins.RetrieveModelMixin, 
        mixins.UpdateModelMixin, 
        mixins.DestroyModelMixin, 
        generics.GenericAPIView): 
    queryset = Issue.objects.all() 
    serializer_class = IssueSerializer 

    def get(self, request, *args, **kwargs): 
     return self.retrieve(request, *args, **kwargs) 

    def put(self, request, *args, **kwargs): 
     return self.update(request, *args, **kwargs) 

    def delete(self, request, *args, **kwargs): 
     return self.destroy(request, *args, **kwargs) 

class PageList(mixins.ListModelMixin, 
        mixins.CreateModelMixin, 
        generics.GenericAPIView): 
    queryset = Page.objects.all() 
    serializer_class = PageSerializer 

    def get(self, request, *args, **kwargs): 
     print kwargs 
     return self.list(request, *args, **kwargs) 

    def post(self, request, *args, **kwargs): 
     return self.create(request, *args, **kwargs) 

class PageDetail(mixins.RetrieveModelMixin, 
        mixins.UpdateModelMixin, 
        mixins.DestroyModelMixin, 
        generics.GenericAPIView): 
    queryset = Page.objects.all() 
    serializer_class = PageSerializer 

    def get(self, request, *args, **kwargs): 
     return self.retrieve(request, *args, **kwargs) 

    def put(self, request, *args, **kwargs): 
     return self.update(request, *args, **kwargs) 

    def delete(self, request, *args, **kwargs): 
     return self.destroy(request, *args, **kwargs) 

Làm thế nào tôi có thể thực hiện điều này loại mối quan hệ giữa issuespages?

+0

Tôi đã thêm 'def get_queryset (self): issue_id = self.kwargs ['issue_id'] trả về Page.objects.filter (issue_id = issue_id)' thành 'PageList' và bây giờ GET làm việc cho' issue//pages' . Bây giờ tôi chỉ cần tìm ra cách để đăng bài. –

+1

Tôi đã thêm 'def pre_save (self, obj): obj.issue_id = self.kwargs ['issue_id']' to 'PageList' và bây giờ POST cũng hoạt động. Truy vấn các trang từ một vấn đề không tồn tại sẽ trả lại kết quả rỗng hơn là 404 không tìm thấy. Nếu có ai biết cách tốt hơn để làm điều này tôi rất thích nghe về nó. –

Trả lời

9

Dưới đây là một cách mà tôi đã làm điều này:

views.py

from models import Customer, Order 
from serializers import CustomerSerializer, OrderSerializer 

from rest_framework import generics 

class CustomerList(generics.ListCreateAPIView): 
    queryset = Customer.objects.all() 
    serializer_class = CustomerSerializer 

class CustomerDetail(generics.RetrieveUpdateDestroyAPIView) 
    queryset = Customer.objects.all() 
    serializer_class = CustomerSerializer 

class OrdersByCustomer(generics.ListCreateAPIView): 
    queryset = Order.objects.all() 
    serializer_class = OrderSerializer 

    def get_queryset(self): 
     customer_pk = self.kwargs['customer_pk'] 
     return self.queryset.filter(customer__pk=customer_pk) 

    def pre_save(self, obj): 
     obj.customer_id = self.kwargs['customer_pk'] 

class OrderDetail(generics.RetrieveUpdateDestroyAPIView): 
    queryset = Order.objects.all() 
    serializer_class = OrderSerializer 

serializers.py

from models import Customer, Order 

from rest_framework import serializers 
from rest_framework.reverse import reverse 

class OrderSerializer(serializers.HyperlinkedModelSerializer) 

    class Meta: 
     model = Order 

class CustomerSerializer(serializers.HyperlinkedModelSerializer) 

    orders = serializers.SerializerMethodField('get_customer_orders') 

    def get_customer_orders(self, obj): 
     return reverse('ordersbycustomer-list', 
       args=[obj.pk], request=self.context['request']) 

    class Meta: 
     model = Customer 

url.py

from django.conf.urls import patterns, include, url 
from views import OrdersByCustomer, CustomerDetail, CustomerList 

urlpatterns = patterns("", 
    url(r'^customers/(?P<customer_pk>.+)/orders/$', OrdersByCustomer.as_view(), name='ordersbycustomer-list'), 
    url(r'^customers/(?P<pk>.+)/$', CustomerDetail.as_view(), name='customer-detail'), 
    url(r'^customers/$', CustomerList.as_view(), name='customer-list'), 
    ) 

Có nhiều mã có liên quan hơn với Viewsets/Router nhưng điều này cung cấp cho bạn kiểm soát nhiều hơn về những gì đang xảy ra.

Ở đây tôi đã chọn chỉ hiển thị đơn đặt hàng dưới dạng con của khách hàng. Vì chúng được tách ra, bạn có thể sử dụng các lớp serializer khác nhau cho danh sách so với chi tiết.

+0

Nếu bạn thêm pre_save vào OrdersByCustomer tương tự như cách tôi đã viết nó trong một câu trả lời cho câu hỏi ban đầu của tôi, tôi sẽ làm cho câu trả lời được chấp nhận này. –

+0

xin lỗi đã mất quá nhiều thời gian! –

8

Dưới đây là cách tôi đã đạt được điều này bằng cách sử dụng mới ViewSetsRouters từ phiên bản Rest-Khung 2.3:

views.py:

from rest_framework import viewsets 
from rest_framework.response import Response 
from models import Order, OrderLine 
from serializers import OrderSerializer, OrderLineSerializer 

class OrderViewSet(viewsets.ModelViewSet): 
    queryset = Order.objects.all() 
    serializer_class = OrderSerializer 

    @link() 
    def lines(self, request, pk=None): 
     queryset = OrderLine.objects.filter(order__pk=pk) 
     serializer = OrderLineSerializer(queryset, 
          context={'request':request}, 
          many=True) 
     return Response(serializer.data) 

class OrderLineViewSet(viewsets.ModelViewSet): 
    queryset = OrderLine.objects.all() 
    serializer_class = OrderLineSerializer 

serializers.py

from rest_framework import serializers 
from models import Order, OrderLine 

class OrderSerializer(serializers.HyperlinkedModelSerializer): 
    lines = serializers.HyperlinkedIdentityField(view_name='order-lines') 

    class Meta: 
     model = Order 


class OrderLineSerializer(serializers.HyperlinkedModelSerializer): 

    class Meta: 
     model = OrderLine 

url py

from views import OrderViewSet, OrderLineViewSet 
from rest_framework.routers import DefaultRouter 

router = DefaultRouter() 
router.register(r'order', OrderViewSet) 
router.register(r'orderline', OrderLineViewSet) 
urlpatterns = router.urls 

Now 'để/id/dòng' sẽ trả về một danh sách các dòng theo thứ tự tuần tự mà có một mối quan hệ với thứ tự xác định bởi id đó.

Bất kỳ phương thức nào trên ViewSet được trang trí với @link hoặc @action sẽ được cung cấp URL khi bạn đăng ký chế độ xem với bộ định tuyến.

+0

Cảm ơn ví dụ rõ ràng. Tuy nhiên, tôi cũng muốn POST cho các nguồn tài nguyên trẻ em dưới cha mẹ//trẻ em và tôi muốn trẻ em có thể truy cập theo cha mẹ của họ chỉ, vì vậy trẻ em/thậm chí không nên là một con đường hợp lệ. Tôi đoán đăng có lẽ có thể được sửa bằng cách sử dụng một phương pháp được trang trí với @action, nhưng sau đó nó không có vẻ giống như một lợi thế nhiều hơn các lớp học dựa trên quan điểm. Tôi thực sự thích ý tưởng của router mặc dù. –

+0

Sau khi khám phá thêm điều này, tôi nghĩ rằng việc sử dụng ViewSets và Router thuận tiện và dễ dàng, nhưng vẫn yêu cầu nhiều tùy chỉnh để làm cho chúng hoạt động giống như mối quan hệ cha mẹ con. Tôi sẽ đăng một cách rõ ràng hơn rằng tôi đã làm điều này trong một câu trả lời khác. –

+0

Khi sử dụng kỹ thuật tài nguyên phân cấp này với ViewSet và @link, bạn có tìm cách thay đổi chuỗi tài liệu được hiển thị ở đầu API có thể duyệt khi bạn theo dõi @link không? Vì nó, nó xuất hiện để hiển thị sự giúp đỡ cho phụ huynh (thứ tự) chứ không phải là con (OrderLine). – Gary

1

tôi thêm def get_queryset (tự): ISSUE_ID = self.kwargs [ 'ISSUE_ID'] trở Page.objects.filter (ISSUE_ID = ISSUE_ID) để PageList và bây giờ GET công trình cho vấn đề/ /trang. Bây giờ tôi chỉ cần tìm ra cách để đăng bài.

Tôi đã thêm def pre_save (self, obj): obj.issue_id = self.kwargs ['issue_id'] vào PageList và bây giờ POST cũng hoạt động. Truy vấn các trang từ một vấn đề không tồn tại sẽ trả lại kết quả rỗng hơn là 404 không tìm thấy. Nếu có ai biết cách tốt hơn để làm điều này tôi rất thích nghe về nó.

Nếu phương thức get_queryset (self) trả về danh sách trống thay vì 404 NOT FOUND, tôi khuyên bạn nên sử dụng hàm phím tắt get_list_or_404 từ django. Phương pháp này có thể trông như thế này:

from django.shortcuts import get_list_or_404 

def get_queryset(self): 
    filter = {} 
    filter['issue_id'] = self.kwargs['issue_id'] 
    return get_list_or_404(self.queryset, **filter) 

Tôi biết đây là một bài cũ, nhưng có lẽ điều này có thể giúp những người khác có cùng một hoặc một số vấn đề tương tự.

Các vấn đề liên quan