我为以下模型编写了API:
class TemplateProjectGroup(models.Model):
pass
class TemplateProject(models.Model):
name = models.CharField(max_length=255, unique=True)
description = models.CharField(max_length=1024, blank=True)
group = models.ForeignKey(TemplateProjectGroup, on_delete=models.CASCADE)
project = models.ForeignKey(Project, on_delete=models.CASCADE)
avatar_url = models.URLField(max_length=1024, blank=True)
逻辑如下:用户可以使用不存在的TemplateProject
字段创建group
的实例。因此,如果组不存在,则应使用特定的ID创建该组。所以,我有这个序列化器:
class TemplateProjectSerializer(serializers.ModelSerializer):
def create(self, validated_data):
template_project_group_id = validated_data.pop('group')
project = validated_data.pop('project')
group, _ = models.TemplateProjectGroup.objects.get_or_create(id=template_project_group_id)
template_project = models.TemplateProject.objects.create(**validated_data, group_id=group.id, project_id=project.id)
return template_project
def update(self, instance, validated_data):
template_project_group_id = validated_data.pop('group')
group, _ = models.TemplateProjectGroup.objects.get_or_create(id=template_project_group_id)
instance.save()
instance.update(**validated_data, group=group)
return instance
class Meta:
model = models.TemplateProject
fields = ('name', 'description', 'group', 'project', 'avatar_url')
和视图:
class TemplateProjectsView(generics.ListCreateAPIView):
pagination_class = None
serializer_class = serializers.TemplateProjectSerializer
def get_queryset(self):
return models.TemplateProject.objects.all()
当我尝试检索对象列表时,效果很好,但是由于出现以下错误,所以无法使用此API创建对象:
Invalid pk "1" - object does not exist.
因此,在创建对象之前,将对所有字段应用验证,并且序列化程序无法将该整数序列化为对象,因为该对象(由外键引用)不存在。我写了一个方法validate_group(self, value)
,但是在执行点到达此方法之前引发了异常。我可以在调试器中中断的最接近点是方法is_valid(self, raise_exception=False)
。我可以在那里创建丢失的对象,但我认为这将是一个坏习惯,因为此方法实际上并非旨在验证或准备数据。
如何在通过所有验证之前正确创建对象?
答案 0 :(得分:0)
一个可能的选择是将 group 明确定义为整数字段。这样,将不会尝试将组字段验证为 TemplateProjectGroup 实例。
class TemplateProjectSerializer(serializers.ModelSerializer):
group = serializers.IntegerField(source='group.id')
...
通过此设置,您可以在序列化程序的create或update方法中获得如下的组ID:
template_project_group_id = validated_data.pop('group').get('id')
另一个选择是,您可以通过从请求中获取组ID来在视图中获取或创建组实例,然后始终将现有的组ID传递给序列化器,并期望序列化器中存在现有的组ID。这将意味着将一些验证逻辑移至视图(您至少需要检查是否为组字段提供了整数),但是您不需要调整序列化器。