Как автоматически заполнить поле сериализатора, доступное только для чтения, в 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
он должен возвращать отправителя и получателя.