2014-12-11 16 views
61

Với django-nghỉ ngơi-framework 3.0 và có những mô hình đơn giản:django-nghỉ ngơi-framework 3.0 tạo hoặc cập nhật trong serializer lồng nhau

class Book(models.Model): 
    title = models.CharField(max_length=50) 


class Page(models.Model): 
    book = models.ForeignKey(Books, related_name='related_book') 
    text = models.CharField(max_length=500) 

Và cho yêu cầu JSON này:

{ 
    "book_id":1, 
    "pages":[ 
     { 
     "page_id":2, 
     "text":"loremipsum" 
     }, 
     { 
     "page_id":4, 
     "text":"loremipsum" 
     } 
    ] 
} 

Làm thế nào tôi có thể viết một serializer lồng nhau để xử lý JSON này và cho mỗi page cho book nhất định hoặc tạo một trang mới hoặc cập nhật nếu nó tồn tại.

class RequestSerializer(serializers.Serializer): 
    book_id = serializers.IntegerField() 
    page = PageSerializer(many=True) 


class PageSerializer(serializers.ModelSerializer): 
    class Meta: 
     model = Page 

Tôi biết rằng instantiating serializer với một instance sẽ cập nhật một dòng nhưng làm thế nào tôi nên sử dụng nó bên trong phương pháp create của serializer lồng nhau?

Trả lời

84

Thứ nhất, bạn có muốn hỗ trợ tạo các bản sao sách mới hay chỉ cập nhật các bản sao hiện có?

Nếu bạn chỉ muốn tạo một trường hợp cuốn sách mới của bạn có thể làm một cái gì đó như thế này ...

class PageSerializer(serializers.Serializer): 
    text = serializers.CharField(max_length=500) 

class BookSerializer(serializers.Serializer): 
    page = PageSerializer(many=True) 
    title = serializers.CharField(max_length=50) 

    def create(self, validated_data): 
     # Create the book instance 
     book = Book.objects.create(title=validated_data['title']) 

     # Create or update each page instance 
     for item in validated_data['pages']: 
      page = Page(id=item['page_id'], text=item['text'], book=book) 
      page.save() 

     return book 

Lưu ý rằng tôi chưa bao gồm book_id đây. Khi chúng tôi tạo các trường hợp sách, chúng tôi sẽ không bao gồm id sách. Khi chúng tôi cập nhật các phiên bản sách, chúng tôi thường sẽ bao gồm id sách làm một phần của URL, thay vì trong dữ liệu yêu cầu.

Nếu bạn muốn hỗ trợ cả tạo và cập nhật cá thể sách thì bạn cần phải suy nghĩ về cách bạn muốn xử lý các trang không được bao gồm trong yêu cầu, nhưng hiện được liên kết với cá thể sách.

Bạn có thể chọn âm thầm bỏ qua các trang đó và để nguyên chúng như vậy, bạn có thể muốn tăng lỗi xác thực hoặc bạn có thể muốn xóa chúng.

Giả sử bạn muốn xóa bất kỳ trang nào không được bao gồm trong yêu cầu.

def create(self, validated_data): 
    # As before. 
    ... 

def update(self, instance, validated_data): 
    # Update the book instance 
    instance.title = validated_data['title'] 
    instance.save() 

    # Delete any pages not included in the request 
    page_ids = [item['page_id'] for item in validated_data['pages']] 
    for page in instance.books: 
     if page.id not in page_ids: 
      page.delete() 

    # Create or update page instances that are in the request 
    for item in validated_data['pages']: 
     page = Page(id=item['page_id'], text=item['text'], book=instance) 
     page.save() 

    return instance 

Nó cũng có thể là bạn có thể muốn chỉ cập nhật hỗ trợ cuốn sách, và không hỗ trợ sáng tạo, trong trường hợp này, chỉ bao gồm các phương pháp update().

Cũng có nhiều cách khác nhau để bạn có thể giảm số lượng truy vấn, ví dụ: sử dụng tạo/xóa hàng loạt, nhưng ở trên sẽ thực hiện công việc theo cách khá đơn giản.

Như bạn có thể thấy có sự tinh tế trong các loại hành vi bạn có thể muốn khi xử lý dữ liệu lồng nhau, vì vậy hãy suy nghĩ kỹ về hành vi bạn mong đợi trong các trường hợp khác nhau.

Cũng lưu ý rằng tôi đã sử dụng Serializer trong ví dụ trên thay vì ModelSerializer. Trong trường hợp này, đơn giản hơn là chỉ bao gồm tất cả các trường trong lớp serializer một cách rõ ràng, thay vì dựa vào tập hợp các trường tự động mà ModelSerializer tạo theo mặc định.

+1

'bạn có thể chỉ muốn hỗ trợ cập nhật sách ..., chỉ bao gồm phương thức update()'. Trong trường hợp này, cách 'instance' trong phương thức cập nhật sẽ được lấp đầy với một cuốn sách hiện có? – norbertpy

+0

Bằng cách khởi tạo trình tuần tự với đối số từ khóa 'thể hiện'. Thông thường bạn sẽ nhận được điều đó bằng cách thực hiện tra cứu dựa trên khóa chính trong URL. Nếu bạn đang sử dụng chế độ xem chung sẽ được xử lý cho bạn. Hãy xem DetailMixin trong 'mixins.py' để thực hiện điều đó. –

+1

Cảm ơn Tom. Tôi đã nhận nó ngay bây giờ. – norbertpy

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