首页 > 解决方案 > 修复 Django Rest Framework 模型序列化程序相关主键查询集中的错误

问题描述

我觉得我在这里追赶我的尾巴,所以我来找你们的好人来帮助我了解我在哪里搞砸了,为什么我对此的想法一定有某种缺陷。

我正在 DRF 中编写一个 API,虽然它在数据库中没有很多表,但数据库中有很多对多的关系,这让它感觉很复杂,或者至少很难只查看数据库表并直观地了解相关内容。

首先是我的模型。尝试将新对象发布到jobs模型时,我得到了这个。我需要验证请求的工作人员是否有权job使用相关targetworkergroup

楷模:

class Workers(models.Model):
    class Meta:
        ordering = ['id']
    workerid = models.CharField(max_length=16, verbose_name="Worker ID", unique=True, default="Empty")
    customer = models.ForeignKey(Customers, on_delete=models.DO_NOTHING, default=1)
    workername = models.CharField(max_length=64, verbose_name="Worker Friendly Name", default="")
    datecreated = models.DateTimeField(auto_now_add=True)
    awsarn = models.CharField(max_length=60, verbose_name="ARN Name of Worker", blank=True, null=True)
    customerrights = models.ManyToManyField(Customers, related_name="access_rights", default="")


class Targets(models.Model):
    class Meta:
        ordering = ['id']
    customer = models.ForeignKey(Customers, on_delete=models.SET_NULL, default=1, null=True)
    friendly_name = models.CharField(max_length=70, verbose_name="Target Friendly Name", unique=False)
    hostname = models.CharField(max_length=120, verbose_name="Target Hostname", default="")
    ipaddr = models.GenericIPAddressField(protocol='both', unpack_ipv4=True, default="", null=True)


class WorkerGroups(models.Model):
    class Meta:
        ordering = ['id']
    name = models.CharField(max_length=60, default="Default Group")
    workers = models.ManyToManyField(Workers)


class Jobs(models.Model):
    target = models.ForeignKey(Targets, on_delete=models.DO_NOTHING)
    datecreated = models.DateTimeField(auto_now_add=True)
    startdate = models.DateTimeField()
    enddate = models.DateTimeField(null=True)
    frequency = models.TimeField(default='00:05')
    workergroup = models.ForeignKey(WorkerGroups, on_delete=models.DO_NOTHING)
    jobdefinition = models.ForeignKey(JobDefinitions, on_delete=models.DO_NOTHING)

在我的序列化程序中,我有一个JobSerializer引用 PrimaryKeyRelatedField 类,我认为它应该具有限制验证这些相关模型的查询集的效果。顺便说一句,customerrightsids正在视图中构建,这似乎适用于所有其他模型。

序列化器:

    def get_queryset(self):
        print("In Custom TargetPK get_queryset")
        queryset = Targets.objects.filter(customer_id__in=self.context['auth'].customerrightsids)
        if isinstance(queryset, (QuerySet, Manager)):
            queryset = queryset.all()
        return queryset


class WorkerGroupPKSerializer(serializers.PrimaryKeyRelatedField):

    def get_queryset(self):
        print("In Custom WorkerGroupPK get_queryset")
        queryset = WorkerGroups.objects.filter(workers__customer_id__in=self.context['auth'].customerrightsids)
        if isinstance(queryset, (QuerySet, Manager)):
            queryset = queryset.all()
        return queryset

class JobSerializer(serializers.ModelSerializer):
    workergroup = WorkerGroupPKSerializer(many=False) # Commenting this out removes error
    target = TargetPKSerializer(many=False) # This seems to work fine even though it's similar to the line above

    class Meta:
        model = Jobs
        fields = '__all__'

    def create(self, validated_data):
        print(self.context['auth'])
        return super().create(validated_data)

viewset 对象的 create 方法没有什么特别之处。它接受请求并将一对传递给 ViewSet 并更新其上下文。如果需要,我可以分享,但这似乎不是问题所在。

所以最后,对于错误。当我执行POST到时,/jobs/我得到以下信息:

错误:

MultipleObjectsReturned at /jobs/
get() returned more than one WorkerGroups -- it returned 2!

该错误清楚地表明我在 get() 中返回了多个 WorkerGroups,但在这种情况下我不知道在哪里或如何解决它。

这显然是 WorkerGroupPKSerializer 的问题。如果我从 JobSerializer 注释掉对它的引用,错误就会消失。但是,这会停止对该字段的验证,因此这不是一个可行的解决方案!

标签: pythondjangodjango-rest-framework

解决方案


我不是 100% 确定我在正确的轨道上,但似乎你可能有重复/多个结果的问题。您应该尝试使用.distinct()in QuerysetWorkerGroupPKSerializer另请参阅Django文档)。您在模型ForeignKeycustomer属性上使用了 a Worker,这样就可以让多个Worker' 属于与WorkerGroup过滤器查询匹配的同一个,从而返回相同的WorkerGroup两次。因此,当idof thatWorkerGroupPOST编辑时,get()将匹配两个结果,抛出该错误。

注释掉似乎清除了错误,这可能是因为你也在注释掉many=False,因此.get()不再被调用。但正如问题中提到的,这将禁用用于过滤的自定义查询集。


推荐阅读