Django ORM 知识点总结
Query是如何工作的
Django QuerySet是懶執(zhí)行的,只有訪問(wèn)到對(duì)應(yīng)數(shù)據(jù)的時(shí)候,才會(huì)去訪問(wèn)數(shù)據(jù)庫(kù)。另外如果你再次讀取查詢到的數(shù)據(jù),將不會(huì)觸發(fā)數(shù)據(jù)庫(kù)的訪問(wèn),而是直接從緩存獲取。
比如
在訪問(wèn)兩個(gè)數(shù)據(jù)庫(kù)的時(shí)候,需要把對(duì)前一個(gè)數(shù)據(jù)庫(kù)訪問(wèn)的結(jié)果轉(zhuǎn)為緩存數(shù)據(jù)再執(zhí)行對(duì)下一個(gè)數(shù)據(jù)庫(kù)的訪問(wèn),比如
# object1與object2通過(guò)關(guān)系表Relations關(guān)聯(lián) # object1和Relations表在同一個(gè)數(shù)據(jù)庫(kù)中,object2在另一個(gè)數(shù)據(jù)庫(kù)中 # 現(xiàn)在需要通過(guò)object1的一堆id來(lái)找到對(duì)應(yīng)的object2# 錯(cuò)誤寫法: object2_ids = Relations.filter(object1_id__in=(object1_ids)).values_list('object2_id', flat=True).distinct() object2s = Object2.objects.filter(id__in=object2_ids) # 如果這時(shí)直接這樣寫,則實(shí)際上是涉及兩個(gè)數(shù)據(jù)庫(kù)的query的拼接,會(huì)出錯(cuò) # 應(yīng)該將第一個(gè)query轉(zhuǎn)換為內(nèi)存數(shù)據(jù)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()函數(shù)代替for循環(huán)計(jì)數(shù)
對(duì)1530條數(shù)據(jù)做for循環(huán)計(jì)數(shù)的速度是0.2~0.3s
而用count只需要0.007s左右
Django目前不提供外鍵或多對(duì)多的關(guān)系跨越多個(gè)數(shù)據(jù)庫(kù)的支持。如果你使用路由器分割模型對(duì)不同的數(shù)據(jù)庫(kù),任何FOREIGNKEY和多對(duì)多關(guān)系的模型定義必須是單個(gè)數(shù)據(jù)庫(kù)的內(nèi)部。
復(fù)制模型數(shù)據(jù)
- 獲取model_object值的方式
model.var
model中定義了為IntegerField的屬性取出來(lái)是int
- 將model_object轉(zhuǎn)成字典
model.__dict__ 或者 model_to_dict(model)
- 復(fù)制模型數(shù)據(jù)
外鍵的反向引用
- Tag.objects.filter(project_tag__project_id=project_id)
ProjectTag表的tag字段外鍵到了Tag表的id字段,并且定義了related_name='project_tag'的反向引用,因此可以通過(guò)Tag Model的project_tag字段訪問(wèn)到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'的反向引用。同時(shí)UserTag表的user字段外鍵到了User表,因此user_tag__user_id表示User的id字段
總之,外鍵的反向引用用兩橫
Update
Tag.objects.filter(id__in=ids).all().update(**update_data)
filter(id__in=ids)相當(dāng)于where id in ids
如果過(guò)濾的結(jié)果是空集則不會(huì)執(zhí)行更新
update_data是一個(gè)字典
利用Q構(gòu)建復(fù)雜的查詢條件
如何取數(shù)據(jù)表最后兩條數(shù)據(jù)
Record.objects.order_by('-id')[:2][:2]會(huì)被翻譯為L(zhǎng)IMIT 2
關(guān)于這個(gè)語(yǔ)句的性能消耗:http://blog.jobbole.com/52852/ 總之就是消耗不大
獲取指定列的數(shù)據(jù)
- values:返回一個(gè)dict
- values_list: 返回一個(gè)tuple,設(shè)置flat=True可以在只選擇一列的情況下返回不用tuple包裹的數(shù)據(jù)
- 若是過(guò)濾出了多行數(shù)據(jù),返回的是queryset類型,可以用list()將其轉(zhuǎn)為列表
獲取上一條數(shù)據(jù)和下一條數(shù)據(jù)
# 本條 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語(yǔ)句是一樣的 # WHERE `translate_app_origin`.`origin_str` = test篩選空
django model從數(shù)據(jù)庫(kù)中取字符串的時(shí)候會(huì)自動(dòng)去掉字符實(shí)際內(nèi)容兩旁的空格
比如 queryset.filter(result='') 可以過(guò)濾出result=" "和result=""的條目
queryset的拼接
a1 = User.objects.filter(id__gt=8) a2 = User.objects.filter(id__lt=4)a3 = a1 | a2 # 這種方式合并的結(jié)構(gòu)還是一個(gè)queryset,相當(dāng)于a3把a(bǔ)1和a2的條件合并了 # 只能合并同一個(gè)數(shù)據(jù)庫(kù)同種model對(duì)象的數(shù)據(jù),并不能拼接兩個(gè)不同數(shù)據(jù)庫(kù)相同model的queryset from itertools import chaina1 = User.objects.filter(id__gt=8) a2 = User.objects.filter(id__lt=4)a3 = chain(a1, a2) # 這時(shí)候a3是個(gè)可迭代對(duì)象,把a(bǔ)1和a2分別求出來(lái)之后合并成了一個(gè)可迭代對(duì)象, # 可以把不同model的對(duì)象合并,類似于與list相加。 # 但是這樣合并之后a3并不是一個(gè)queryset,不能用任何篩選,沒(méi)什么意義,還不如全部轉(zhuǎn)成data_dict再拼接總之就是,沒(méi)有把多個(gè)不同數(shù)據(jù)庫(kù)中相同model過(guò)濾出來(lái)的queryset合并的辦法
distinct
如果出現(xiàn)錯(cuò)誤:DISTINCT ON fields is not supported by this database backend
如果你用的Mysql數(shù)據(jù)庫(kù),那么distinct() 里面不要任何參數(shù),參數(shù)應(yīng)該寫在 value 中去,如
language_list = items.values_list('language', flat=True).distinct()order by
一個(gè)query只能有一個(gè)order_by,如果有多個(gè),后面的order_by會(huì)覆蓋前面的,如
Order.objects.order_by('project_id').order_by('name') # sql: # select * from order order by order.name ASC對(duì)bool值按默認(rèn)順序排序的時(shí)候,False會(huì)排在True前面,因?yàn)镕alse相當(dāng)于0,True相當(dāng)于1
# 需要將True排在前面 def test_order_by(): result = OrderLanguagePair.objects.order_by('-activate').first() print(result.activate)group by
比如現(xiàn)在想知道每個(gè)項(xiàng)目有多少個(gè)訂單,在sql語(yǔ)句中應(yīng)對(duì)訂單按項(xiàng)目id分組,然后求出每組訂單的數(shù)量
SELECT project_id, count(*) FROM order group by project_id;
django ORM中沒(méi)有顯式的group by函數(shù),通過(guò)annotate來(lái)實(shí)現(xiàn)分組
# annotate的作用是為一個(gè)query增加一個(gè)自定義的新字段 # annotate接收表達(dá)式作為參數(shù) def annotate(self, *args, **kwargs): """ Return a query set in which the returned objects have been annotated with extra data or aggregations. """如果沒(méi)有指定任何字段,annotate會(huì)根據(jù)前面queryset的第一個(gè)字段(一般是id)分組計(jì)算,如
Order.objects.annotate(Count('name')) # sql: # select *, count(order.name) from order group by order.id在annotate前用values或values_list指定根據(jù)什么字段分組,如
# 注意values要放在annotate之前 Order.objects.values('project_id').annotate(count=Count('*')) # sql: # select order.project_id, count(*) as count from order group by order.project_idannotate定義的字段會(huì)加到前面的values或values_list中
values中有多個(gè)值時(shí),會(huì)按照順序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的字段分組外,還會(huì)額外按照order_by的字段分組(如果order_by中的字段不在values中)
# 下面兩個(gè)query對(duì)應(yīng)的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解決的方法是用對(duì)分組字段的排序覆蓋query之前的排序,比如
query = Order.objects.order_by('name') query.order_by('project_id').values('project_id').annotate(count=Count('*'))別名
希望使用ORM實(shí)現(xiàn)給字段加別名,如
select name as user_name, id as user_id from usersDjango有兩種實(shí)現(xiàn)方式
但是這種方法只能適用于沒(méi)有外鍵引用的情況,即只能選擇給此Model的字段取別名,如果要給外鍵引用的字段取別名,需要用到下面這種方式
ProjectLanguagePair用supplier字段外鍵到了Supplier表,相當(dāng)于
SELECT `supplier_app_supplier`.`supplier_name` AS `supplier_name`轉(zhuǎn)載于:https://www.cnblogs.com/luozx207/p/11545057.html
總結(jié)
以上是生活随笔為你收集整理的Django ORM 知识点总结的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: python基本语法:元组
- 下一篇: 【我解C语言面试题系列】003 死循环格