是否有一种简单的方法来查询对象的反向关系过滤,如果该对象尚不存在,则该值是默认值?
让我用一个例子详细说明。
我有以下基本型号型号:
class Delegation(models.Model):
name = models.CharField(unique=True,max_length=4)
country = models.CharField(unique=True,max_length=100)
members = models.ManyToManyField(User, blank=True)
class Exam(models.Model):
name = models.CharField(max_length=100, unique=True)
active = models.BooleanField(default=True)
现在我需要存储有关某些操作的信息,基本上如果操作仍在进行中或已完成(提交)。出于这个原因,我使用了一个链接到两个模型的模型。
class ExamAction(models.Model):
OPEN = 'O'
SUBMITTED = 'S'
STATUS_CHOICES = ((OPEN, 'In progress'), (SUBMITTED, 'Submitted'))
TRANSLATION = 'T'
POINTS = 'P'
ACTION_CHOICES = ((TRANSLATION, 'Translation submission'), (POINTS, 'Points submission'))
exam = models.ForeignKey(Exam)
delegation = models.ForeignKey(Delegation)
action = models.CharField(max_length=2, choices=ACTION_CHOICES)
status = models.CharField(max_length=1, choices=STATUS_CHOICES, default=OPEN)
timestamp = models.DateTimeField(auto_now=True)
class Meta:
unique_together = (('exam', 'delegation', 'action'),)
我的问题是查询变得非常复杂,因为(目前)我认为该操作尚未在数据库中列出,我将假设其默认值为ExamAction.OPEN
。
对于一个具体的例子,我现在使用这个来查询仍然为代表团开放的考试列表:
exams_open = Exam.objects.filter((Q(examaction__delegation=delegation) & Q(examaction__action=ExamAction.TRANSLATION) & Q(examaction__status=ExamAction.OPEN))
| Q(examaction__isnull=True), active=True, )
我认为上述查询也是错误的,因为如果Exam
与ExamAction
和action=TRANSLATION
没有delegation=delegation
,它应返回ExamAction.objects.get_or_create()
个对象,但它不会如果已经存储了另一个动作(具有任何值)。
我很确定我不是第一个遇到这个设计问题的人,我认为必须存在一个更简单的实现。但是什么?
我目前正在考虑的是:
ExamAction
Exam
对象时生成所有可能的through=ExamAction
。这意味着所有代表团都要循环。
<html>
<head>
<title>DZ Prototype</title>
<link rel="icon" type="img/ico" href="images/favicon.jpg">
</head>
<body>
<center>
<h1>Welcome to DZ Prototype Testing Area!!</h1>
</center>
<p></p>
<p></p>
<p></p>
<p style="text-align:center"><img src="http://images1.knowable.com/live/articles/2_1ec282dc7578c9356aef339b8b98bbe9.gif" alt="It works!!"></p>
<p></p>
<p></p>
<div align="center">
<?php
//$theFile = "cowrie.txt";
//$line = file($theFile);
//echo $line[18];
// Simulated line array for demonstraiton purposes
$line = array("ewfefe", "ewfewfewf", "54g5grthrhryt", "Incorrectly Classified Instances 1 100 %");
if (trim($line[3]) == "Incorrectly Classified Instances 1 100 %") {
echo "<h2><font color=red>Possible Malicious Login Attempt</h2>";
} else {
echo "<h2><font color=green>Status Green</h2>";
}
?>
</div>
</body>
</html>
的ManyToMany关系是否有助于这种情况?我不这么认为,因为我仍然应该查询具有所需(默认)值或尚不存在的ExamAction。非常感谢。
答案 0 :(得分:0)
如果我正确理解了您想要的查询,我会像这样(这里作为Manager
上的自定义方法):
# UPDATE: Bugfix thanks to Mic D.
class ExamManager(models.Manager):
def open_exams(delegation, action):
return Exam.objects.exclude(
examaction__in=ExamAction.objects.filter(
delegation=delegation,
action=action,
status=ExamAction.SUBMITTED,
)
).distinct()
所以这还不错。
简要介绍一下您提出的解决方案:
如您所知,这一次只能在一行上运行。
对于大多数这样的问题,这就是我的建议。但是在你的情况下,它会以二次方式增加数据库的大小,当你添加一个新的委托时,它会使生活变得更加复杂。
ManyToManyField
只是一些语法糖,在这里对你没有任何帮助。
这可能是一个好主意,但这里没有足够的信息可以提出任何建议。
所以我认为你的方法实际上非常合理,你只需要弄清楚正确的查询。
答案 1 :(得分:0)
我最终使用的查询是:
Find
这是受Kevin Christopher Henry的启发,但我发现它有一个错误。为了调试它,我实际上必须使用exams_open = Exam.objects.exclude(
examaction__in=ExamAction.objects.filter(
delegation=delegation,
action=ExamAction.TRANSLATION,
status=ExamAction.SUBMITTED)
).distinct()
打印生成的查询。差异非常微妙,但就我而言,它产生了巨大的差异。
查询错误:
print QuerySet.query
输出:
print Exam.objects.exclude(
examaction__delegation=delegation,
examaction__action=action,
examaction__status=ExamAction.SUBMITTED,
).query
此处符合任何SELECT "app_exam"."id",
"app_exam"."name"
FROM "app_exam"
WHERE NOT ( "app_exam"."id" IN (SELECT U1."exam_id" AS Col1
FROM "app_examaction" U1
WHERE U1."action" = t)
AND "app_exam"."id" IN (SELECT U1."exam_id" AS Col1
FROM "app_examaction" U1
WHERE U1."delegation_id" = 1)
AND "app_exam"."id" IN (SELECT U1."exam_id" AS Col1
FROM "app_examaction" U1
WHERE U1."status" = s) )
语句的任何考试都会被删除。
正确查询:
exclude()
输出:
print Exam.objects.exclude(
examaction__in=ExamAction.objects.filter(
delegation=delegation,
action=ExamAction.TRANSLATION,
status=ExamAction.SUBMITTED)
).query
这里我们只正确地排除了一次考试。