如何在自定义DRF MultipleChoiceField中从m2m模型关系中预先选择选项



我的Book模型可以通过m2m关系将Tag模型与其关联,这些标签总是通过FKTagCategory模型进一步分类。

class TagCategory(models.Model):
name = models.CharField(...)
class Tag(models.Model):
name = models.CharField(...)
category = models.ForeignKey(to=TagCategory, ...)
class Book(models.Model):
tags = models.ManyToManyField(to=Tag, ...)

使用DRF中的序列化程序,我希望BookSerializer提供一个MultipleChoiceField,供最终用户从中选择许多标签。如果我使用serializers.ModelSerializer并且不接触任何东西,它可以正常工作。

但我实际上想按类别对标签/选项进行分组,这不是默认行为,所以我必须定义自己的MultipleChoiceField,在choices中对选项进行分组并提醒字段从Book模型的正确属性中获取其source

class BookSerializer(serializers.ModelSerializer):
tags_input = serializers.MultipleChoiceField(
choices=[
[category.name, [[tag.pk, tag.name]
for tag in category.tags.all()]] for category in Category.objects.all()],
source="tags",
write_only=True,
)
fields = ("tags_input",)

这似乎适用于创建Book模型和通过m2m分配标签。但是,当用标记序列化现有模型以进行更新时,初始标记/选项并没有按预期预先选择。设置initial="tags"似乎不会改变任何内容。

在序列化模型时,如何从Book.tags中成功检索和预选标记/选项?

好的,所以我在这里的困惑是认为ModelSerializer实际上会使用MultipleChoiceField,所以我可以击败它并自己定义它:不。tags是m2m关系,所以我需要一个RelatedFieldmany=True

首先,由于我是从同一个模型字段序列化和反序列化的,所以我不应该使用我提出的tags_input解决方法。我需要一个能做所有事情的领域:

class TagChoiceRelatedField(serializers.RelatedField):
queryset = Tags.objects.all()
def to_representation(self, value):
return value.pk
def get_choices(self, cutoff=None):
return {
category.name:
{tag.pk: tag.name for tag in category.tags.all()}
for category in TagCategory.objects.all()
}
def to_internal_value(self, data):
try:
tag = self.get_queryset().get(pk=data)
except ObjectDoesNotExist:
raise ValidationError()
return tag
class BookSerializer(serializers.ModelSerializer):
tags = TagChoiceRelatedField(many=True)
class Meta:
fields = ("tags",)

串行器现在使用该字段:

  • 期望将每个标签及其pk序列化(to_representation(
  • 预期使用pk(to_internal_value(反序列化每个标签
  • 很好地根据标签/选项的类别对其进行分组(get_choices(
  • 如果适用的话,最后用book实例的标记初始化后者(内部的东西(

最新更新