Данные обновления Django Rest Framework перед сериализацией

Я хочу, чтобы любой пользователь мог создавать свои собственные продукты с помощью моего RESTful API. Для этого я создал представление, которое наследует ListCreateAPIView. Проблема в том, что пользователь должен создавать только те продукты, которыми он владеет, поэтому при создании экземпляра модели продукта я хотел, чтобы поле «Владелец» соответствовало аутентифицированному пользователю.

Вот моя модель продукта

class Product(models.Model):
    owner = models.ForeignKey(User)
    name = models.CharField(max_length=30)

Очевидно, мой сериализатор:

class ProductSerializer(serializers.ModelSerializer):
    class Meta:
        model = models.Product

и мой взгляд:

class ProductView(generics.ListCreateAPIView):
    queryset = models.Product.objects.all()
    serializer_class = serializers.ProductSerializer
    permission_classes = (IsAuthenticatedOrReadOnly,)

    def create(self, request, *args, **kwargs):
        serializer = self.get_serializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        #serializer.initial_data['owners'] = models.Person.objects.get(user__email=request.user).user_id
        self.perform_create(serializer)
        headers = self.get_success_headers(serializer.data)

        return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers)

Как видите, я попытался изменить «initial_data», но это неизменяемый QueryDict. Другой вариант - преобразовать его в словарь Python, а затем добавить значение «владелец», но при этом я получаю каждое значение в виде списка (т.е. {'name': ['MyName']}), так что это было бы очень уродливый способ решить проблему, я думаю, что это должно быть более простое решение.


person Andres Espinosa    schedule 03.07.2016    source источник


Ответы (3)


Вы можете переопределить perform_create() и передать текущего пользователя как owner. Затем, когда экземпляр Product будет создан, поле owner будет сохранено с текущим пользовательским значением.

class ProductView(generics.ListCreateAPIView):
    queryset = models.Product.objects.all()
    serializer_class = serializers.ProductSerializer
    permission_classes = (IsAuthenticatedOrReadOnly,)

    def perform_create(self, serializer):
        serializer.save(owner=self.request.user) # pass the current user as the 'owner'

Кроме того, вы должны определить поле owner в сериализаторе как read_only. Тогда поле не потребуется при десериализации. Но это поле будет включено в вывод при сериализации.

 class ProductSerializer(serializers.ModelSerializer):
    class Meta:
        model = models.Product
        extra_kwargs = {'owner': {'read_only':True}} # set 'owner' as read-only field 
person Rahul Gupta    schedule 03.07.2016
comment
Проблема в том, что функция execute_create вызывается после выполнения is_valid(), а сериализатор недействителен без поля владельца, поэтому функция create вызовет исключение до того, как будет выполнено Perform_create. - person Andres Espinosa; 03.07.2016
comment
Вы можете определить поле owner как read_only в своем сериализаторе. Тогда он не будет требоваться при десериализации, но всегда будет возвращаться в выводе при сериализации. - person Rahul Gupta; 03.07.2016

Простое решение ниже. owner не будет отображаться в запросах GET/POST/PUT и т. д., но будет автоматически назначен текущему аутентифицированному пользователю.

from rest_framework.serializers import (CurrentUserDefault, HiddenField,
                                        ModelSerializer)

class ProductSerializer(ModelSerializer):
    owner = HiddenField(default=CurrentUserDefault())

    class Meta:
        model = models.Product
person dikamilo    schedule 04.07.2016
comment
это довольно хорошие работы. Спасибо. - person ishak O.; 09.02.2021

Вы можете передать исходные данные в поле зрения, а затем переписать значение по умолчанию в сериализаторе.

просмотры.py

class ItemListCreateView(ListCreateAPIView):

    def get_serializer_context(self):
        return {"delivery_request": self.kwargs['req_pk']}

сериализаторы.py

class ItemCreateSerializer(ModelSerializer):
    delivery_request = CharField(default='')

    def validate_delivery_request(self, value):
        try:
            value = DeliveryRequest.objects.get(
                id=self.context["delivery_request"])
        except DeliveryRequest.DoesNotExist:
            raise ValidationError(
                self.Meta.error_messages['delivery_request_not_found'])
        return value

PS. это полезно, когда вы хотите, например, заполнить ненулевые данные из URL-адреса

person Artem Bernatskyi    schedule 12.03.2018