【问题标题】:Avoid validation of foreign key in django rest framework serializer避免在 django rest 框架序列化程序中验证外键
【发布时间】:2019-04-12 21:08:56
【问题描述】:

我为以下模型编写了一个 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)

逻辑如下:用户可以使用不存在的group 字段创建TemplateProject 的实例。因此,如果组不存在,则应使用特定 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)。我可以在那里创建丢失的对象,但我认为这是一种不好的做法,因为这种方法实际上并没有验证或准备数据的目的。

如何在对象通过所有验证之前正确创建对象?

【问题讨论】:

    标签: python django django-rest-framework


    【解决方案1】:

    一个可能的选项是,将 group 明确定义为整数字段。这样,组字段将不会被尝试验证为 TemplateProjectGroup 实例。

    class TemplateProjectSerializer(serializers.ModelSerializer):
        group = serializers.IntegerField(source='group.id')
        ...
    

    通过此设置,您可以在序列化程序的创建或更新方法中获取这样的组 ID:

    template_project_group_id = validated_data.pop('group').get('id')
    

    另一种选择是,您可以在视图中获取或创建组实例,方法是从请求中获取组 id,然后始终将现有组 id 传递给序列化程序,并期望序列化程序中存在现有组 id。这意味着将一些验证逻辑移至视图(您至少需要检查是否为组字段提供了一个整数),但您不需要调整您的序列化程序。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-09-03
      • 1970-01-01
      • 1970-01-01
      • 2021-04-08
      • 2019-05-21
      • 2017-01-07
      • 1970-01-01
      • 2021-06-22
      相关资源
      最近更新 更多