Django 视图中的原始 SQL 查询

Posted

技术标签:

【中文标题】Django 视图中的原始 SQL 查询【英文标题】:Raw SQL queries in Django views 【发布时间】:2011-08-21 08:31:36 【问题描述】:

如何在views.py 中使用原始 SQL 执行以下操作?

from app.models import Picture

def results(request):
    all = Picture.objects.all()
    yes = Picture.objects.filter(vote='yes').count()
    return render_to_response('results.html', 'picture':picture, 'all':all, 'yes': yes, context_instance=RequestContext(request))

results 函数会是什么样子?

【问题讨论】:

为什么要使用原始 sql 来进行过滤和计数? 这种情况没有实际原因。只是为了看看/知道怎么做。 【参考方案1】:
>>> from django.db import connection
>>> cursor = connection.cursor()
>>> cursor.execute('''SELECT count(*) FROM people_person''')
1L
>>> row = cursor.fetchone()
>>> print row
(12L,)
>>> Person.objects.all().count()
12

使用 WHERE 子句过滤赞成票:

>>> cursor.execute('''SELECT count(*) FROM people_person WHERE vote = "yes"''')
1L

【讨论】:

非常有用!谢谢!我用rows = cursor.fetchall()【参考方案2】:

The Django Documentation is really really good. 执行原始 SQL 基本上有两种选择。您可以使用Manager.raw() 执行返回模型实例的原始查询,也可以避开模型层直接执行自定义SQL。

使用raw() 管理器:

>>> for p in Person.objects.raw('SELECT * FROM myapp_person'):
...     print p
John Smith
Jane Jones

如果要直接绕过模型层,可以使用django.db.connection,代表默认数据库连接:

def my_custom_sql():
    from django.db import connection, transaction
    cursor = connection.cursor()

    # Data modifying operation - commit required
    cursor.execute("UPDATE bar SET foo = 1 WHERE baz = %s", [self.baz])
    transaction.commit_unless_managed()

    # Data retrieval operation - no commit required
    cursor.execute("SELECT foo FROM bar WHERE baz = %s", [self.baz])
    row = cursor.fetchone()

    return row

【讨论】:

+1 很好的解释,你能用 raw 返回一个计数吗? 不,它返回一个RawQuerySet,只有在你想返回一个模型实例时才有用。要执行count(*) 或您不想返回模型实例的任何其他操作,最好使用django.db.connection【参考方案3】:

如果您使用的是 PostgreSQL,则可以在一个查询中完成。 如果没有,您可以相应地更改查询并获取结果。

from django.db import connection
from app.models import Picture

def results(request):
    with connection.cursor() as cursor:
        query = """
        SELECT count(*) as all_count, 
        count(*) FILTER(WHERE vote = 'yes') as yes_count
        FROM people_person;
        """
        cursor.execute(query)
        row = cursor.fetchone()
        all_count, yes_count = row

【讨论】:

【参考方案4】:

你可以试试这个

Picture.objects.raw("SELECT 1 as id ,"\
 "(SELECT  count(*) as yes FROM people_person WHERE vote='yes') as yes ,"\
 "(SELECT  count(*) FROM people_person WHERE vote='no') as no ,"\
 "(SELECT  count(*) FROM people_person WHERE vote='all') as all ")

【讨论】:

这是一个脆弱的技巧,因为它只适用于整数主键(例如不是 uuid) 当我使用这种方式运行原始 SQL 时,我得到 NameError: name 'MyModel' is not defined。在 django ORM 的上下文下如何运行?【参考方案5】:

具有特定数据库名称的原始 sql:

from django.db import connections
cursor = connections['database_name'].cursor()
cursor.execute("select * from table_name")

database_name = 我们创建的任何数据库

table_name = 我们创建的任何表名

【讨论】:

【参考方案6】:

raw() 方法可用于执行返回模型实例的原始 sql 查询 ..see docs

books = Book.objects.raw('SELECT id,name,pages FROM app_books WHERE pages>100')

如果您执行的查询不能完全映射到模型.. django.db.connection 代表默认数据库连接,所以调用 connection.cursor() 使用数据库连接。 see docs

from django.db import connection
def my_custom_sql(self):
    with connection.cursor() as cursor:
        cursor.execute("UPDATE bar SET foo = 1 WHERE baz = %s", [self.baz])
        cursor.execute("SELECT foo FROM bar WHERE baz = %s", [self.baz])
        row = cursor.fetchone()

    return row

【讨论】:

以上是关于Django 视图中的原始 SQL 查询的主要内容,如果未能解决你的问题,请参考以下文章

为啥 Django 在更改列表视图页面中进行不必要的 SQL 查询?

视图的概述

如何将原始 SQL 转换为 Yii2,如查找查询

mybatis调用视图和存储过程

如何将数据从回调传递到Django中的另一个视图?

Django 视图中的大量查询