Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/django/24.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Django合并表列的最大值_Django_Join_Merge_Union_Annotate - Fatal编程技术网

Django合并表列的最大值

Django合并表列的最大值,django,join,merge,union,annotate,Django,Join,Merge,Union,Annotate,我试图通过合并两个独立表的结果来获得最大值。我正在尝试获取一篇帖子的最新评论。我有一个模型注释,可以通过Post.comments访问。我还有一个独立于Post的body,Post.body可以访问它。当注释和正文都是DateTimeField时,它们都有一个字段。我想返回一个按最新活动排序的查询集,这样,带有最新评论或正文的帖子将首先显示 假设模型如下所示: class Body(models.Model): when = models.DateTimeField(default=da

我试图通过合并两个独立表的结果来获得最大值。我正在尝试获取一篇帖子的最新评论。我有一个模型注释,可以通过Post.comments访问。我还有一个独立于Post的body,Post.body可以访问它。当注释和正文都是DateTimeField时,它们都有一个字段。我想返回一个按最新活动排序的查询集,这样,带有最新评论或正文的帖子将首先显示

假设模型如下所示:

class Body(models.Model):
    when = models.DateTimeField(default=datetime.datetime.now)

class Post(models.Model):
    body = models.ForeignKey(Body)

class Comment(models.Model):
    post = models.ForeignKey(Post, related_name='comments')
    when = models.DateTimeField(default=datetime.datetime.now)
如果可能的话,我希望结果仍然是查询集,因为我会继续处理它,并进一步将其传递到分页器以限制结果

基本上,我希望能够打电话:

q = Post.annotate(
    activity=Max(
        Union('comments__when', 'body__when')
    )
)
q = q.order_by('-activity')
但我不知道如何实现这种结合

我相信实现我所寻找的目标的SQL可以与:

SELECT
...
IF(MAX(c.`when`), MAX(c.`when`), b.`when`) AS `activity`
...
FROM `post` p
...
LEFT OUTER JOIN `comment` AS c
ON c.`post_id`=p.`id`
LEFT OUTER JOIN `body` AS b
ON p.`body_id`=b.`id`
...

这样一个定制的注释和连接可以实现吗?

我花了很长时间才弄明白。一个大问题是Django不支持JOIN语句ON子句的多个条件。由于单个SELECT语句依赖于两个单独的联接,因此我们无法准确跟踪表名。当你要求django注释一个表时,比如用Max,你最终得到的条件是MaxT7.When。。。将联接表省略为T7,其中T7不一致。因此,当给定Django自动生成的联接时,我需要一种累积生成表达式MaxT7.0的方法。许多在线帖子都告诉您在QuerySet上使用.raw支持,但是在这种情况下,使用ORM会失去很多好处

我提出的解决方案是生成一个自定义聚合函数。我调用了这个函数CustomMax:

该功能的用途是:

q = Post.annotate(
    activity=CustomMax(
        'comments__when',
        alt_table="app_post",
        alt_field="when",
    )
)
q.query.join((
    'app_post',
    'app_comment',
    'id',
    'post_id',
))
q = q.order_by('-activity')
我包括.join以允许alt_表作为一个join存在,Django将自动处理Max部分的SELECT和join语句的命名。此用法生成的SQL类似于:

SELECT 
...
GREATEST(app_post.when, IFNULL(MAX(T7.`when`), app_post.when)) AS `activity`,
...
`app_post`.`id`
...
INNER JOIN `app_post` ON ...
...
LEFT OUTER JOIN `app_comment` T7 ON (`app_post`.`id` = T7.`post_id`)
...
注意:这仅适用于上面的帖子和评论模型。我的实际实现有点复杂,需要这个解决方案

如果Django团队开发了这个建议补丁,将join语句包含在其中,那么这也会容易得多。额外:

SELECT 
...
GREATEST(app_post.when, IFNULL(MAX(T7.`when`), app_post.when)) AS `activity`,
...
`app_post`.`id`
...
INNER JOIN `app_post` ON ...
...
LEFT OUTER JOIN `app_comment` T7 ON (`app_post`.`id` = T7.`post_id`)
...