Как добавить связанное поле в экземпляр сериализатора?

У меня есть следующая модель + сериализатор, где я посылаю пост-запрос для создания нового экземпляра модели. Пользователь, отправляющий пост-запрос, связан с Company, который я хочу передать в сериализатор как связанный экземпляр модели.

<
# views.py

class OfferList(APIView):
    """
    List all Offers or create a new Offer related to the authenticated user
    """
    def get(self, request):
        offers = Offer.objects.filter(company__userprofile__user=request.user)
        serializer = OfferSerializer(offers, many=True)
        return Response(serializer.data)

    def post(self, request):
        serializer = OfferSerializer(data=request.data)
        
        # Add related company instance
        company = Company.objects.get(userprofile__user=request.user)
        serializer['company'] = company # this doesn't work
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data,
                            status=status.HTTP_201_CREATED)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
# offer/models.py

class Offer(models.Model):
    """
    A table to store Offer instances
    """

    # Relations
    company = models.ForeignKey(Company, on_delete=models.CASCADE)

..
# serializers.py

class OfferSerializer(serializers.ModelSerializer):
    class Meta:
        model = Offer
        fields = '__all__'
user/models.py

class UserProfile(models.Model):
    """
    Extends Base User via 1-1 for profile information
    """
    # Relations
    user = models.OneToOneField(User, on_delete=models.CASCADE)
    company = models.ForeignKey(Company, on_delete=models.CASCADE, null=True)

Один из простых способов - передать экземпляр компании через сериализатор. Так что, возможно, измените ваш метод post на что-то вроде:

from rest_framework.generics import get_object_or_404

def post(self, request):
    serializer = OfferSerializer(data=request.data)
    
    # Add related company instance
    
    if serializer.is_valid():
        company = get_object_or_404(Company, userprofile__user=request.user)  # raising 404 exception if related company does not exist, 
        # and you're sure that there is one and only one company for this user not more!
        
        serializer.save(company=company)
        return Response(serializer.data,
                        status=status.HTTP_201_CREATED)
    return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

и затем измените поля вашего сериализатора, чтобы исключить из них поле компании (поскольку вы уже отправляете эти данные через ваш сериализатор):

class OfferSerializer(serializers.ModelSerializer):
    class Meta:
        model = Offer
        fields = ["some_field", "other_field"]  # Do not include company in your fields.
        # also note that since I didn't know your Offer's fields I used ["some_field", "other_field"] for fields
    

надеюсь, это решит вашу проблему.

Хмм, я думаю, что использование контекста для сериализаторов будет хорошим способом решить ваш случай.

# serializers.py

class OfferSerializer(serializers.ModelSerializer):
    class Meta:
        model = Offer
        # now that we do not want company from the request body
        exclude = ["company"]

    def create(self, validated_data):
        # add company to the validated data from the context
        # we can feed the context from the APIView
        validated_data["company"] = self.context.get("company", None)
        ...
        return super().create(validated_data)
# views.py

class OfferList(APIView):
    def post(self, request):
        # imo, we do not have to query for UserProfile
        # if the company is assigned to the UserProfile instance for the requestor
        # then, one2one relation can give us this
        context = {"company": request.user.userprofile.company}
        serializer = OfferSerializer(data=request.data, context=context)
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data, status=status.HTTP_201_CREATED)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
Вернуться на верх