You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Django中替代含子查询原生SQL的ORM实现方案咨询

咨询:用Django ORM替代原生SQL查询的可行方案

原生SQL查询

SELECT id,
       title,
       date_format(books.timestamp,"%%Y/%%m/%%d") AS timestamp,
       (SELECT count(*) FROM pages WHERE pages.book_id=books.id) AS page_count
FROM books
ORDER BY books.timestamp DESC LIMIT %s

对应的Model代码(models.py)

class Book(models.Model):
    title     = models.CharField(max_length=64)
    timestamp = models.DateTimeField(auto_now_add=True)

class Page(models.Model):
    timestamp = models.DateTimeField(auto_now_add=True)
    book      = models.ForeignKey(Book, on_delete=models.CASCADE)

当前视图实现(views.py)

def something(request):
    n_books = 10
    books = Book.objects.raw(the_query, [n_books])
    return render(request, "books/list.html", {"books":books})

问题

我原本想通过filter()实现,但不知道如何处理子查询部分。请问有没有仅用Python代码的Django ORM等价实现方式?还是继续用原生SQL查询更好?

尝试后的报错

感谢@dostogircse171的建议,我在shell中尝试了类似方法,但出现如下错误:

In [1]: from django.db.models import F
In [2]: from book.models import Book
In [3]: Book.objects.annotate(t=F("timestamp")).values("t")
Out[3]: <QuerySet [{'t': datetime.datetime(2023, 3, 5, 15, 58, 21, 114352)}, {'t': 
datetime.datetime(2023, 3, 5, 16, 2, 48, 916458)}]>
In [4]: Book.objects.annotate(t=F("timestamp").strftime("%Y")).values("t")
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-4-6a25525e5bb4> in <module>
----> 1 Book.objects.annotate(t=F("timestamp").strftime("%Y")).values("t")
AttributeError: 'F' object has no attribute 'strftime'

Django ORM等价实现方案

完全可以用ORM实现需求,无需原生SQL,具体方案如下:

完整代码示例

from django.db.models import Count, Func, Value
from .models import Book

def something(request):
    n_books = 10
    books = Book.objects.annotate(
        # 数据库层面格式化日期为YYYY/MM/DD
        formatted_timestamp=Func(F('timestamp'), Value('%Y/%m/%d'), function='DATE_FORMAT'),
        # 统计关联的Page数量(利用外键反向关联)
        page_count=Count('page')
    ).order_by('-timestamp')[:n_books]
    
    return render(request, "books/list.html", {"books": books})

报错原因说明

你用F("timestamp").strftime("%Y")报错,是因为F()对象是数据库层面的表达式,不能直接调用Python的strftime方法。必须用Django提供的数据库函数(比如Func)来实现数据库端的日期格式化逻辑。

方案对比

  • ORM实现:可读性强,兼容Django的模型特性(自动迁移、跨数据库适配等),后续维护成本更低。
  • 原生SQL:仅推荐用于ORM无法表达的极复杂查询,否则ORM是更优选择。

内容的提问来源于stack exchange,提问作者Jihyun

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.29 03:23:26