python - 修复 Django Rest Framework 模型序列化程序相关主键查询集中的错误
问题描述
我觉得我在这里追赶我的尾巴,所以我来找你们的好人来帮助我了解我在哪里搞砸了,为什么我对此的想法一定有某种缺陷。
我正在 DRF 中编写一个 API,虽然它在数据库中没有很多表,但数据库中有很多对多的关系,这让它感觉很复杂,或者至少很难只查看数据库表并直观地了解相关内容。
首先是我的模型。尝试将新对象发布到jobs
模型时,我得到了这个。我需要验证请求的工作人员是否有权job
使用相关target
和workergroup
楷模:
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 注释掉对它的引用,错误就会消失。但是,这会停止对该字段的验证,因此这不是一个可行的解决方案!
解决方案
我不是 100% 确定我在正确的轨道上,但似乎你可能有重复/多个结果的问题。您应该尝试使用.distinct()
in Queryset
(WorkerGroupPKSerializer
另请参阅Django文档)。您在模型ForeignKey
的customer
属性上使用了 a Worker
,这样就可以让多个Worker
' 属于与WorkerGroup
过滤器查询匹配的同一个,从而返回相同的WorkerGroup
两次。因此,当id
of thatWorkerGroup
被POST
编辑时,get()
将匹配两个结果,抛出该错误。
注释掉似乎清除了错误,这可能是因为你也在注释掉many=False
,因此.get()
不再被调用。但正如问题中提到的,这将禁用用于过滤的自定义查询集。
推荐阅读
- jhipster - 如何解密存储在数据库中并由 jhipster web-app 生成的密码?
- ruby-on-rails - Rails + GraphQl + Rspec
- ruby-on-rails - Kubernetes readinessProbe 返回“连接拒绝”
- python - 如何将文件文件夹移动到可变名称文件夹
- sql - 在 AWS Athena 中减去两个时间戳列
- node.js - 用一个后端 Nodejs 运行两个源前端 Reactjs
- asp.net-core - 使用当前版本的 System.Text.Json.JsonSerializer 序列化 DataSet
- php - laravel 使用 ajax 重定向
- ios - 带有 Parse 平台的 iOS 推送通知 - didRegisterForRemoteNotificationsWithDeviceToken - 从未调用
- java - 使用存储过程从输入 csv 文件将多个表创建到 oracle 数据库中