#python #django #django-rest-framework
#питон #django #django-rest-фреймворк #python
Вопрос:
У меня есть пользовательский метод create в моем сериализаторе для добавления тегов, где потребитель может отправлять полезную нагрузку исключительно с tags
ключом, содержащим список имен тегов.
{
"id": 1,
"title": "Testing",
...
"tags": ["Python", "Django", "Go"]
}
Сериализатор:
class StreamSerializer(serializers.HyperlinkedModelSerializer):
streamer = StreamerSerializer()
tags = TagSerializer(many=True)
class Meta:
model = Stream
fields = [
"id",
"source",
"stream_id",
"started_at",
"collected_at",
"title",
"thumbnail_url",
"viewer_count",
"video_type",
"language",
"streamer",
"stream_data",
"tags",
"live_now",
]
extra_kwargs = {"tags": {"validators": []}}
def create(self, validated_data):
# pop streamer and tags from the payload
print(validated_data)
streamer_data = validated_data.pop("streamer")
tag_names = validated_data.pop("tags")
# get_or_create the streamer for this stream
streamer_user_id = streamer_data.pop("user_id")
streamer, created = Streamer.objects.get_or_create(
user_id=streamer_user_id, defaults=streamer_data
)
# use get_or_create on the stream to prevent duplicates if stream
# crashes or a node change and just update the existing stream
# with new data instead.
stream, created = Stream.objects.get_or_create(
streamer=streamer, defaults=validated_data
)
# add tags to the newly created stream
for tag_name in tag_names:
tag = Tag.objects.get(name=tag_name)
stream.tags.add(tag.id)
stream.save()
return stream
Я бы хотел, чтобы теги имели read_only=True
, но, делая это, я получаю KeyError
при отправке в эту конечную точку, поскольку теперь это исключено из любых методов записи.
class StreamSerializer(serializers.HyperlinkedModelSerializer):
streamer = StreamerSerializer()
tags = TagSerializer(many=True, read_only=True) # add read_only
...
Что я мог бы сделать, чтобы не иметь тегов, необходимых для проверки, но при этом иметь доступ к полю в моем create
методе? Нужен ли мне для этого пользовательский валидатор?
Ответ №1:
Это не совсем отвечает на вопрос, но достигает цели, которую я собираюсь использовать to_internal_value
на своем TagSerializer
.
class TagSerializer(serializers.HyperlinkedModelSerializer):
parent = ParentTagSerializer()
class Meta:
model = Tag
fields = ["name", "aliases", "parent"]
extra_kwargs = {"aliases": {"validators": []}}
# to_internal_value will iterate each tag name in the post payload
# and return the tag matching that name.
def to_internal_value(self, tag_name):
tag = Tag.objects.get(name=tag_name)
return tag
class StreamSerializer(serializers.HyperlinkedModelSerializer):
streamer = StreamerSerializer()
tags = TagSerializer(many=True)
...