Python DJango ORM操作

這篇來紀錄一下Python DJango ORM的相關操作。

資料的建立

TABLE_NAME.objects.create(colume1='xxx', colume2='yyy', colume3='zzz')

資料的讀取

#使用預設DB存取表格的方式
TABLE_NAME.objects.all()

#使用非預設DB存取表格的方式
TABLE_NAME.objects.using(DB_NAME).all()
DB_NAME:settings.py中其他定義的資料庫名稱
TABLE_NAME:資料表格的名稱

#回傳符合條件的唯一一筆資料。如果找不到符合條件的資料、或是有多筆資料符合條件,都會產生 exception。
TABLE_NAME.objects.get(pk=123)

#透過filter來進行資料篩選
#bkname這個欄位包含「XYZ」的資料列
TABLE_NAME.objects.filter(bkname__contains='XYZ')
#bkname這個欄位是「XYZ」的資料列
TABLE_NAME.objects.filter(bkname='XYZ')
#bkname這個欄位不是「XYZ」的資料列
TABLE_NAME.objects.exclude(bkname='XYZ')

#排序。透過加上「-」可達到desc的效果
TABLE_NAME.objects.order_by('-column_name')
#排序,且只抓10筆
TABLE_NAME.objects.order_by('-column_name')[:10]

資料的修改

bkn = TABLE_NAME.objects.filter(bkname__contains='XYZ')
bkn.update(colume1='aaa')

資料的刪除

bkn = TABLE_NAME.objects.filter(bkname__contains='XYZ')
bkn.delete()

DJango ORM下的JOIN

參考|10. How to perform join operations in django ORM? — Django ORM Cookbook 2.0 documentation (agiliq.com)

理解dajngo ORM查询中select_related的作用_Nick_Spider的博客-CSDN博客_select_related

select_related

select_related 將會根據外鍵關係(注意: 僅限一對一和多對一關係),在執行查詢語句的時候通過建立一個包含 SQL inner join 操作的 SELECT 語句來一次性獲得主對象及相關對象的資料。且透過指定的結果,可以避免重複的對資料庫進行存取。

以下面的範例為例,有兩個表格「Job」與「Project」,其中Project透過job這個foreign key對應到表格Job。如果Job表格中有n筆資料,Project表格中有m筆資料,需要透過Project表格的查詢來印出Job的job_name時,透過<作法1>僅需使用約2次的SQL查詢次數,透過<作法2>則會需要約 m +1 次的SQL查詢次數。當層數越多的時候,造成的影響就越可觀。

透過<作法1>,在列印 item.job.job_name 時會從qs1的緩存結果中直接搜尋;透過<作法2>,在列印 item.job.job_name時,for迴圈中會不斷的驅動一次新的SQL查詢。

# ========== models.py ==========
class Person(models.Model):
    person_number = models.CharField(max_length=20, primary_key=True)
    person_name = models.CharField(max_length=50, blank=True, null=True)

class Employee(models.Model):
    person = models.ForeignKey(Person, null=True) # updated (null=True)***
    employee_number = models.CharField(max_length=50, blank=True, null=True)

class Company(models.Model):
    company_name = models.CharField(max_length=50, blank=True, null=True)
    employee = models.ForeignKey(Employee, null=True) # updated (null=True)***


# ========== views.py ==========
#作法1
qs1 = Company.objects.select_related('employee')
for item in qs1:
    print(item.employee.employee_number)

#作法2
qs2 = Company.objects
for item in qs2:
    print(item.employee.employee_number)

select_related 中透過「__」來實現兩層的外鍵連接

qsperson = Company.objects.select_related('employee__person')
qsperson = Company.objects.select_related('employee__person').filter(company_name='FIH')

以下是網路上查到的一些相關注意事項

  1. 主要針一對一和多對一關係進行優化。
  2. 可以通過可變長參數指定需要select_related的欄位名。
  3. 沒有指定的欄位不會緩存,沒有指定的深度不會緩存,如果要訪問的話Django會再次進行SQL查詢。
  4. 可以通過depth參數指定遞歸的深度,Django會自動緩存指定深度內所有的欄位。 如果要訪問指定深度外的字段,Django會再次進行SQL查詢。
  5. 也接受無參數的調用,Django會盡可能深的遞歸查詢所有的字段。 但注意有Django遞歸的限制和性能的浪費。
  6. Django >= 1.7,鏈式調用的select_related相當於使用可變長參數。 Django < 1.7,鏈式調用會導致前邊的select_related失效,只保留最後一個。
  7. select_related('foo', 'bar') is equivalent to select_related('foo').select_related('bar').
  8. The order of filter() and select_related() chaining isn’t important. These querysets are equivalent:

[筆記] Django Query 優化. 最近處理的 server 有個 api… | by Lin Po-An | Medium

Django之ORM跨表查询、join查询、聚合查询、分组查询_Sunny_Future的博客-CSDN博客_django join查询