我有一个版本化的模型(简化)看起来有点像:
Project(id, ref, version)
unique_together(ref, version)
其中id是自动生成的主键,ref是随机UUID,version是由我的应用程序递增的整数。每次保存项目时,我都会创建一个新实例,在版本中添加1并将ref复制到新对象。
以下SQL将通过执行subselect返回每个Project的最新版本。
SELECT * FROM myapp_project WHERE (ref, version) IN
(SELECT ref, max(version) FROM myapp_project GROUP BY ref)
或者(或许稍微简单):
SELECT * from myapp_project p
WHERE p.version =
(SELECT max(version) FROM myapp_project p1 WHERE p1.ref = p.ref)
如何使用Django的ORM实现相同的查询?
编辑:我已经达到了这个目标 -
foo = Project.objects.values('ref').annotate(version=Max('version'))
如果我检查它,这给了我一些看起来正确的东西。一旦我尝试将id输出:
foo.values('id')
似乎丢弃原始结果并返回所有行。
修改更多内容:
现在用.extra():
解决这个问题maxids = """id in (SELECT id from myapp_project p WHERE p.version =
(SELECT max(version) FROM myapp_project p1 WHERE p1.ref = p.ref))"""
Project.objects.all().extra(where=[maxids])
答案 0 :(得分:2)
使用in
以下是直接来自链接文档的示例
inner_qs = Blog.objects.filter(name__contains='Cheddar')
entries = Entry.objects.filter(blog__in=inner_qs)
您正在使用的确切查询不是所有使用Django的数据库都支持的查询。例如,虽然它适用于postgresql但它不适用于sqlite,因此您必须更改使用主键而不是unique_together键的方法。或者使用联接。
Update
第二个查询可以更轻松地处理,但我不会在此处发布,因为这似乎是对@anand的答案进行诽谤。
答案 1 :(得分:1)
您可以像这样构建它:
from django.db.models import Max
latest_refs_with_max_id = Project.objects.values('ref').annotate(Max('version'), Max('id')).values('id__max')
latest_refs = [ d['id__max'] for d in latest_refs_with_max_id]
q = Project.objects.filter(id__in=latest_refs)
注意:如果您有多条记录具有相同的最大version
和ref
答案 2 :(得分:1)
您可以执行以下操作:首先获取所有引用,然后为每个引用获得具有最高版本的项目:
projects = []
for ref in Project.objects.all().values_list('ref', flat=True).distinct():
projects.append(Project.objects.filter(ref=ref).order_by('-version')[0])
更高效的版本:
from django.db.models import Max
max_project_versions = Project.objects.values('ref').annotate(id_max=Max('version')).values_list('id_max', flat=True)
projects = Project.objects.filter(id__in=max_project_versions)