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
相关产品推荐
相关产品推荐

