这是一个应用程序,它启用了一些协作审核功能,类似于Stackoverflow。
我有一个像这样的Django ORM查询:
versions = Version.objects.filter(is_reviewed=False).exclude(moderations__user__pk=request.user.id).order_by('content_type__id', 'object_id', '-number').distinct('content_type', 'object_id')
每个内容对象可以具有由用户创建的任意数量的版本。我在这里做的是获取来自其他用户的所有未经审核的版本,但每个内容对象只有最新版本。
但是我想添加另一个排除条件:如果内容对象具有is_reviewed=True
的较新版本,则不应返回以前的版本。应该退回未经审核的新版本。知道怎么做吗?
一些例子。我假设这里的所有版本都是针对相同的内容对象。
示例A
这应该返回第三行。按预期工作。
示例B
这应该返回第三行。按预期工作。
示例C
这应该返回第三行。按预期工作。
示例D
这应该返回没有行。目前这不起作用。它将返回第二行,而不是它的目的。
/编辑
以下是我的模型:http://sql.nopaste.dk/p48981
答案 0 :(得分:1)
我喜欢编写queryset方法来帮助解释我们正在尝试做什么,并从那里开始向后工作。
Version.objects.newest_by_content_type().unreviewed()
然后,我们只需要queryset / manager方法。 [注意:我正在使用Building a higher-level query API中描述的模式将这些方法添加到查询集中。
事实证明,这是你已经编写的代码,只是略有不同。
def newest_by_content_type(self):
return self.order_by('content_type__id', 'object_id', '-updated').distinct('content_type', 'object_id')
def unreviewed(self):
return self.filter(is_reviewed=False)
然后,您可以使用此查询集执行其他操作。例如,删除当前用户拥有的那些。
此答案的上一个版本使用superseded_by
或supersedes
自我关系讨论了另一种解决方案:
class Version(models.Model):
supersedes = models.ForeignKey('Version',
related_name='superseded_by', null=True, blank=True)
然后,您可以通过以下方式获取所有未被取代的对象:
Version.objects.filter(superseded_by=None)
根据约束条件,对于被取代的关系使用OneToOneField
可能是有意义的:如果版本最多只能被一个版本取代,并且版本可能只取代一个版本。例如,当尝试再次取代已被取代的对象时,也可以使用它和HTTP标头并返回412 Precondition Failed
。这对于版本链“直”而言是有意义的,并且不允许分支。