python - 使用有序相关模型的第一个值来注释QuerySet

我有一些对象。对于每一个,我都希望用相关模型的最小值进行注释(在几个条件下结合,按日期排序)。我可以用SQL简洁地表达我想要的结果,但是我很好奇如何将其转换为Django的ORM。
背景
假设我有两个相关的模型:QuerySetBook,每个模型都有一个foreign key to anBlogPost

class Book(models.Model):
    title = models.CharField(max_length=255)
    genre = models.CharField(max_length=63)
    author = models.ForeignKey(Author)
    date_published = models.DateField()

class BlogPost(models.Model):
    author = models.ForeignKey(Author)
    date_published = models.DateField()

我试图找到第一本神秘的书,一个给定的作者发表在他们写的每一篇博文之后。在SQL中,这可以通过窗口化很好地实现。
PostgreSQL 9.6中的工作解决方案
WITH ordered AS (
  SELECT blog_post.id,
         book.title,
         ROW_NUMBER() OVER (
            PARTITION BY blog_post.id ORDER BY book.date_published
         ) AS rn
    FROM blog_post
         LEFT JOIN book ON book.author_id = blog_post.author_id
                       AND book.genre = 'mystery'
                       AND book.date_published >= blog_post.date_published
)
SELECT id,
       title
  FROM ordered
 WHERE rn = 1;

翻译成Django的ORM
虽然上面的SQL很适合我的需要(如果需要,我可以使用原始SQL),但是我很好奇在查询集中如何做到这一点。我有一个现有的查询集,我想在其中进一步注释它
books = models.Book.objects.filter(...).select_related(...).prefetch_related(...)
annotated_books = books.annotate(
    most_recent_title=...
)

我知道Django2.0支持窗口功能,但我现在使用的是Django1.10。
尝试的解决方案
我首先构建了一个Author对象来过滤在博客帖子之后发布的神秘书籍。
published_after = Q(
    author__book__date_published__gte=F('date_published'),
    author__book__genre='mystery'
)

从这里开始,我试图拼凑出我想要的结果,但是没有成功。
注意:Django2.0引入了窗口表达式,但我现在在Django1.10上,我想知道如何使用那里可用的查询集功能来实现这一点。


最佳答案:

也许使用.raw不是一个坏主意。检查代码是否存在Window class我们可以看到,这实质上构成了一个SQL查询来实现“窗口化”。
一个简单的方法可能是使用architect模块,该模块可以根据the documentation为PostgreSQL添加分区功能。
另一个声称向django<2.0注入窗口功能的模块是django-query-builder,它添加了一个partition_by()查询集方法,可以与order_by一起使用:

query = Query().from_table(
    Order,
    ['*', RowNumberField(
              'revenue', 
              over=QueryWindow().order_by('margin')
                                .partition_by('account_id')
          )
    ]
)
query.get_sql()
# SELECT tests_order.*, ROW_NUMBER() OVER (PARTITION BY account_id ORDER BY margin ASC) AS revenue_row_number
# FROM tests_order

最后,您可以复制项目中的类源代码或使用窗口类代码。

译文:来源   文章分类: python django postgresql django-queryset django-1.10

相关文章:

python - Python实现BLAST对齐算法? [关闭]

python - 使用countVectorizer计算跳过图频率

python - 循环通过netcdf文件并运行计算 - Python或R.

python - 成对映射一个numpy数组

python - 创建新的Pandas专栏,其中仅包含另一列的年份

python - 为什么numpy.any对大型数组这么慢?

python - 如何直接打印到python 2.x和3.x中的文本文件?

python - reload(sys)导致随后的执行丢失其`Out [n]:`标签

python - python中的Bunch和Dictionary类型有什么区别?

python - 当您绘制数据而不是图像时,它会显示。方面和范围之间的实现?