#python #django #django-rest-framework
#python #django #django-rest-framework
Вопрос:
У меня есть модель Django, которая служит описанием запроса. Оно создано для отправки запроса клиентом REST, служит для записи текущего статуса задач и записи исторических запросов, полученных клиентами.
В этой модели есть несколько полей, которые используются для точной настройки и управления запрошенной задачей (скажем, целевым объектом и типом действия). Очевидно, я бы хотел, чтобы клиент управлял этими полями при создании объекта, но не после (вы не можете изменить объект после запуска задачи).
Я надеялся на что-то похожее на serializers.ReadOnlyField
, поэтому у меня могло бы быть что-то похожее на это:
class TaskSerializer(serializers.ModelSerializer):
owner = serializers.ReadOnlyField(source='owner.username')
task_id = serializers.ReadOnlyField()
target_object = serializers.CreateOnlyField()
но не смог найти его в документации или Google.
Ответ №1:
Просто чтобы расширить ответ Wim, это способ выбрать другой сериализатор на основе метода входящего запроса:
class RequestViewSet(viewsets.ModelViewSet):
serializer_class = RequestModelSerializer
model = Request
def get_serializer_class(self):
serializer_class = self.serializer_class
if self.request.method == 'POST':
serializer_class = SerializerWithoutCertainFields
return serializer_class
Ответ №2:
Ответ @fabio.sussetto направил меня на правильный путь. Я думаю, что мой ответ немного красивее; я не указываю сериализатор в классе напрямую, а только в get_serializer_class()
. Кроме того, я переключаю его не на основе типа HTTP (т. Е. POST
), а скорее на основе действия, update
которое я считаю более декларативным.
class RequestViewSet(viewsets.ModelViewSet):
model = Request
def get_serializer_class(self):
if self.action == 'update':
return serializer_class = SerializerWithoutCertainFields
return RequestModelSerializer
Ответ №3:
Этого можно достичь с помощью одного сериализатора с помощью to_internal_value
метода
class TaskSerializer(serializers.ModelSerializer):
# Field settings here
def to_internal_value(self, data):
data = super().to_internal_value(data)
# Remove target_object if serializer is updating object
if self.instance:
data.pop('target_object', None)
return data
class Meta:
model = Task
fields = ('owner', 'task_id', 'target_object')
Ответ №4:
также может быть выполнено с помощью комбинации required=False
и удаления значения поля при обновлении, как в этом примере:
class SectionSerializer(serializers.ModelSerializer):
# do not require field lesson when updating
lesson = serializers.PrimaryKeyRelatedField(queryset=Lesson.objects.all(), required=False)
# do not allow changing the lesson field
def update(self, instance, validated_data):
validated_data.pop("lesson", None)
return super().update(instance, validated_data)