Django ORM 知识点总结
Query是如何工作的
Django QuerySet是懶執行的,只有訪問到對應數據的時候,才會去訪問數據庫。另外如果你再次讀取查詢到的數據,將不會觸發數據庫的訪問,而是直接從緩存獲取。
比如
在訪問兩個數據庫的時候,需要把對前一個數據庫訪問的結果轉為緩存數據再執行對下一個數據庫的訪問,比如
# 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)
- 復制模型數據
外鍵的反向引用
- 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
- values_list: 返回一個tuple,設置flat=True可以在只選擇一列的情況下返回不用tuple包裹的數據
- 若是過濾出了多行數據,返回的是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=""的條目
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_idannotate定義的字段會加到前面的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 usersDjango有兩種實現方式
但是這種方法只能適用于沒有外鍵引用的情況,即只能選擇給此Model的字段取別名,如果要給外鍵引用的字段取別名,需要用到下面這種方式
ProjectLanguagePair用supplier字段外鍵到了Supplier表,相當于
SELECT `supplier_app_supplier`.`supplier_name` AS `supplier_name`轉載于:https://www.cnblogs.com/luozx207/p/11545057.html
總結
以上是生活随笔為你收集整理的Django ORM 知识点总结的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: python基本语法:元组
- 下一篇: 【我解C语言面试题系列】003 死循环格