Django ORM 知識點總結

Query是如何工作的

Django QuerySet是懶執行的,只有訪問到對應數據的時候,才會去訪問數據庫。另外如果你再次讀取查詢到的數據,將不會觸發數據庫的訪問,而是直接從緩存獲取。
比如

# 這里不會訪問數據庫,origins只是一個查詢query,不是數據實例
origins = queryset.filter(status__in=[0, 2])
# 這里會訪問數據庫,將origins中的查詢query與此update語句拼在一起組成一個sql語句
origins.update(status=1)
# 這里的origins,是再次執行查詢之后的結果,因此,結果為空集
# 如果此時認為origins是之前查詢的結果集,就會出錯
for origin in origins:
self.after_confirm(origin, project_id)

在訪問兩個數據庫的時候,需要把對前一個數據庫訪問的結果轉為緩存數據再執行對下一個數據庫的訪問,比如

# object1與object2通過關系表Relations關聯
# object1和Relations表在同一個數據庫中,object2在另一個數據庫中
# 現在需要通過object1的一堆id來找到對應的object2# 錯誤寫法:
object2_ids = Relations.filter(object1_id__in=(object1_ids)).values_list('object2_id', flat=True).distinct()
object2s = Object2.objects.filter(id__in=object2_ids)
# 如果這時直接這樣寫,則實際上是涉及兩個數據庫的query的拼接,會出錯
# 應該將第一個query轉換為內存數據list# 正確寫法:
object2_ids = list(Relations.filter(object1_id__in=(object1_ids)).values_list('object2_id', flat=True).distinct())
object2s = Object2.objects.filter(id__in=object2_ids)

多使用query的count()函數代替for循環計數

對1530條數據做for循環計數的速度是0.2~0.3s

而用count只需要0.007s左右

Django目前不提供外鍵或多對多的關系跨越多個數據庫的支持。如果你使用路由器分割模型對不同的數據庫,任何FOREIGNKEY和多對多關系的模型定義必須是單個數據庫的內部。

復制模型數據

  • 獲取model_object值的方式

model.var

model中定義了為IntegerField的屬性取出來是int

  • 將model_object轉成字典

model.__dict__ 或者 model_to_dict(model)

  • 復制模型數據
# 在主數據庫創建一個訂單副本
# id也會相應復制,但created_time和modified_time不會
order = Order.objects.using('qtr').last()
OrderCopy.objects.create(**model_to_dict(order), project_id='qtr')

外鍵的反向引用

  • Tag.objects.filter(project_tag__project_id=project_id)

ProjectTag表的tag字段外鍵到了Tag表的id字段,并且定義了related_name='project_tag'的反向引用,因此可以通過Tag Model的project_tag字段訪問到ProjectTag Model。project_tag__project_id表示ProjectTag Model的project_id字段

  • Tag.objects.filter(user_tag__user_id=user_id)

UserTag表的tag字段外鍵到了Tag表的id字段,并且定義了related_name='user_tag'的反向引用。同時UserTag表的user字段外鍵到了User表,因此user_tag__user_id表示User的id字段

總之,外鍵的反向引用用兩橫

Update

Tag.objects.filter(id__in=ids).all().update(**update_data)

filter(id__in=ids)相當于where id in ids

如果過濾的結果是空集則不會執行更新

update_data是一個字典

利用Q構建復雜的查詢條件

如何取數據表最后兩條數據

Record.objects.order_by('-id')[:2]

[:2]會被翻譯為LIMIT 2

關于這個語句的性能消耗:http://blog.jobbole.com/52852/ 總之就是消耗不大

獲取指定列的數據

  • values:返回一個dict
record = Record.objects.values('id','name').first()
print(type(record))
# <class 'dict'>
  • values_list: 返回一個tuple,設置flat=True可以在只選擇一列的情況下返回不用tuple包裹的數據
# 取最后兩條數據記錄的svn版本
ClientVersion.objects.values_list('svn_version', flat=True).order_by('-id')[:2]
  • 若是過濾出了多行數據,返回的是queryset類型,可以用list()將其轉為列表

獲取上一條數據和下一條數據

# 本條
obj = Record.objects.get(name='test')
# 上一條
pre_obj = Record.objects.filter(id__lt=obj.id).last()
# 下一條
next_obj = Record.objects.filter(id__gt=obj.id).first()

不等于

User.objects.exclude(age=10) // 查詢年齡不為10的用戶
User.objects.exclude(age__in=[10, 20]) // 查詢年齡不為在 [10, 20] 的用戶

exact

def test_exact():
query1 = Origin.objects.filter(origin_str='test')
print(query1.query)
query2 = Origin.objects.filter(origin_str__exact='test')
print(query2.query)
# 二者翻譯成sql語句是一樣的
# WHERE `translate_app_origin`.`origin_str` = test

篩選空

django model從數據庫中取字符串的時候會自動去掉字符實際內容兩旁的空格
比如 queryset.filter(result='') 可以過濾出result=" "和result=""的條目

# 排除result=null、result=""、result=" "
# 注意不要寫成queryset.exclude(result__isnull=True, result=''),這表示同時滿足兩個條件才會被過濾
items = queryset.exclude(result__isnull=True).exclude(result='')

queryset的拼接

a1 = User.objects.filter(id__gt=8)
a2 = User.objects.filter(id__lt=4)a3 = a1 | a2
# 這種方式合并的結構還是一個queryset,相當于a3把a1和a2的條件合并了
# 只能合并同一個數據庫同種model對象的數據,并不能拼接兩個不同數據庫相同model的queryset
from itertools import chaina1 = User.objects.filter(id__gt=8)
a2 = User.objects.filter(id__lt=4)a3 = chain(a1, a2)
# 這時候a3是個可迭代對象,把a1和a2分別求出來之后合并成了一個可迭代對象,
# 可以把不同model的對象合并,類似于與list相加。
# 但是這樣合并之后a3并不是一個queryset,不能用任何篩選,沒什么意義,還不如全部轉成data_dict再拼接

總之就是,沒有把多個不同數據庫中相同model過濾出來的queryset合并的辦法

distinct

如果出現錯誤:DISTINCT ON fields is not supported by this database backend

如果你用的Mysql數據庫,那么distinct() 里面不要任何參數,參數應該寫在 value 中去,如

language_list = items.values_list('language', flat=True).distinct()

order by

一個query只能有一個order_by,如果有多個,后面的order_by會覆蓋前面的,如

Order.objects.order_by('project_id').order_by('name')
# sql:
# select * from order order by order.name ASC

對bool值按默認順序排序的時候,False會排在True前面,因為False相當于0,True相當于1

# 需要將True排在前面
def test_order_by():
result = OrderLanguagePair.objects.order_by('-activate').first()
print(result.activate)

group by

比如現在想知道每個項目有多少個訂單,在sql語句中應對訂單按項目id分組,然后求出每組訂單的數量

SELECT project_id, count(*) FROM order group by project_id;

django ORM中沒有顯式的group by函數,通過annotate來實現分組

# annotate的作用是為一個query增加一個自定義的新字段
# annotate接收表達式作為參數
def annotate(self, *args, **kwargs):
"""
Return a query set in which the returned objects have been annotated
with extra data or aggregations.
"""

如果沒有指定任何字段,annotate會根據前面queryset的第一個字段(一般是id)分組計算,如

Order.objects.annotate(Count('name'))
# sql:
# select *, count(order.name) from order group by order.id

在annotate前用values或values_list指定根據什么字段分組,如

# 注意values要放在annotate之前
Order.objects.values('project_id').annotate(count=Count('*'))
# sql:
# select order.project_id, count(*) as count from order group by order.project_id

annotate定義的字段會加到前面的values或values_list中

values中有多個值時,會按照順序group by

Order.objects.values('project_id', 'name').annotate(count=Count('*'))
# sql:
# select order.project_id, order.name, count(*) as count from order group by order.project_id, order.name

如果annotate所屬的query含有order_by的話,除了按values的字段分組外,還會額外按照order_by的字段分組(如果order_by中的字段不在values中)

# 下面兩個query對應的sql是一樣的
Order.objects.values('project_id').annotate(count=Count('*')).order_by('name')
Order.objects.order_by('name').values('project_id').annotate(count=Count('*'))
# sql:
# select order.project_id, count(*) as count from order
# group by order.project_id, order.name 
# order by order.name

解決的方法是用對分組字段的排序覆蓋query之前的排序,比如

query = Order.objects.order_by('name')
query.order_by('project_id').values('project_id').annotate(count=Count('*'))

別名

希望使用ORM實現給字段加別名,如

select name as user_name, id as user_id
from users

Django有兩種實現方式

  1. extra
User.objects.extra(select={'user_id':user, 'user_name':id}). \
values('user_id', 'user_name')

但是這種方法只能適用于沒有外鍵引用的情況,即只能選擇給此Model的字段取別名,如果要給外鍵引用的字段取別名,需要用到下面這種方式

  1. annotate
ProjectLanguagePair.objects.\
annotate(supplier_name=F('supplier__supplier_name')). \
values('supplier_name')

ProjectLanguagePair用supplier字段外鍵到了Supplier表,相當于

SELECT `supplier_app_supplier`.`supplier_name` AS `supplier_name` 

轉載于:https://www.cnblogs.com/luozx207/p/11545057.html

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/447692.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/447692.shtml
英文地址,請注明出處:http://en.pswp.cn/news/447692.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

22天養成好習慣,一年后脫胎換骨!

第一個習慣&#xff1a; 每天對鏡子的自己微笑。 親愛的&#xff0c;如果你都不喜歡自己的話&#xff0c;怎么可能指望別人喜歡你&#xff1f; 第二個習慣&#xff1a; 每天用涼水洗臉。 涼水洗臉&#xff0c;皮膚健康&#xff1b;熱水洗腳&#xff0c;強似吃藥。 第三個習…

springCloud - 第1篇 - 服務的注冊 Eureka

前些天發現了一個巨牛的人工智能學習網站&#xff0c;通俗易懂&#xff0c;風趣幽默&#xff0c;忍不住分享一下給大家。點擊跳轉到教程。 PS&#xff1a;這個系列不定時更新&#xff0c;只是個人的學習分享&#xff0c; 內容全程參考書目&#xff1a; 《Spring Cloud 與 Do…

js中的Map對象

var map new Map();//map對象中添加鍵值對map.set("name","tom");map.set("age",35);map.set("sex",0);//獲取map對象中的值map.get("name")//tom//遍歷map 函數中第一個參數是value&#xff0c;第二個參數是keymap.forEa…

十六個字 一輩子學不完

1、道歉&#xff1a;并不總意味著你是錯的&#xff0c;它只是意味著你更珍惜你們之間的關系。 2、相愛&#xff1a;不是尋找一個完美的人&#xff0c;而是學會用完美的眼光&#xff0c;去欣賞一個不完美的人。 3、專一&#xff1a;不是一輩子只喜歡一個人&#xff0c;…

解決:com.mysql.jdbc.MysqlDataTruncation: Data truncation: Data too long for column ‘ip‘ at row 1

前些天發現了一個巨牛的人工智能學習網站&#xff0c;通俗易懂&#xff0c;風趣幽默&#xff0c;忍不住分享一下給大家。點擊跳轉到教程。 1. 報錯&#xff1a; SQL []; Data truncation: Data too long for column ip at row 1; nested exception is com.mysql.jdbc.MysqlDa…

Xampp配置本地域名及常見錯誤解決

Xampp配置本地域名及常見錯誤解決 本地域名配置1、計算機-->C盤-->Windows-->System32-->drivers-->etc-->hosts127.0.0.1 localhost//設置你要配置的本地域名2、計算機-->XAMPP-->apache-->conf-->extra-->httpd-vhosts.conf<Virtu…

單元測試寫法

前些天發現了一個巨牛的人工智能學習網站&#xff0c;通俗易懂&#xff0c;風趣幽默&#xff0c;忍不住分享一下給大家。點擊跳轉到教程。 好像很早前寫過的&#xff1a; package com.xxx.dubbo;import com.xxx.app.xx.xx.dao.MarketingRuleMapper; import com.xxx.app.xx.xx…

刷新網頁跳轉錨點

html中&#xff1a; <a name"miao" > <b>{{ $v->department_name }}</b></a> js跳轉錨點&#xff1a; window.οnlοadfunction(){location.hashmiao;} 轉載于:https://www.cnblogs.com/best-coder/p/11550177.html

java - 通用 CRUD(增、刪、改、查)工具類,代碼高效復用

前些天發現了一個巨牛的人工智能學習網站&#xff0c;通俗易懂&#xff0c;風趣幽默&#xff0c;忍不住分享一下給大家。點擊跳轉到教程。 1. 基本 CRUD 方法實現&#xff1a; package com.xxx.xxx.ls.xxx.utils;import com.alibaba.fastjson.JSON; import com.google.common…

CSS文本溢出顯示省略號

項目中常常有這種需要我們對溢出文本進行"..."顯示的操作&#xff0c;單行多行的情況都有&#xff08;具體幾行得看設計師心情了&#xff09;&#xff0c;這篇隨筆是我個人對這種情況解決辦法的歸納&#xff0c;歡迎各路英雄指教。 單行 語法 overflow:hidden;text-o…

@JsonFormat Date類型時間 格式化 注解 使用

前些天發現了一個巨牛的人工智能學習網站&#xff0c;通俗易懂&#xff0c;風趣幽默&#xff0c;忍不住分享一下給大家。點擊跳轉到教程。 JsonFormat注解是一個時間格式化注解&#xff0c;比如我們存儲在mysql中的數據是date類型的&#xff0c;當我們讀取出來封裝在實體類中的…

好用的在線工具

1.在線工具 http://tool.oschina.net/ 網站里面包含很多強大的工具&#xff0c;代碼對比&#xff0c;正則表達式在線驗證&#xff0c;各種語言的語法對照表等。 2.so JSON在線工具 https://www.sojson.com/ 這個網站可能更加偏向前端一些吧&#xff0c;里面有一些加密解密&…

解決 Idea 卡在 Resolving Maven dependencies ...

前些天發現了一個巨牛的人工智能學習網站&#xff0c;通俗易懂&#xff0c;風趣幽默&#xff0c;忍不住分享一下給大家。點擊跳轉到教程。 Idea卡在Resolving Maven dependencies的解決方案 在Reimpot All Maven Porjects時, 如果項目過大, maven依賴過多, 會直接卡在Resolvin…

VS Code (visual studio code) VSC 編輯器(微軟出品,js開發的編輯器)

一.選擇合適的編輯器&#xff0c;提高編程效率 代碼編輯器的選擇&#xff0c;可以說是開發者社區中一個經久不衰的話題&#xff0c;現今編輯器的數量數不勝數&#xff0c;vim&#xff0c;sublime Text,Emacs,Atom等等&#xff0c;那么對于一個開發者而言&#xff0c;挑選一個合…

Docker 安裝 redis 、Redis docker 方式部署

前些天發現了一個巨牛的人工智能學習網站&#xff0c;通俗易懂&#xff0c;風趣幽默&#xff0c;忍不住分享一下給大家。點擊跳轉到教程。 1. 找鏡像&#xff1a; docker search redis2. 拉取鏡像&#xff1a; 在這一步可以選擇版本&#xff0c;不選擇版本&#xff0c;默認為…

xcode windows版安裝使用教程

隨著iPhone、iPad、Mac等蘋果產品越來越火爆&#xff0c;越來越多的初學者想要了解和嘗試蘋果平臺&#xff0c;包括蘋果操作系統Mac OS X、蘋果演示軟件Keynote、蘋果開發工具Xcode等。然而&#xff0c;蘋果電腦價格昂貴&#xff0c;并不是每個人都可以承受。 因此&#xff0c;…

解決:Unable to open debugger port (127.0.0.1:55017): java.net.SocketException “Socket closed“

項目以前啟動正常&#xff0c;突然報錯&#xff0c;啟動不起來了&#xff0c;報了個Unable to open debugger port (127.0.0.1:55017): java.net.SocketException "Socket closed"這個錯。 前些天發現了一個巨牛的人工智能學習網站&#xff0c;通俗易懂&#xff0c;…

html5 如何打包成apk,將H5封裝成android應用APK文件的幾種方法

直接使用編程軟件提供的方法&#xff1a; 1、需要下載安裝MyEclipse2014&#xff0c;Android SDK&#xff0c;eclipse(需配置Android開發環境) Java和Android環境安裝與配置。 2、打開MyEclipse2014&#xff0c;新建一個HTML5 Mobile Application Project&#xff0c;命名&…

解決 Unmapped Spring configuration files found.Please configure Spring facet.

最近在學習使用IDEA工具&#xff0c;覺得與Eclipse相比&#xff0c;還是有很多的方便之處。 但是&#xff0c;當把自己的一個項目導入IDEA之后&#xff0c;Event Log提示“Unmapped Spring configuration files found.Please configure Spring facet.” 這個提示不影響工程正…

uni-app—從安裝到卸載

uni-app實現了一套代碼&#xff0c;同時運行到多個平臺。支持iOS模擬器、Android模擬器、H5、微信開發者工具、支付寶小程序Studio、百度開發者工具、字節跳動開發者工具 工具安裝 開發uni-app需要安裝HBuilder X.下載地址。 下載成功后直接解壓即可 簡單的配置一下開發偏好&am…