Как автоматически заполнить поле сериализатора, доступное только для чтения, в django rest framework?

У меня есть вопрос относительно django rest framework.

В большинстве случаев у меня есть сериализатор, который имеет некоторые поля, доступные только для чтения. Например, рассмотрим эту простую модель ниже:

class PersonalMessage(models.Model):
    sender = models.ForeignKey(User, related_name="sent_messages", ...)
    recipient = models.ForeignKey(User, related_name="recieved_messages", ...)
    text = models.CharField(...)

    def __str__(self) -> str:
        return f"{self.text} (sender={self.sender})"

В этой модели значения sender и recipient должны автоматически предоставляться самим приложением, и пользователь не должен иметь возможности редактировать эти поля. Хорошо, теперь посмотрите на этот сериализатор:

class PersonalMessageSerializer(serializers.ModelSerializer):
    class Meta:
        model = PersonalMessage
        fields = '__all__'
        read_only_fields = ('sender', 'recipient')

Это прекрасно предотвращает установку пользователем произвольного значения в полях sender и recipient. Но проблема в том, что когда эти поля помечены в сериализаторе как доступные только для чтения, сериализатор полностью игнорирует все значения, которые передаются в конструктор для этих полей. Поэтому, когда я пытаюсь создать модель, никакие значения не будут установлены для этих полей:

PersonalMessageSerializer(data={**request.data, 'sender': ..., 'recipient': ...) # Won't work

Какой лучший способ препятствовать пользователям устанавливать произвольные значения и в то же время автозаполнять ограниченные поля в django rest framework?

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

sender = User.objects.first()
recipient = User.objects.last()

serializer = PersonalMessageSerializer(data=request.data)
message = serializer.save(sender=sender, recipient=recipient)

Для того чтобы это работало, имена полей в вашей модели должны совпадать с именами полей. Для справки посмотрите kwargs здесь

Из вопроса невозможно понять, с каким полем (полями) отношений sender и recipient вы хотите взаимодействовать, но общий ответ можно найти в разделе Serializer relations документации Django REST.

Короче говоря, если вы хотите взаимодействовать только с одним полем, вы можете использовать SlugRelatedField, который позволяет вам взаимодействовать с объектом отношения, используя только одно из его полей. Если это только id, вы можете использовать PrimaryKeyRelatedField.

Если вы хотите взаимодействовать с более чем одним полем, то лучше всего использовать вложенные отношения . Здесь вы можете указать пользовательский сериализатор для целевого отношения, но вам придется переопределить метод create() в вашем PersonalMessageSerializer для создания объекта из вашего отношения, поскольку вложенные сериализаторы по умолчанию доступны только для чтения.

Вы можете переопределить контекст сериализатора следующим образом;

PersonalMessageSerializer(data={**request.data, context={'sender': sender, 'recipent': recipent})

и поймать контекст внутри сериализатора.

class PersonalMessageSerializer(serializers.ModelSerializer):
    class Meta:
        model = PersonalMessage
        fields = '__all__'
        read_only_fields = ('sender', 'recipient')
    def validate(self, attrs):
        attrs = super().validate(attrs)
        attrs['sender'] = self.context['sender']
        attrs['recipent'] = self.context['recipent']
        return attrs

теперь serializer.validated_data он должен возвращать отправителя и получателя.

Вернуться на верх