Django过滤器问题多对多
Posted
技术标签:
【中文标题】Django过滤器问题多对多【英文标题】:Django Filter Issue Many to Many 【发布时间】:2021-04-07 18:51:14 【问题描述】:我遇到了一个问题,即使用多对多查找的链式过滤器未按预期执行。以下是相关细节:
views.py
def cs_edit_result(request, ctype=None, survey_id=None):
#if POST request resume answering survey answers from a selected customer survey.
if request.method == 'GET':
sid = Survey.objects.get(pk=survey_id)
if request.method == 'POST':
sid = Survey.objects.get(pk=survey_id)
form = CustomerSurveyForm(request.POST, instance=sid)
#filter placeholders to only form data from customer survey:
if form.is_valid():
cs_result = form.save()
answers = SurveyAnswers.objects.filter(surveyid=sid.id)
for x in answers:
x.status=False
x.save()
print(form)
citype = form.cleaned_data['institution_type']
cproducts = form.cleaned_data['products']
cpurchases = form.cleaned_data['purchase']
cservices = form.cleaned_data['services']
colb = form.cleaned_data['olb_vendor']
cph1 = SurveyAnswers.objects.filter(surveyid=cs_result).filter(
Q(placeholder__purchase__in=cpurchases),
Q(placeholder__institution_type__in=citype),
Q(placeholder__olb_vendor__in=colb),
models.py
class PlaceHolder(models.Model):
output_choices = [
('link','Link'),
('plain text', 'Plain Text'),
('html', 'HTML')
]
purchase = models.ManyToManyField(Purchase, related_name='purchase_place')
institution_type = models.ManyToManyField(InstitutionType, related_name='itype_place')
products = models.ManyToManyField(Product,blank=True, related_name='products_place')
services = models.ManyToManyField(Service,blank=True, related_name='services_place')
olb_vendor = models.ManyToManyField(OLB_Vendor,blank=True, related_name='olb_place')
output_type = models.ManyToManyField(Output_Type)
question = models.TextField(null=True, verbose_name = 'question/title')
silvercloud_placeholder = models.CharField(max_length=50)
output_type = models.CharField(
max_length=100,
choices= output_choices,
default='Plain Text')
answer = models.TextField(blank=True,null=True, verbose_name='url/answer')
def __str__(self):
return self.silvercloud_placeholder
class Survey(models.Model):
customer = models.CharField(max_length=50)
purchase = models.ManyToManyField(Purchase)
institution_type = models.ManyToManyField(InstitutionType)
products = models.ManyToManyField(Product)
services = models.ManyToManyField(Service,blank=True)
olb_vendor = models.ManyToManyField(OLB_Vendor)
def __str__(self):
return (' Survey '.format(self.customer, str(self.id)))
class SurveyAnswers(models.Model):
#contributor = admin.
surveyid = models.ForeignKey(Survey,on_delete=models.CASCADE)
placeholder = models.ForeignKey(PlaceHolder,on_delete=models.CASCADE)
answer = models.TextField(blank=True,null=True)
status = models.BooleanField(default=False)
class meta:
constraints = [
models.UniqueConstraint(fields=['surveyid', 'placeholder'], name='Unique Answer')
]
def __str__(self):
return (' Survey '.format(self.surveyid.customer, str(self.surveyid.id),self.placeholder.silvercloud_placeholder))
所以问题是 cph1 不会返回适当的 SurveyAnswer 对象。如果我删除除了一个 Q 对象之外的所有对象,则预期的 SurveyAnswer 将在查询集中返回,但是一旦我添加第二个 Q 对象,过滤器不会满足预期的调查答案。任何帮助将不胜感激。如果有任何遗漏的细节,我可以添加它们。
【问题讨论】:
【参考方案1】:filter
参数默认与AND
组合。如果您正在寻找OR
,您可以使用|
运算符组合Q 对象:
cph1 = SurveyAnswers.objects.filter(surveyid=cs_result).filter(
Q(placeholder__purchase__in=cpurchases) |
Q(placeholder__institution_type__in=citype) |
Q(placeholder__olb_vendor__in=colb) |
)
【讨论】:
感谢您的回复。这不是问题。我需要过滤器才能使用 AND 运算符。问题是 SurveyAnswer[x] 符合 Q(placeholder__purchase__in=cpurchases) 的标准。它也符合 Q(placeholder__institution_type__in=citype) 的标准。但是当我有这样的系列过滤器时,SurveyAnswer[x] 不会返回。 而且还满足placeholder__olb_vendor__in=colb
?我认为它可能是 OR 而不是 AND 的原因是因为 Q
对象在这种情况下不是必需的,因为 AND
是默认值,您可以将它们直接传递给 filter
。但是您对它应该如何工作的理解是正确的,因此请仔细检查 SurveryAnswer[x]
是否确实满足这些条件。可能是您的表单数据格式不正确,无法处理您的查询,或者 null
值没有得到正确考虑。
form.cleaned_data[x] 是问题所在。我需要将该数据类型转换为 ID 列表。然后在我的过滤器中使用 ID 字段(例如:placeholder__purchase__id__in=cpuchase_id_list)。感谢您指出这可能是问题所在。我被困了一段时间。
cpurchase 是一个查询集。所以我做了一个循环把它转换成一个列表: cpurchases = form.cleaned_data['purchase'] purchase_list = [] for x in cpurchases: purchase_list.append(x.id) print(purchase_list) 我为每个表单键。有没有更好的方法从查询集中获取 Id?也许在一行中而不是一个 for 循环?
是的!你可以使用cpurchases.values_list('id', flat=True)
以上是关于Django过滤器问题多对多的主要内容,如果未能解决你的问题,请参考以下文章