我有m2m相关实体:
class Tag(models.Model):
name = models.CharField(
max_length=80,
blank=False,
unique=True
)
class File(models.Model):
tags = models.ManyToManyField(Tag)
uploader = models.ForeignKey(User, on_delete=models.DO_NOTHING)
name = models.CharField(
max_length=255,
blank=False,
unique=True,
)
和它们的序列化器:
class TagSerializer(serializers.ModelSerializer):
class Meta:
model = Tag
fields = ('id', 'name')
extra_kwargs = {
'name': {
'validators': [],
},
}
class FileSerializer(serializers.ModelSerializer):
tags = TagSerializer(many=True, read_only=False)
class Meta:
model = File
fields = ('id', 'name', 'tags')
def update(self, instance, validated_data):
tags_data = validated_data.pop('tags')
if 'name' in validated_data:
instance.name = validated_data['name']
instance_tags = instance.tags.all()
new_tag_list = []
# add new tags
for tag in tags_data:
tag, created = Tag.objects.get_or_create(name=tag['name'])
new_tag_list.append(tag)
if tag not in instance_tags:
instance.tags.add(tag)
# remove old tags
for instance_tag in instance_tags:
if instance_tag not in new_tag_list:
instance.tags.remove(instance_tag)
return instance
正如您所看到的,我通过以下代码设置关闭了TagSerializer中Tag.name字段的所有验证:extra_kwargs = {'name': {'validators': []}}
这是因为在保存更新文件时出现验证错误:
serializer = FileSerializer(file, data=request.data, partial=True)
if serializer.is_valid():
...
如果您有包含标签列表的文件,并且只想添加或删除某些标签,则您将收到错误'此类名称的标签已存在'。
所以这个峰值工作正常,但是现在我没有对Tag.name进行唯一检查。 我试着写一些像FileSerializer中的内容:
class FileSerializer(serializers.ModelSerializer):
class Meta:
model = File
extra_kwargs = {
'tags': {
'validators': [],
},
}
但当然不行。 问题是当我用文件添加/删除它的绑定时,根本不可能验证Tag实体。
答案 0 :(得分:0)
您可以通过update
的方式尝试,但如果此解决方案适合您,则还需要覆盖create
方法。
class FileSerializer(serializers.ModelSerializer):
tags = TagSerializer(many=True, read_only=True)
# ^^^^^^
class Meta:
model = File
fields = ('id', 'name', 'tags')
def update(self, instance, validated_data):
# Override tags_data = validated_data.pop('tags')
# this way
request = self.context['request']
tags_data = request.data.get('tags', [])
# Next your current code
当您使用get_serializer
方法添加的extra-context上下文时,在序列化程序初始添加views from drf 。
serializer = FileSerializer(file, data=request.data, partial=True, context={'request': request})
答案 1 :(得分:0)
您还可以从实例中获取标签,无需通过上下文发送整个请求。
tags_data = self.initial_data.get('tags', [])