2015-01-09 14 views
20

Tôi đang đọc về tùy chỉnh nhiều bản cập nhật here và tôi chưa tìm ra phương thức cập nhật tùy chỉnh ListSerializer. Tôi muốn cập nhật nhiều đối tượng cùng một lúc, tôi không lo lắng về việc tạo nhiều hoặc xóa tại thời điểm này.Cách đăng/đặt dữ liệu json vào ListSerializer

Từ ví dụ trong tài liệu:

# serializers.py 
class BookListSerializer(serializers.ListSerializer): 
    def update(self, instance, validated_data): 
     # custom update logic 
     ... 

class BookSerializer(serializers.Serializer): 
    ... 
    class Meta: 
     list_serializer_class = BookListSerializer 

Và ViewSet tôi

# api.py 
class BookViewSet(ModelViewSet): 
    queryset = Book.objects.all() 
    serializer_class = BookSerializer 

Và thiết lập url của tôi sử dụng DefaultRouter

# urls.py 
router = routers.DefaultRouter() 
router.register(r'Book', BookViewSet) 

urlpatterns = patterns('',      
    url(r'^api/', include(router.urls)), 
    ... 

Vì vậy, tôi đã này thiết lập bằng cách sử dụng DefaultRouter để /api/Book/ sẽ sử dụng BookSerializer.

Ý tưởng chung là nếu tôi POST/PUT/PATCH một mảng đối tượng JSON thành /api/Book/ thì trình nối tiếp sẽ chuyển sang BookListSerializer?

Tôi đã thử POST/PUT/PATCH JSON danh sách dữ liệu để /api/Book/ này trông giống như:

[ {id:1,title:thing1}, {id:2, title:thing2} ] 

nhưng nó dường như vẫn đối xử với các dữ liệu sử dụng BookSerializer thay vì BookListSerializer. Nếu tôi gửi qua POST, tôi nhận được Invalid data. Expected a dictionary, but got list. và nếu tôi gửi qua PATCH hoặc PUT thì tôi gặp lỗi Method 'PATCH' not allowed.

Câu hỏi: Tôi có phải điều chỉnh allowed_methods của DefaultRouter hoặc BookViewSet cho phép POST/PATCH/PUT của danh sách? Các chế độ xem chung có được thiết lập để hoạt động với ListSerializer không?

Tôi biết tôi có thể viết danh sách deserializer của riêng mình cho điều này, nhưng tôi đang cố gắng cập nhật các tính năng mới trong DRF 3 và có vẻ như điều này sẽ hiệu quả nhưng tôi chỉ thiếu một số quy ước hoặc một số Tùy chọn.

Trả lời

33

Khuôn khổ Django REST theo mặc định giả định rằng bạn không xử lý việc tạo, cập nhật hoặc xóa dữ liệu hàng loạt. Điều này là do 99% người không xử lý việc tạo dữ liệu hàng loạt và DRF leaves the other 1% to third-party libraries.

Trong khung công tác REST Django 2.x và 3.x, gói bên thứ ba exists for this.

Bây giờ, bạn đang cố gắng làm sáng tạo với số lượng lớn nhưng bạn đang nhận được một lại lỗi mà nói

dữ liệu không hợp lệ. Dự kiến ​​một từ điển, nhưng có danh sách

Điều này là do bạn đang gửi trong danh sách các đối tượng cần tạo, thay vì chỉ gửi một đối tượng. Bạn có thể thực hiện việc này một vài cách, nhưng cách dễ nhất là chỉ cần override get_serializer on your view đến add the many=True flag đến bộ nối tiếp khi đó là danh sách.

def get_serializer(self, *args, **kwargs): 
    if "data" in kwargs: 
     data = kwargs["data"] 

     if isinstance(data, list): 
      kwargs["many"] = True 

    return super(MyViewSet, self).get_serializer(*args, **kwargs) 

Điều này sẽ cho phép khung công tác REST Django biết tự động sử dụng ListSerializer khi tạo đối tượng hàng loạt.Bây giờ, đối với các hoạt động khác như cập nhật và xóa, bạn sẽ cần phải ghi đè lên các tuyến mặc định. Tôi sẽ giả định rằng bạn đang sử dụng routes provided by Django REST framework bulk, nhưng bạn được tự do sử dụng bất kỳ tên phương thức nào bạn muốn.

Bạn cũng sẽ cần thêm các phương thức cho số lượng lớn PUTPATCH vào chế độ xem.

from rest_framework.response import Response 

def bulk_update(self, request, *args, **kwargs): 
    partial = kwargs.pop("partial", False) 

    queryset = self.filter_queryset(self.get_queryset)) 

    serializer = self.get_serializer(instance=queryset, data=request.data, many=True) 
    serializer.is_valid(raise_exception=True) 

    self.perform_update(serializer) 

    return Response(serializer.data) 

def partial_bulk_update(self, *args, **kwargs): 
    kargs["partial"] = True 
    return super(MyView, self).bulk_update(*args, **kwargs) 

Điều này sẽ không hoạt động vì hộp này không hỗ trợ cập nhật hàng loạt theo mặc định. Điều này có nghĩa là bạn cũng have to implement your own bulk updates. Mã hiện tại sẽ xử lý các bản cập nhật hàng loạt như thể bạn đang cố gắng cập nhật toàn bộ danh sách, đó là cách gói cập nhật hàng loạt cũ đã hoạt động trước đó.

Trong khi bạn không yêu cầu xóa hàng loạt, điều đó sẽ không đặc biệt khó thực hiện.

def bulk_delete(self, request, *args, **kwargs): 
    queryset = self.filter_queryset(self.get_queryset()) 
    self.perform_delete(queryset) 
    return Response(status=204) 

Điều này có cùng tác dụng xóa tất cả các đối tượng, giống như plugin hàng loạt cũ.

Không có mã nào trong số này được kiểm tra. Nếu nó không hoạt động, hãy xem nó như một ví dụ chi tiết.

+0

Cảm ơn. Sửa lỗi đó. Bây giờ tôi đang gửi một danh sách tới '/ api/Book /'. Nếu tôi gửi qua POST tôi nhận được 'Dữ liệu không hợp lệ. Dự kiến ​​một từ điển, nhưng có danh sách.' và nếu tôi gửi qua PATCH hoặc PUT thì tôi nhận được một 'Phương thức' PATCH 'không được phép.'. Tôi đang sử dụng 'DefaultRouter' và' ModelViewSet' nếu điều đó có ích. – petroleyum

+0

Tôi đã cập nhật câu trả lời để giải quyết câu hỏi của bạn ** chi tiết **. Hy vọng nó bao gồm nhiều phần cho câu hỏi của bạn. Với bất kỳ may mắn nào, gói bên thứ ba sẽ được cập nhật để hỗ trợ 3.0 trong tương lai gần. –

+0

Tuyệt vời, cảm ơn bạn. Tôi đoán câu hỏi của tôi có thể đã được đun sôi xuống "Có vẻ như DRF có một số hành vi cập nhật hàng loạt mặc định hiện tại với 3.0?" và câu trả lời là "Không hoàn toàn." Ví dụ mã của bạn là chính xác những gì tôi cần, tôi sẽ kiểm tra nó ra và cập nhật nếu cần thiết. – petroleyum

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