在django中,執行原始sql語句


extra()方法

結果集修改器,一種提供額外查詢參數的機制

使用extra:
1:Book.objects.filter(publisher__name='廣東人員出版社').extra(where=['price>50'])
Book.objects.filter(publisher__name='廣東人員出版社',price__gt=50)
2:Book.objects.extra(select={'count':'select count(*) from hello_Book'})

raw()方法

示例

使用raw:
Book.objects.raw('select * from hello_Book')
自定義sql:
Book.objects.raw("insert into hello_author(name) values('測試')")
rawQuerySet為惰性查詢,只有在使用時生會真正執行

 執行原始查詢

管理器的 raw() 方法可以用於執行原始 SQL 並返回模型實例:

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

這個方法執行一個原始 SQL 查詢並返回一個 RawQuerySet 實例。這個 RawQuerySet 實例是可迭代的,就象通常的查詢集一樣可以提供對象實例。

來個例子就容易明白了,假設你有下面的模型:

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 

當然這個例子不是十分有趣,只是相當於運行了 Person.objects.all() 。但是, raw() 有一大把的相當給力的參數。

模型表名稱

上例中 Person 表的名稱是什么?

缺省情況下, Django 把模型的“應用標簽”(你在 manage.py startapp 中使用的名稱)和模型的類名稱用下划線連接起來作為一個數據庫表名。在上例中,我們假設 Person 模型在名稱 myapp 的應用中,所以它的表名是 myapp_person

詳情參見 db_table 選項的文檔。這個選項還可以讓你手動指定數據庫表名。

Warning

傳遞給 .raw() 的 SQL 語句是不經過 Django 查驗的。 Django 會指望從數據庫中返回一組行,但這不是強迫性的。如果查詢沒有返回行,那么可以會產生一個(可能是隱性的)錯誤。

映射查詢字段到模型字段

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') ... 

映射是根據名字進行的。你可以使用 SQL 的 AS 子句來進行映射,因此如果你有一些其他包含 Person 數據的表,那么可以輕易地與 Person 實例相映射:

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

當名稱一致時,模型實例就會正確創建。

還有一種方法,你可以使用 raw()translations 參數來進行映射。這個參數是一個映射查詢字段名稱和模型字段名稱的字典。上述的查詢也可以寫成:

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

但是,索引和切片不是在數據庫級別執行的。如果你在數據庫中有大量的 Person 對象,那么在 SQL 級別來限制查詢更有效率:

>>> 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 ... print p.last_name # This will be retrieved on demand ... John Smith Jane Jones 

從表面看,好像查詢同時獲取了名和姓。但是,這個例子實際發出了三個查詢。原始查詢只獲取了名,而兩個姓是在打印時分別獲取的。

唯一不能省略的字段是主鍵。 Django 使用主鍵來判別模型實例,所以在一個原始查詢中必須包含主鍵,否則會拋出一個 InvalidQuery 異常。

加入統計

你也可以執行包含模型中沒有的字段的查詢。例如,我們可以使用 PostgreSQL 的 age() 函數 來讓數據庫統計出人員的年齡:

>>> 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() 傳遞參數

如果你需要執行帶參數的查詢,你可以使用 params 參數:

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

params 是一個參數列表。在查詢字符串中你要使用 %s 占位符(不管你用何種數據庫引擎)。占位符會被 params 列表中的參數代替。

Warning

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

你可能將上文的查詢寫成這樣:

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

千萬不要這樣做。

使用 params 列表可以保護你避開 SQL 注入攻擊 (通過漏洞把惡意 SQL 注入你的數據庫)。如果你使用了字符串插入,那么盡早你會成為 SQL 注入的受害者,因此請謹記使用 params 列表。

執行自定義SQL

(
這種方式完全不依賴model,前兩種還是要依賴於model;直接執行自定義SQL,這種方式可以完全避免數據模型,而是直接執行原始的SQL語句。
)

示例

執行自定義sql:
from django.db import connection
cursor=connection.cursor()
#插入操作
cursor.execute("insert into hello_author(name) values('郭敬明')")
#更新操作
cursor.execute('update hello_author set name='abc' where name='bcd'')
#刪除操作
cursor.execute('delete from hello_author where name='abc'')
#查詢操作
cursor.execute('select * from hello_author')
raw=cursor.fetchone() #返回結果行游標直讀向前,讀取一條
cursor.fetchall() #讀取所有

擴展

有時候,甚至  Manager.raw() 還是不夠用:你可能需要執行不明確對應模型的查詢或者直接執行 UPDATE 、  INSERT 或 DELETE 查詢。
在這種情況下,你可以直接操作數據庫,完全繞開模型層。

django.db.connection 對象表現缺省數據庫連接, django.db.transaction 表現缺省數據庫事務。要使用數據庫連接可以調用 connection.cursor() 來得到一個指針對象。然后,就可以調用 cursor.execute(sql,  [params]) 來執行 SQL 和 cursor.fetchone() 或 cursor.fetchall() 來返回結果行。在執行一個改變數據的操作后,你應當調用 transaction.commit_unless_managed() 來確保你的改變被提交。如果只是獲取數據就不必提交了。例如:

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

如果你使用多個數據庫,那么可以使用 django.db.connections 來獲得指定數據庫的連接(和指針)。 django.db.connections 是一個類似字典的對象,允許你通過別名來獲得指定數據庫的連接:

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

事務和原始 SQL

當你執行了原始 SQL 之后, Django 會自動把當前事務放入黑箱。你必須確保事務正確結束。
Django 1.3 版之前,當使用原始 SQL 時必須通過 transaction.set_dirty() 手動把事務放入黑箱。
在Django的ORM中,想使用事務操作時,要先導入一個Django的內置模塊

from django.db import transaction
  def index(request):
        from django.db import transaction
        try:
            with transaction.atomic():
                models.Userinfo.objects.create(username="python001",email="python001@qq.com")
                models.Group.objects.create(title="python002")
        except Exception as e:
            return HttpResponse("出現錯誤....")
        return HttpResponse("ok")

連接和指針

連接 和  指針 大多數執行標准  Python DB-API (除非是為了  事務處理 )。如果你不熟悉 Python DB-API ,那么要注意 cursor.execute() 中的 SQL 語句使用占位符 "%s" 比直接在 SQL 中添加參數要好。如果你使用了這個技術,那么基礎數據庫會根據需要為你的參數自動添加引號和轉義符。這樣做是符合一致性原則的,並且是一種聰明的作法。(還要注意 Django 使用 "%s" 作為占位符,而 不是 "?" 。)

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM