Django REST框架从列表创建对象并将错误返回到无效对象

时间:2014-03-13 14:33:20

标签: python django django-rest-framework

我有以下代码

serializer.py

class ContactSerializer(serializers.ModelSerializer):

    def __init__(self, *args, **kwargs):
        many = kwargs.pop('many', True)
        many = True
        super(ContactSerializer, self).__init__(many=many, *args, **kwargs)

    class Meta:
        model = Contact

    def validate(self, attrs):
        # Check that the user in contact isn't the same as the parent user
        if 'user' in attrs.keys() and 'parent_user' in attrs.keys() and attrs['user']:
            if attrs['user'].pk == attrs['parent_user'].pk:
                raise serializers.ValidationError("You can't add yourself as a contact")
        return attrs

views.py

class ContactViewSet(viewsets.ModelViewSet):

    queryset = Contact.objects.all()
    serializer_class = ContactSerializer
    authentication_classes = (TokenAuthentication,)
    permission_classes = (permissions.IsAuthenticated, )

    def get_queryset(self):
        return Contact.objects.filter(parent_user=self.request.user.pk)

    def create(self, request):
        if isinstance(request.DATA, list):
            for i, contact_data in enumerate(request.DATA):
                # Get the user id from the request
                request.DATA[i]['parent_user'] = self.request.user.pk

                # Check if the contact is aleardy a user
                if 'email' in contact_data:
                    try:
                        request.DATA[i]['user'] = User.objects.get(email=contact_data['email']).pk
                    except User.DoesNotExist, e:
                        pass

        return super(ContactViewSet, self).create(request)

现在问题在于,当我在POST中发送联系人列表时,没有创建任何对象,它只会发送无效对象的错误。例如: 的 POST

[
  {
    "first_name": "Eyad",
    "last_name": "tttttt",
    "email": "eyad@gmail.com"
  },
  {
    "first_name": "Eyad",
    "last_name": "mmmmmm",
    "email": "eyad2@gmail.com"
  }
]

返回

[
    {},
    {
        "non_field_errors": [
            "You can't add yourself as a contact"
        ]
    }
]

我怎样才能返回这样的内容:

[
    {
        "created": true
    },
    {
        "non_field_errors": [
            "You can't add yourself as a contact"
        ]
    }
]

这样,当调用API时,会创建有效对象,并且API调用者不必再次发送这些对象。

2 个答案:

答案 0 :(得分:1)

我创建了CreateModelMixin的子类来更改create方法。

class BulkCreateModelMixin(mixins.CreateModelMixin):
    """
    Create valid objects and return errors for invalid ones.
    """

    def create(self, request, *args, **kwargs):
        # The initial serializer
        serializer = self.get_serializer(data=request.DATA)
        return_list = []

        for item in zip(serializer.errors, serializer.init_data):
            # If item doesn't have errors
            if not item[0]:

                # Create a an individual serializer for the valid object and save it
                object_serializer = self.get_serializer(data=[item[1]])
                if object_serializer.is_valid():
                    self.pre_save(object_serializer.object)
                    self.object = object_serializer.save(force_insert=True)
                    self.post_save(self.object, created=True)

                    return_list.append(object_serializer.data[0])
            else:
                return_list.append(item[0])

        # Status code
        if serializer.errors:
            return_status = status.HTTP_206_PARTIAL_CONTENT
        else:
            return_status = status.HTTP_201_CREATED

        return Response(return_list, status=return_status)

然后将新的mixin添加到视图集

class ContactViewSet(viewsets.ModelViewSet, BulkCreateModelMixin):
    ..........
    ..........

答案 1 :(得分:0)

我用另一种方式解决了这个问题。 创建 2 个 mixin,一个用于视图(覆盖 create 方法,另一个用于 ListSerializer(覆盖 to_internal_value method)。

所以我有:

class CreateListMixin:
    """Allows bulk creation of a resource."""

    def get_serializer(self, *args, **kwargs):
        if isinstance(kwargs.get('data', {}), list):
            kwargs['many'] = True

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

    def create(self, request, *args, **kwargs):
        serializer = self.get_serializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        self.perform_create(serializer)
        headers = self.get_success_headers(serializer.data)
        return Response({"result": serializer.data, "errors": serializer.errors_list},
                        status=status.HTTP_202_ACCEPTED, headers=headers)


class ErrorsListSerializerMixin:
    error_list = []

    def to_internal_value(self, data):
        """
        List of dicts of native values <- List of dicts of primitive datatypes.
        """
        if not isinstance(data, list):
            message = self.error_messages['not_a_list'].format(
                input_type=type(data).__name__
            )
            raise ValidationError({
                api_settings.NON_FIELD_ERRORS_KEY: [message]
            }, code='not_a_list')
        if not self.allow_empty and len(data) == 0:
            message = self.error_messages['empty']
            raise ValidationError({
                api_settings.NON_FIELD_ERRORS_KEY: [message]
            }, code='empty')

        ret = []
        errors = []

        for item in data:
            try:
                validated = self.child.run_validation(item)
            except ValidationError as exc:
                errors.append({"error": exc.detail, "data": item})
            else:
                ret.append(validated)

        if any(errors):
            self.errors_list = errors
            # raise ValidationError(errors)
        return ret

views.py

class SKUMatchesView(CreateListMixin, viewsets.ModelViewSet):
......................
......................

serializers.py

class SKUMatchesListSerializer(ErrorsListSerializerMixin, serializers.ListSerializer):
.....................
.....................

因此,当我发布例如此数据时:

[{          "sku_customer_uid": "13864-20000000428265",
            "company": 1,
            "code": "123456784654654",
            "marketplace": "ozon"
},
{          "sku_customer_uid": "13864-2000000042824",
            "company": 1,
            "code": "123456789*8",
            "marketplace": "ozon"
}
]

我收到同样的回复:

{
  "result": [
    {
      "id": 8821,
      "sku_customer_uid": null,
      "company": 1,
      "code": "123456784654654",
      "marketplace": "ozon"
    }
  ],
  "errors": [
    {
      "error": {
        "non_field_errors": [
          "Wrong code"
        ]
      },
      "data": {
        "sku_customer_uid": "13864-2000000042824",
        "company": 1,
        "code": "123456789*8",
        "marketplace": "ozon"
      }
    }
  ]
}