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

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

進行原始的sql查詢

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

警告

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

進行原始查詢

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

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

模型表的名稱

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

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

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

警告

傳遞給raw()方法的sql語句并沒有任何檢查。django默認它會返回一個數(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ù)名字進行匹配。這意味著你可以使用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ù)庫層面上進行操作。如果數(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輸入的攻擊。只要你記住默認使用參數(shù)化查詢,就可以免于攻擊。

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

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

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

django.db.connection對象提供了常規(guī)數(shù)據(jù)庫連接的方式。為了使用數(shù)據(jù)庫連接,調(diào)用connection.cursor()方法來獲取一個游標對象之后,調(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ù)庫的連接(以及游標)對象。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}]

連接和游標

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

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

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

Django 1.7中的改變。

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

將游標作為上下文管理器使用:

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

等價于:

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