在线观看不卡亚洲电影_亚洲妓女99综合网_91青青青亚洲娱乐在线观看_日韩无码高清综合久久

鍍金池/ 教程/ Python/ 進(jìn)行原始的sql查詢
編寫自定義存儲系統(tǒng)
高級
編寫你的第一個Django應(yīng)用,第5部分
視圖層
Django管理文檔生成器
編寫你的第一個 Django 程序 第3部分
編寫你的第一個Django應(yīng)用,第6部分
模型層
中間件
測試
數(shù)據(jù)庫訪問優(yōu)化
文件上傳
中間件
驗證器
基于類的內(nèi)建通用視圖
部署靜態(tài)文件
使用Django認(rèn)證系統(tǒng)
高級教程:如何編寫可重用的應(yīng)用
Model 類參考
Django 初探
使用Django輸出PDF
模型的實例
模型
文件上傳
進(jìn)行原始的sql查詢
面向程序員
中間件
編寫數(shù)據(jù)庫遷移
TemplateResponse 和 SimpleTemplateResponse
異常
Django中的測試
基礎(chǔ)
管理器
File對象
URL調(diào)度器
加密簽名
國際化和本地化
日志
查詢集
django-admin 和 manage.py
使用基于類的視圖處理表單
聚合
內(nèi)建基于類的視圖的API
如何使用會話
部署 Django
其它
其它核心功能
高級
Django中的密碼管理
模型元選項
按需內(nèi)容處理
查找 API 參考
高級
Django 的快捷函數(shù)
Django 的設(shè)置
Admin
開發(fā)過程
新手入門
基于類的視圖
模型實例參考
信號
表單素材 ( <code>Media</code> 類)
自定義查找
常見的網(wǎng)站應(yīng)用工具
模型
django.contrib.humanize
Django模版語言
點擊劫持保護(hù)
管理操作
編寫你的第一個 Django 程序 第2部分
Django安全
模式編輯器
多數(shù)據(jù)庫
部署
基于類的視圖
內(nèi)建的視圖
視圖裝飾器
面向設(shè)計師
編寫視圖
應(yīng)用程序
如何使用WSGI 部署
參考
表單 API
文件儲存API
認(rèn)證
國際化和本地化
錯誤報告
基礎(chǔ)
基礎(chǔ)
將遺留數(shù)據(jù)庫整合到Django
教程
Django異常
編寫你的第一個 Django 程序 第4部分
遷移
分頁
重定向應(yīng)用
表單
從零開始
為模型提供初始數(shù)據(jù)
設(shè)置
使用Django輸出CSV
關(guān)聯(lián)對象參考
使用表單
Django 中的用戶認(rèn)證
快速安裝指南
安全問題歸檔
數(shù)據(jù)庫函數(shù)
編寫自定義的django-admin命令
高級教程
管理文件
格式本地化
基于類的通用視圖 —— 索引
安全
系統(tǒng)檢查框架
為Django編寫首個補丁
模板層
Widgets
編寫你的第一個 Django 程序 第1部分
執(zhí)行查詢

進(jìn)行原始的sql查詢

模型查詢API不夠用的情況下,你可以使用原始的sql語句。django提供兩種方法使用原始sql進(jìn)行查詢:一種是使用Manager.raw()方法,進(jìn)行原始查詢并返回模型實例;另一種是完全避開模型層,直接執(zhí)行自定義的sql語句。

警告

編寫原始的sql語句時,應(yīng)該格外小心。每次使用的時候,都要確保轉(zhuǎn)義了參數(shù)中的任何控制字符,以防受到sql注入攻擊。更多信息請參閱防止sql注入。

進(jìn)行原始查詢

raw()方法用于原始的sql查詢,并返回模型的實例:

Manager.raw(raw_query, params=None, translations=None)

這個方法執(zhí)行原始的sql查詢之后,返回django.db.models.query.RawQuerySet的實例。RawQuerySet實例可以像一般的QuerySet那樣,通過迭代來提供對象的實例。

這里最好通過例子展示一下,假設(shè)存在以下模型:

class Person(models.Model):
    first_name = models.CharField(...)
    last_name = models.CharField(...)
    birth_date = models.DateField(...)

你可以像這樣執(zhí)行自定義的sql語句:

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

當(dāng)然,這個例子不是特別有趣,和直接使用Person.objects.all()的結(jié)果一模一樣。但是,raw()擁有其它更強大的使用方法。

模型表的名稱

在上面的例子中,Person表的名稱是從哪里得到的?

通常,Django通過將模型的名稱和模型的“應(yīng)用標(biāo)簽”(你在manage.py startapp中使用的名稱)進(jìn)行關(guān)聯(lián),用一條下劃線連接他們,來組合表的名稱。在這里我們假定Person模型存在于一個叫做myapp的應(yīng)用中,所以表就應(yīng)該叫做myapp_person。

更多細(xì)節(jié)請查看db_table選項的文檔,它也可以讓你自定義表的名稱。

警告

傳遞給raw()方法的sql語句并沒有任何檢查。django默認(rèn)它會返回一個數(shù)據(jù)集,但這不是強制性的。如果查詢的結(jié)果不是數(shù)據(jù)集,則會產(chǎn)生一個錯誤。

警告

如果你在mysql上執(zhí)行查詢,注意在類型不一致的時候,mysql的靜默類型強制可能導(dǎo)致意想不到的結(jié)果發(fā)生。如果你在一個字符串類型的列上查詢一個整數(shù)類型的值,mysql會在比較前強制把每個值的類型轉(zhuǎn)成整數(shù)。例如,如果你的表中包含值'abc''def',你查詢'where mycolumn=0',那么兩行都會匹配。要防止這種情況,在查詢中使用值之前,要做好正確的類型轉(zhuǎn)換。

警告

雖然RawQuerySet可以像普通的QuerySet一樣迭代,RawQuerySet并沒有實現(xiàn)可以在QuerySet上使用的所有方法。例如,__bool__()__len__()RawQuerySet中沒有被定義,所以所有RawQuerySet轉(zhuǎn)化為布爾值的結(jié)果都是True。RawQuerySet中沒有實現(xiàn)他們的原因是,在沒有內(nèi)部緩存的情況下會導(dǎo)致性能下降,而且增加內(nèi)部緩存不向后兼容。

將查詢字段映射到模型字段

raw()方法自動將查詢字段映射到模型字段。

字段的順序并不重要。換句話說,下面兩種查詢的作用相同:

>>> 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會根據(jù)名字進(jìn)行匹配。這意味著你可以使用sql的as子句來映射二者。所以如果在其他的表中有一些Person數(shù)據(jù),你可以很容易地把它們映射成Person實例。

>>> Person.objects.raw('''SELECT first AS first_name,
...                              last AS last_name,
...                              bd AS birth_date,
...                              pk AS id,
...                       FROM some_other_table''')

只要名字能對應(yīng)上,模型的實例就會被正確創(chuàng)建。 又或者,你可以在raw()方法中使用翻譯參數(shù)。翻譯參數(shù)是一個字典,將表中的字段名稱映射為模型中的字段名稱、例如,上面的查詢可以寫成這樣:

>>> name_map = {'first': 'first_name', 'last': 'last_name', 'bd': 'birth_date', 'pk': 'id'}
>>> Person.objects.raw('SELECT * FROM some_other_table', translations=name_map)

索引訪問

raw()方法支持索引訪問,所以如果只需要第一條記錄,可以這樣寫:

>>> first_person = Person.objects.raw('SELECT * FROM myapp_person')[0]

然而,索引和切片并不在數(shù)據(jù)庫層面上進(jìn)行操作。如果數(shù)據(jù)庫中有很多的Person對象,更加高效的方法是在sql層面限制查詢中結(jié)果的數(shù)量:

>>> first_person = Person.objects.raw('SELECT * FROM myapp_person LIMIT 1')[0]

延遲加載模型字段

字段也可以被省略:

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

查詢返回的Person對象是一個延遲的模型實例(請見 defer())。這意味著被省略的字段,在訪問時才被加載。例如:

>>> 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

從表面上來看,看起來這個查詢獲取了first_namelast_name。然而,這個例子實際上執(zhí)行了3次查詢。只有first_name字段在raw()查詢中獲取,last_name字符按在執(zhí)行打印命令時才被獲取。

只有一種字段不可以被省略,就是主鍵。Django 使用主鍵來識別模型的實例,所以它在每次原始查詢中都必須包含。如果你忘記包含主鍵的話,會拋出一個InvalidQuery異常。

增加注解

你也可以在查詢中包含模型中沒有定義的字段。例如,我們可以使用PostgreSQL的age()函數(shù)來獲得一群人的列表,帶有數(shù)據(jù)庫計算出的年齡。

>>> people = Person.objects.raw('SELECT *, age(birth_date) AS age FROM myapp_person')
>>> for p in people:
...     print("%s is %s." % (p.first_name, p.age))
John is 37.
Jane is 42.
...

raw() 方法中傳遞參數(shù)

如果你需要參數(shù)化的查詢,可以向raw() 方法傳遞params參數(shù)。

>>> lname = 'Doe'
>>> Person.objects.raw('SELECT * FROM myapp_person WHERE last_name = %s', [lname])

params是存放參數(shù)的列表或字典。你可以在查詢語句中使用%s占位符,或者對于字典使用%(key)占位符(key會被替換成字典中鍵為key的值),無論你的數(shù)據(jù)庫引擎是什么。這樣的占位符會被替換成參數(shù)表中正確的參數(shù)。

注意

SQLite后端不支持字典,你必須以列表的形式傳遞參數(shù)。

警告

不要在原始查詢中使用字符串格式化!

它類似于這種樣子:

>> query = 'SELECT * FROM myapp_person WHERE last_name = %s' % lname
>> Person.objects.raw(query)

使用參數(shù)化查詢可以完全防止sql注入,一種普遍的漏洞使攻擊者可以向你的數(shù)據(jù)庫中注入任何sql語句。如果你使用字符串格式化,早晚會受到sql輸入的攻擊。只要你記住默認(rèn)使用參數(shù)化查詢,就可以免于攻擊。

直接執(zhí)行自定義sql

有時Manager.raw()方法并不十分好用,你不需要將查詢結(jié)果映射成模型,或者你需要執(zhí)行UPDATEINSERT以及DELETE查詢。

在這些情況下,你可以直接訪問數(shù)據(jù)庫,完全避開模型層。

django.db.connection對象提供了常規(guī)數(shù)據(jù)庫連接的方式。為了使用數(shù)據(jù)庫連接,調(diào)用connection.cursor()方法來獲取一個游標(biāo)對象之后,調(diào)用cursor.execute(sql, [params])來執(zhí)行sql語句,調(diào)用cursor.fetchone()或者curser.fetchall()來返回結(jié)果行。

例如:

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

注意如果你的查詢中包含百分號字符,你需要寫成兩個百分號字符,以便能正確傳遞參數(shù):

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

如果你使用了不止一個數(shù)據(jù)庫,你可以使用django.db.connections來獲取針對特定數(shù)據(jù)庫的連接(以及游標(biāo))對象。django.db.connections是一個類似于字典的對象,允許你通過它的別名獲取特定的連接

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

通常,Python DB API會返回不帶字段的結(jié)果,這意味著你需要以一個列表結(jié)束,而不是一個字典?;ㄙM一點性能之后,你可以返回一個字典形式的結(jié)果,像這樣:

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()
    ]

下面是一個體現(xiàn)二者區(qū)別的例子:

>>> 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}]

連接和游標(biāo)

連接和游標(biāo)主要實現(xiàn)PEP 249中描述的Python DB API標(biāo)準(zhǔn),除非它涉及到事務(wù)處理。

如果你不熟悉Python DB-API,注意cursor.execute()中的sql語句使用占位符"%s",而不是直接在sql中添加參數(shù)。如果你使用它,下面的數(shù)據(jù)庫會在必要時自動轉(zhuǎn)義你的參數(shù)。

也要注意Django使用"%s"占位符,而不是SQLite Python綁定的"?"占位符。這是一致性和可用性的緣故。

Django 1.7中的改變。

PEP 249并沒有說明游標(biāo)是否可以作為上下文管理器使用。在python2.7之前,游標(biāo)可以用作上下文管理器,由于魔術(shù)方法lookups中意想不到的行為(Python ticket #9220)。Django 1.7 顯式添加了對允許游標(biāo)作為上下文管理器使用的支持。

將游標(biāo)作為上下文管理器使用:

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

等價于:

c = connection.cursor()
try:
    c.execute(...)
finally:
    c.close()