2015-01-07 35 views
12

Tôi hiện đang làm việc trên Django với Django Rest Framwork.ModelViewSet - Cập nhật trường lồng nhau

Tôi không thể cập nhật đối tượng của mình trong trường đối tượng lồng nhau.


serializer.py

class OwnerSerializer(serializers.ModelSerializer): 
    class Meta: 
     model = Owner 
     fields = ('id', 'name') 

class CarSerializer(serializers.ModelSerializer): 
    owner = ownerSerializer(many=False, read_only=False) 
    class Meta: 
     model = Car 
     fields = ('id', 'name', 'owner') 

view.py

class OwnerViewSet(viewsets.ModelViewSet): 
    queryset = Owner.objects.all() 
    serializer_class = OwnerSerializer 

class CarViewSet(viewsets.ModelViewSet): 
    serializer_class = CarSerializer 
    queryset = Car.objects.all() 

    def create(self, request): 
     serialized = self.serializer_class(data=request.DATA) 
     if serialized.is_valid(): 
      serialized.save() 
      return Response(status=HTTP_202_ACCEPTED) 
     else: 
      return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) 

Khi tôi làm điều này:

Request URL:http://localhost:9000/api/v1/cars/1/?format=json 
Request Method:PUT 
Request Paylod : 
{ 
    "id":1, 
    "name": "TEST", 
    "ower": { 
     "id":1, 
     "name": "owner_test" 
    } 
} 

tôi nhận được phản ứng sau:

The `.update()` method does not support writable nestedfields by default. 
Write an explicit `.update()` method for serializer `app.serializers.CarSerializer`, 
or set `read_only=True` on nested serializer fields. 

Biết:

  • Tôi muốn giữ serialization chủ sở hữu trên GET;
  • Chúng ta có thể tưởng tượng chiếc xe lồng nhau bởi một đối tượng và vv ...

Làm thế nào tôi có thể làm gì nếu tôi muốn thay đổi chủ sở hữu khi tôi cập nhật các xe.

+2

bản sao có thể có của [django-rest-framework 3.0 tạo hoặc cập nhật trong bộ nối tiếp lồng nhau] (http://stackoverflow.com/questions/27434593/django-rest-framework-3-0-create-or-update -in-lồng nhau-serializer) –

+0

Xe tăng! Tôi lặp lại bản thân mình xin lỗi, nhưng tại sao ghi đè là trong serializer và không phải trong xem, như: [Django-doc] (http://www.django-rest-framework.org/api-guide/viewsets/#marking- thêm hành động-cho-định tuyến), theo cách đó có thể trả về trạng thái ?? –

Trả lời

3

Chỉ trong trường hợp ai đó tình cờ về vấn đề này

có lỗi tương tự trong trường hợp của tôi, nhưng thiết READ_ONLY True cố định nó cho tôi.

owner = ownerSerializer(many=False, read_only=True) 

Lưu ý rằng, trường này sẽ không xuất hiện dưới dạng khi đăng dữ liệu lên api.

6

Một chút trễ, nhưng, Hãy thử điều này,

class OwnerSerializer(serializers.ModelSerializer): 
    class Meta: 
     model = Owner 
     fields = ('id', 'name') 
     extra_kwargs = { 
      'id': { 
       'read_only': False, 
       'required': True 
      } 
     } #very important 

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

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

     # Delete any detail not included in the request 
     owner_ids = [item['owner_id'] for item in validated_data['owners']] 
     for owner in cars.owners.all(): 
      if owner.id not in owner_ids: 
       owner.delete() 

     # Create or update owner 
     for owner in validated_data['owners']: 
      ownerObj = Owner.objects.get(pk=item['id']) 
      if ownerObje: 
       ownerObj.some_field=item['some_field'] 
       ....fields... 
      else: 
       ownerObj = Owner.create(car=instance,**owner) 
      ownerObj.save() 

     return instance 
-2

Nguồn ModelSerializer.create()ModelSerializer.update() cấm hành vi này:

raise_errors_on_nested_writes('create', self, validated_data) 

Nếu chúng ta loại bỏ dòng này, những hành động có thể nhận được thông qua và công trình tốt.

Điều đó có nghĩa, the doc nói:

Để sử dụng có thể ghi serialization lồng nhau bạn sẽ muốn khai báo một lĩnh vực lồng nhau trên lớp serializer, và viết create() và/hoặc update() phương pháp một cách rõ ràng.

Chúng ta có thể sử dụng trực tiếp mã ModelSerializer.save()ModelSerializer.update() nguồn đến phương pháp "viết rõ ràng" này, với dòng raise_errors_on_nested_writes gỡ bỏ.

Vì vậy, trên tất cả, chúng ta có thể định nghĩa một lớp như vậy AllowNestedWriteMixin như sau:

import traceback 
from rest_framework.utils import model_meta 
from rest_framework.compat import set_many 

class AllowNestedWriteMixin: 
    def create(self, validated_data): 
     ModelClass = self.Meta.model 
     info = model_meta.get_field_info(ModelClass) 
     many_to_many = {} 
     for field_name, relation_info in info.relations.items(): 
      if relation_info.to_many and (field_name in validated_data): 
       many_to_many[field_name] = validated_data.pop(field_name) 

     try: 
      instance = ModelClass.objects.create(**validated_data) 
     except TypeError: 
      tb = traceback.format_exc() 
      msg = (
       'Got a `TypeError` when calling `%s.objects.create()`. ' 
       'This may be because you have a writable field on the ' 
       'serializer class that is not a valid argument to ' 
       '`%s.objects.create()`. You may need to make the field ' 
       'read-only, or override the %s.create() method to handle ' 
       'this correctly.\nOriginal exception was:\n %s' % 
       (
        ModelClass.__name__, 
        ModelClass.__name__, 
        self.__class__.__name__, 
        tb 
       ) 
      ) 
      raise TypeError(msg) 

     # Save many-to-many relationships after the instance is created. 
     if many_to_many: 
      for field_name, value in many_to_many.items(): 
       set_many(instance, field_name, value) 

     return instance 

    def update(self, instance, validated_data): 
     info = model_meta.get_field_info(instance) 

     for attr, value in validated_data.items(): 
      if attr in info.relations and info.relations[attr].to_many: 
       set_many(instance, attr, value) 
      else: 
       setattr(instance, attr, value) 
     instance.save() 

     return instance 

Và nếu chúng ta muốn hành vi trên, chúng ta được thừa hưởng lớp mixin này trước khi ModelSerializer, một cái gì đó giống như dưới đây về ví dụ của bạn:

class OwnerSerializer(AllowNestedWriteMixin, 
         serializers.ModelSerializer): 
    class Meta: 
     model = Owner 
     fields = ('id', 'name') 

class CarSerializer(AllowNestedWriteMixin, 
        serializers.ModelSerializer): 
    owner = ownerSerializer(many=False, read_only=False) 
    class Meta: 
     model = Car 
     fields = ('id', 'name', 'owner') 
+0

Bạn có thể thêm hàng nhập khẩu không? Tôi không thể thấy phương thức set_many bắt đầu từ đâu. Cảm ơn! – Lukas

+0

Sử dụng phương pháp này, bạn chỉ lặng lẽ bỏ qua vấn đề, trường 'chủ sở hữu' sẽ không được cập nhật –

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