django

django原始sql查询

2018-08-26  本文已影响180人  陆_志东

row管理器方法用于原始的sql查询,并返回模型的实例

Manager.raw(raw_query, params=None, translations=None)
注意:使用管理器的raw方法,在写sql语句的时候,一定要带上主键的查询,因为django是通过主键来区分不同的实例的,所以其他字段可以省略,但是主键字段一定不能省略

示例:

假设存在以下模型
class Person(models.Model):
  first_name = models.CharField(...)
  last_name = models.CharField(...)
  birth_date = models.DateField(..)

可以照下面这样执行sql对上面模型的查询
>>> for p in Person.objects.raw('SELECT * FROM myapp_person'):
...     print(p)
John Smith
Jane Jones

这个sql可以看到和Person.objects.all()结果是一样的

注意上面的sql查询的表,是数据库中的表名,在执行数据库迁移的时候会在数据库生成数据表名字,默认是应用名_模型名,如果你在模型类元类选择里面添加了db_table设置的话就是db_table的表名

对于row方法来说.查询字段的顺序是不重要的

>>> Person.objects.raw('SELECT id, first_name, last_name, birth_date FROM myapp_person')
...
>>> Person.objects.raw('SELECT last_name, birth_date, first_name, id FROM myapp_person')
...
这两个查询语句的作用是一样的

如果你要查询的数据表字段和django的模型字段名字不一致,可以采用下面两种做法中的任一做法

比如你的其他表中存放了一些Person数据,可以这样使用raw
>>> Person.objects.raw('''SELECT first AS first_name,
...                              last AS last_name,
...                              bd AS birth_date,
...                              pk AS id,
...                       FROM some_other_table''')

或者使用raw的第三个参数,添加一个映射字典
>>> name_map = {'first': 'first_name', 'last': 'last_name', 'bd': 'birth_date', 'pk': 'id'}
>>> Person.objects.raw('SELECT first,last,bd,pk FROM some_other_table', translations=name_map)

延迟加载模型字段

如果你在使用raw方法查询字段的时候把字段没有放在要查询的字段里面.也可以访问到字段.
这是因为,写入了查询集的字段,可以能够直接使用,没有放在查询集里面的字段,django在使用的时候会自动去查询,不过不要这么做.这么做的后果就是增加查询的次数

>>> people = Person.objects.raw('SELECT id, first_name FROM myapp_person')

# 注意什么字段省略都能省略就是主键id字段不能省略
>>> for p in Person.objects.raw('SELECT id, first_name FROM myapp_person'):
...     print(p.first_name, # This will be retrieved by the original query
...           p.last_name) # This will be retrieved on demand
...
John Smith
Jane Jones
在访问last_name的时候,又进行了一次查询

传递参数使用它raw方法的第二个参数

为了防止sql注入,使用方法
>>> lname = 'Doe'
>>> Person.objects.raw('SELECT * FROM myapp_person WHERE last_name = %s', [lname])

在sql语句中使用%s占位符,然后在params参数中添加这些占位符对应的值
不过要注意params可以是列表也可以是元祖

注意row方法只是select,如果你想要执行update,insert,以及delete可以直接使用游标查询

django.db.connection对象提供了常规数据库连接的方式。为了使用数据库连接,先要调用connection.cursor()方法来获取一个游标对象之后,调用cursor.execute(sql, [params])来执行sql语句,调用cursor.fetchone()或者cursor.fetchall()来返回结果行。
也可以使用with上下文管理器.自动结束连接
例如:

from django.db import connection

def my_custom_sql(self):
    cursor = connection.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

sql语句转义%

注意由于占位符%s的存在,如果你的sql语句中要使用%,而不希望被理解为占位符,要写两个%%
来达到转义%的目的

cursor.execute("SELECT foo FROM bar WHERE baz = '30%'")
cursor.execute("SELECT foo FROM bar WHERE baz = '30%%' AND id = %s", [self.id])

如果你的django设置了多个数据库

你可以使用django.db.connections来获取针对特定数据库的连接(以及游标)对象。django.db.connections是一个类似于字典的对象,允许你通过它的别名获取特定的连接。

from django.db import connections
cursor = connections['my_db_alias'].cursor()
# Your code here...

添加列表转字典操作

默认情况下,Python DB API会返回不带字段的结果,这意味着你得到的是一个列表,而不是一个字典。花费一点性能代价之后,你可以返回一个字典形式的结果,像这样

def dictfetchall(cursor):
    "Returns all rows from a cursor as a dict"
    desc = cursor.description
    return [
        dict(zip([col[0] for col in desc], row))
        for row in cursor.fetchall()
    ]

下面是返回字典和返回列表的差别,也就是相当于把游标改为了字典游标DictCursor

>>> cursor.execute("SELECT id, parent_id FROM test LIMIT 2");
>>> cursor.fetchall()
((54360982L, None), (54360880L, None))

>>> cursor.execute("SELECT id, parent_id FROM test LIMIT 2");
>>> dictfetchall(cursor)
[{'parent_id': None, 'id': 54360982L}, {'parent_id': None, 'id': 54360880L}]

使用with管理连接

with connection.cursor() as c:
    c.execute(...)

等价于:
c = connection.cursor()
try:
    c.execute(...)
finally:
    c.close()
上一篇下一篇

猜你喜欢

热点阅读