Django 模型和數據庫 總結


模型和數據庫

模型

首先我們在創建一個model的時候,這個類都是繼承自 django.db.models.Model,

各種Model Field類型

  1. AutoField,自動增長的IntegerField,如果不指定,則默認添加。
  2. IntegerField/BigIntegerField/PositiveSmallIntegerField/SmallIntegerField:都是類似的,只是數字的范圍不同。
  3. BinaryField/DecimalField:二進制和十進制。
  4. BooleanField,如果沒有指定default的話,默認為None
  5. CharField,**必須**接收另外一個參數 max_length
  6. DateField,使用Python的datetime.date實例表示的日期。

    需要注意的是,auto_now用於每次保存對象的時候,自動設置該字段為當前時間;auto_now_add則用於第一次被創建時自動設置該字段為當前時間,這些選項還有default之間相互違背的,所以不要同時使用任意多個。這些選項默認保存的是 django.utils.timezone.datetime 里面的now,所以如果想要進行特殊的保存,需要自己重寫save函數。
  7. EmailField,基於CharField,使用EmailValidator來驗證輸入和合法性。

  8. FileField,上傳文件,字段的選項不支持primary_key和unique。

    需要在settting文件里面,需要添加MEDIA_ROOT用來提供文件上傳的根路徑,而參數upload則提供文件具體的位置。
    當你刪除了該model,文件需要你自己手動去刪除。
  9. ImageField,繼承自FileField,同時還添加了圖像的驗證。

  10. NullBooleanField,和之前BooleanField不同的是,它除了允許True或者False,還允許Null=True,也就是為null。

  11. TextField,適用於大文本字段,如果設定了max_length屬性,那么其只會對組件進行一個內容顯示的限制,但是不會對數據庫存在限制。

  12. TimeField,和Python中的datetime.time一樣,參數則和DateField相同。

  13. URLField,繼承自CharField,但是同樣添加了URL的驗證。

除了上面的Fields,還有關系Field:

  1. ForeignKey,對應的是一對多的關系,可以指定關聯刪除-**on_delete=models.CASCADE**,如果要關聯的對象還沒有定義好,可以使用其名字。
    1. limit_choices_to,可以限制關聯返回的內容。
    2. related_name,可以讓關聯的對象反查到源對象,如果不想創建反向關聯,則設置為"+"即可。需要注意的是,如果沒有使用該Field,那么想要使用反向關聯,則需要**foo_set**,foo為關聯對象的小寫名稱,如果使用了該Field,則可以直接使用自己定義的名稱。
    3. related_query_name,和上面的作用類似,同樣可以反向查詢,兩者只需要設置一個即可。
    4. to_field,指定關聯對象的字段名稱,默認情況下為對方的主鍵。
    5. db_constraint,控制是否在數據庫中為這個外鍵創建約束,默認為True。
    6. on_delete,可以實現CASCADE,級聯刪除;PROTECT,防止被引用對象刪除,拋出ProtectedError;SET_NULL,將其設置成null;

SET_DEFAULT,設置成默認值;SET,可以傳遞值,同時還可以傳遞可調用對象;DO_NOTHING,不采取任何動作。

  1. ManyToManyField,對應的是多對多的關系。
    1. symmetrical,只用在自己對自己進行關聯的時候。比如說Friend,你的朋友是我,我的朋友是你。
    2. through,如果不想要Django自動創建的多對多的關系表,可以通過指定through指定自己定義的中介表。
    3. through_fields,在上面的基礎上指定中間模型的**哪些字段**來建立是多對多關聯。
    4. db_table,設定多對多關系表的名稱。
    5. db_constraint,同上。
    6. swappable,
  2. OneToOneField,對應的是一對一的關系,其可以直接返回關系另一邊的對象,最主要的用途是作為擴展自另外一個模型的主鍵。比如多表繼承就是利用這樣的原理,通過對子模型添加一個隱式的一對一關聯關系到父親模型實現的。

    如果你沒有指定其的related_name參數,那么Django將使用當前模型的小寫名稱作為默認值。
    如果訪問相應的對象不存在的話,則會拋出ObjectDoesNotExist的異常。
    當設置**parent_link**為True時,??

Model Field Options

下面這些選項都是可選擇的,非固定要求。

  1. Field.null,注意在CharField或者TextField里避免使用null,因為其存儲的值是空字符串而不是NULL。
  2. Field.blank,和上面的不同,其限制的是組件,而上面限制的是數據庫。
  3. Field.choices,由可迭代的二元祖來組成,其中元祖里面第一個元素是存儲在數據中的值,第二個則是元素更加詳細的描述,界面上顯示的是后者。,數據庫存儲的是前者。
  4. Field.db_column,數據庫中用來表示字段的名稱,如果沒有提供,則默認使用filed的名稱。
  5. Field.db_index,如果為True,則為該字段創建索引。
  6. Field.db_tablespace,表空間,如果該字段已經創建了索引,那么數據庫表空間的名稱將作為該字段的索引名。注意,部分數據庫不支持表空間。
  7. Field.db_default,指定一個默認值,它可以是一個值或者可調用對象,注意的是,其不可以是一個可變對象,因為會指向同一個引用。
  8. Field.editable,如果為false,則不可編輯,那么admin和其它model則忽略掉這個字段。
  9. Field.error_messages,能夠重寫默認拋出的錯誤信息。
  10. Field.help_text,將會作為提示信息顯示在表單中。
  11. Field.primary_key,這意味着null=False和unique=True,所以一個對象只能擁有一個主鍵。
  12. Field.unique,當設定為True時,不需要再設定db_index,因為其本身就是一個索引的創建。注意的是,ManyToManyField和OneToOneField和FileField以外的其它類型都可以使用這個字段(????)。
  13. Field.unique_for_date/Field.unique_for_month/Field.unique_for_year/Field,設置對應的時間是唯一的。
  14. Field.validators,指定驗證器。
  15. ForeignKey、ManyToManyField和OneToOneField需要通過Field.verbose_name才能自定義設置字段名,其它均可以每個字段類型都可在第一個參數上自定義設置字段的字段名。

每個字段實例都包含幾個允許內省其行為的屬性,自定義模型字段需要實行這些標志。

  1. Field.auto_created
  2. Field.concrete
  3. Field.hidden
  4. Field.is_relation
  5. Field.model

上面是普通Field的屬性,下面是關系Field的屬性:

  1. Field.many_to_many,多對多關系;
  2. Field.many_to_one,多對一關系,例如ForeignKey;
  3. Field.one_to_many,一對多關系,例如GenericRelation或者ForeignKey的反向;
  4. Field.one_to_one,一對一關系;
  5. Field.related_model,指向字段涉及的模型;

自定義Model Field

不是很懂

可以參考源碼。

Relationships

Many-to-one relationships

翻譯-一對多關系

Many-to-many relationships

翻譯-多對多關系

One-to-one relationships

翻譯-一對一關系

Meta 選項

所有的選項都不是必須的。

  1. abstract,如果聲明為True,則表明這是一個抽象基類。
  2. app_label,如果定義在application之外,則需要指明它是那個applicaition的,也可以通過其屬性自定義格式。
  3. base_manager_name,指定managers的名字。
  4. db_table,指定數據庫表格的名字。
  5. db_tablespace,指定表格空間,如果數據庫不支持則忽略。
  6. default_manger_name,指定manager的名字。
  7. default_related_name,指定反向關聯的模型的名稱,需要注意的是,這個名稱應該是唯一的,建議命名中包含app和model名字以避免沖突,%(app_label)s和%(model_name)s
  8. get_latest_by,指定model中某個可排序的字段的名稱,這樣當通過managers去調用lates函數的時候會返回根據排序的最新的結果。
  9. managed,是否指明Django為當前模型創建和刪除數據庫表,True或者False。
  10. order_with_respect_to,通常用在關聯對象上面,指定某個字段,使其在父對象中有序。

        設置之后,可以通過get_RELATED_order和set_RELATED_order進行獲取關聯對象的已經拍好序的主鍵列表或者是自定義設置其順序。
        我們還可以通過get_next_in_order和get_previous_in_order,可以用於獲取一個生成器。
  11. ordering,對象默認的順序,獲取一個對象的列表時候使用。

  12. permissions,設置創建對象時權限表中額外的權限,注意其是一個二元祖的元祖或者列表。

  13. default_permissions,默認為 add,change,delete。

  14. proxy,如果為True,則表明這是另外一個模型的子類,這將會作為一個代理模型。

  15. required_db_features,

  16. required_db_vendor,指定使用哪種數據庫。

  17. select_on_save,指定使用哪種保存數據的算法。

  18. unique_together,用來設置不重復的字段組合。

  19. index_together,用來設置帶有索引的字段組合,和上面的用法相似。

  20. verbose_name,為model創建一個易於理解的名稱,單數。

  21. verbose_name_plural,和上面不同的是,為復數形式。

模型屬性

如果沒有自定義Manager,則默認的名稱為objects;Managers只能通過模型類來訪問,而不能通過模型實例來訪問。

模型方法

創建對象

在封裝一些操作的時候,可以在model中添加一個類方法,或者在自定義管理器中添加一個方法(推薦)。

模型加載

Model.from_db和Model.refresh_from_db。

驗證對象

驗證一個模型涉及這三個步驟:

  1. 驗證模型的字段 —— Model.clean_fields()
  2. 驗證模型的完整性 —— Model.clean()
  3. 驗證模型的唯一性 —— Model.validate_unique()

當調用full_clean()的時候,上面三個方法都會按順序執行。如果驗證失敗,則會拋出ValidationError

保存對象

保存對象需要經過下面的步驟:

  1. 發出一個pre-save 信號。 發送一個django.db.models.signals.pre_save 信號,以允許監聽該信號的函數完成一些自定義的動作。
  2. 預處理數據。 如果需要,對對象的每個字段進行自動轉換。

    大部分字段不需要預處理 —— 字段的數據將保持原樣。預處理只用於具有特殊行為的字段。例如,如果你的模型具有一個auto_now=True 的DateField,那么預處理階段將修改對象中的數據以確保該日期字段包含當前的時間戳。(我們的文檔還沒有所有具有這種“特殊行為”字段的一個列表。)
  3. 准備數據庫數據。 要求每個字段提供的當前值是能夠寫入到數據庫中的類型。

    大部分字段不需要數據准備。簡單的數據類型,例如整數和字符串,是可以直接寫入的Python 對象。但是,復雜的數據類型通常需要一些改動。
    例如,DateField 字段使用Python 的 datetime 對象來保存數據。數據庫保存的不是datetime 對象,所以該字段的值必須轉換成ISO兼容的日期字符串才能插入到數據庫中。
  4. 插入數據到數據庫中。 將預處理過、准備好的數據組織成一個SQL 語句用於插入數據庫。

  5. 發出一個post-save 信號。 發送一個django.db.models.signals.post_save 信號,以允許監聽聽信號的函數完成一些自定義的動作。

關於Django是怎么知道UPDATE還是INSERT?

  • 如果對象的主鍵屬性為一個求值為True 的值(例如,非None 值或非空字符串),Django 將執行UPDATE。
  • 如果對象的主鍵屬性沒有設置或者UPDATE 沒有更新任何記錄,Django 將執行INSERT。

當然你也可以通過指定save的參數,強制進行INSERT或者UPDATE。

在執行完create動作之后,需要將其創建的對象調用save進行保存。

更新對象

可以通過F表達式可以避免競爭條件而且更快,而不是通過對對象賦一個新值。

刪除對象

通過Model.delete方法。

Pickling對象

pickle是Python自帶的用於對象序列化的。

Model.__str__

用來返回一個更易讀的字符串。

Model.__eq__

為了讓具有相同主鍵的相同實類的實例是相等的。

Model.__hash__

基於實例主鍵的值。

Model.get_absolute_url

告訴Django如何計算對象的標准URL。需要注意的是,get_absolute_url() 返回的字符串必須只包含ASCII 字符(URI 規范RFC 2396 的要求),並且如需要必須要URL-encoded。

其它

Model.get_FOO_display,對於每個具有choices 的字段,每個對象將具有一個get_FOO_display() 方法,其中FOO 為該字段的名稱。

Model.get_next_by_FOO和Model.get_previous_by_FOO。

Model.DoesNotExist,通常發生在找不到對象的時候則報出這個錯。

模型繼承

在Django 中有3種風格的繼承。

  1. 通常,你只想使用父類來持有一些信息,你不想在每個子模型中都敲一遍。這個類永遠不會單獨使用,所以你要使用抽象基類。
  2. 如果你繼承一個已經存在的模型且想讓每個模型具有它自己的數據庫表,那么應該使用多表繼承。繼承關系在子model和它的每個父類之間添加一個鏈接,這是通過自動創建的OneToOneField來實現的。
  3. 最后,如果你只是想改變一個模塊Python 級別的行為,而不用修改模型的字段,你可以使用代理模型。

抽象基類

基類並不會創建任何的數據庫,繼承自其的子model才會創建包括基類的數據庫。

多表繼承

因為是隱藏的創建了一對一的關系,其反向關聯名字是默認的,如果你還存在和父model的一對多或者多對多的關系,那么你必須指定它們的related_name,否則它們都用默認的就會發生沖突。

代表模型

有時,你可能只想更改 model 在 Python 層的行為實現。比如:更改默認的 manager ,或是添加一個新方法。

為原始模型創建一個代理 。你可以創建,刪除,更新代理 model 的實例,而且所有的數據都可以像使用原始 model 一樣被保存。 不同之處在於:你可以在代理 model 中改變默認的排序設置和默認的 manager ,更不會對原始 model 產生影響

多重模型

一般來說,你並不需要繼承多個父類。多重繼承主要對“mix-in”類有用:向每個繼承mix-in的類添加一個特定的、額外的字段或者方法。你應該嘗試將你的繼承關系保持得盡可能簡潔和直接,這樣你就不必費很大力氣來弄清楚某段特定的信息來自哪里。

不允許重寫字段。普通的 Python 類繼承允許子類覆蓋父類的任何屬性。 但在 Django 中,重寫 Field實例是不允許的(至少現在還不行)。如果基類中有一個 author字段,你就不能在子類中創建任何名為 author的字段。

查詢

關聯對象參考

就像 remove() 方法一樣,clear()只能在 null=True的ForeignKey上被調用,也可以接受bulk關鍵詞參數。

注意,對於所有類型的關聯字段,add()、create()、remove()和clear()都會馬上更新數據庫。換句話說,在關聯的任何一端,都不需要再調用save()方法。

獲取對象

每個模型至少擁有一個管理器,其默認命名為objects。

鏈式過濾

查詢集的篩選結果還是查詢集,所以可以將篩選結果鏈接在一起,表示一個鏈式過濾:

Entry.objects.filter(headline__startswith='What')
.exclude(pub_date__gte=datetime.date.today())
.filter(pub_date__gte=datetime(2005, 1, 30))

需要注意的是,查詢集是懶惰的,只有在請求其的時候才會去訪問數據庫。

使用get

注意使用get方法,如果其不存在數據或者存在多條數據,都會拋出錯誤,所以要保證只有一條單獨的數據。

另外一些查詢字段:

  • exact:精確匹配,通常我們查詢時使用的字段都包含了exact,只不過Dangjo都默認幫你處理好了;
  • iexact:匹配,忽略大小寫;
  • contains,icontains:包含和忽略大小寫的包含;
  • startswith,endswith,istartswith,iendswith:以某字符串開頭和其忽略大小寫的情況;
  • pk:和主鍵的作用一樣,任何查詢類型都可以與pk 結合來完成一個模型上對主鍵的查詢;

F表達式

F() 返回的實例用作查詢內部對模型字段的引用,Django支持對對象使用加法、減法、乘法、除法、取模以及冪計算等算術操作.

Entry.objects.filter(n_comments__gt=F('n_pingbacks') * 2)  # n_pingbacks為一個字段

當面對多值查詢的時候,需要注意使用filter,一種是同時滿足條件,另一種是至少滿足條件。

緩存和查詢集

為了避免查詢的內容不一致,可以先將查詢集進行緩存;但是如果訪問查詢集中不存在的部分,那么后面的部分查詢集將不會保存。

使用Q對象

如果使用Q對象,那么其必須位於所有關鍵字參數的前面。

Poll.objects.get(
    Q(pub_date=date(2005, 5, 2)) | Q(pub_date=date(2005, 5, 6)),
    question__startswith='Who')

刪除對象

注意,delete() 是唯一沒有在管理器 上暴露出來的查詢集方法。這是一個安全機制來防止你意外地請求Entry.objects.delete(),而刪除所有 的條目。如果你確實想刪除所有的對象,你必須明確地請求一個完全的查詢集:

update

update() 方法會立即執行並返回查詢匹配的行數。如果你想保存查詢集中的每個條目並確保每個實例的save() 方法都被調用,你不需要使用任何特殊的函數來處理。只需要迭代它們並調用save():

for item in my_queryset:
    item.save()

聚合

常用的字段包括:

  • Avg:平均值;
  • Count:返回對應expression的個數;
  • Max:返回expression的最大值;
  • Min:返回expression的最小值;
  • StdDev:標准差;
  • Sum:和;
  • Variance:方差;

annotate() 和 values() 字句的順序

和使用 filter() 子句一樣,作用於某個查詢的annotate() 和 values() 子句的使用順序是非常重要的。如果values() 子句在 annotate() 之前,就會根據 values() 子句產生的分組來計算注解。

但是,如果 annotate() 子句在 values()子句之前,就會根據整個查詢集生成注解。在這種情況下,values() 子句只能限制輸出的字段范圍。

比如:

Author.objects.annotate(average_rating=Avg('book__rating'))  # 根據作家id進行分組
Author.objects.values('name').annotate(average_rating=Avg('book__rating'))  # 根據作家名字進行分組

默認排序交換或order_by()

如果在 Meta 中指定了排序方式,那么在annotate的時候則會將默認的排序方式也作為一個分組項,所以要將其默認排序方式進行清空,做法如下:

Item.objects.values("data").annotate(Count("id")).order_by()

搜索

Managers

自定義管理器和模型繼承

可以繼承自models.Manger,從而自定義管理器。需要注意的是,如果使用自定義的管理器對象,Django會將遇到的第一位當成默認的管理器。可以在Meta中指定base_manager_name,這樣就不用自己去寫創建的代碼。

Django如何處理:

  1. 定義在非抽象基類中的管理器是不會被子類繼承的。如果你想從一個非抽象基類中重用管理器,只能在子類中重定義管理器。 這是因為這種管理器與定義它的模型綁定得非常緊密,所以繼承它們經常會導致異常的結果(特別是默認管理器運行的時候)。 因此,它們不應繼承給子類。
  2. 定義在抽象基類中的管理器總是被子類繼承的,是按 Python 的命名解析順序解析的(首先是子類中的命名覆蓋所有的,然后是第一個父類的,以此類推)。
  3. 如果類當中顯示定義了默認管理器,Django 就會以此做為默認管理器;否則就會從第一個抽象基類中繼承默認管理器; 如果沒有顯式聲明默認管理器,那么 Django 就會自動添加默認管理器。

注意在抽象模型上面定義一個自定義管理器的時候,不能調用任何使用這個抽象模型的方法,需要通過子管理器來使用。比如,這樣就是錯的:

AbstractBase.objects.do_something()

Django 為自定義管理器的開發者提供了一種方式:無論開發的管理器類是不是默認的管理器,它都應該可以用做自動管理器。 可以通過在管理器類中設置 use_for_related_fields屬性來做到這點。

class MyManager(models.Manager):
    use_for_related_fields = True  # 注意是在管理器中進行定義

但是需要注意的是,不要在這種類型的管理器子類中過濾掉任何結果,一個原因是自動管理器是用來訪問關聯模型的對象。 在這種情況下,Django 必須要能看到相關模型的所有對象,所以才能根據關聯關系得到任何數據 ;如果過濾掉了數據,那么會使得它所在的管理器不適於用做自動管理器。

原生SQL語句的查詢

有兩種方式,分別是使用ORM提供的函數或者不用ORM,但要注意的是,需要防止SQL注入。

使用raw

for p in Person.objects.raw('SELECT * FROM myapp_person'):
    print(p)

這里的myapp_person,Django會去從指定的myapp中找到對應的模型。

也可以通過字典的方式來傳遞參數,使用函數的參數params可以完全防止SQL注入攻擊,不要使用字符串的連接。:

name_map = {'first': 'first_name', 'last': 'last_name', 'bd': 'birth_date', 'pk': 'id'}
Person.objects.raw('SELECT * FROM some_other_table', translations=name_map)

當對其的結果進行數量的限制時,直接對數據庫進行操作,這樣可以稍微提升效率。

使用原生orm

如果你需要直接訪問數據庫,則格式如下:

from django.db import connection
def my_custom_sql(self):
    cursor = connection.cursor()
    cursor.execute("UPDATE bar SET foo = 1 WHERE baz = %s", [self.baz])
    cursor.execute("SELECT foo FROM bar WHERE baz = %s", [self.baz])
    row = cursor.fetchone()
    return row

延遲加載

注意延遲加載的問題,在每次訪問的時候,會從加載中返回指定內容並且指向下一個。

數據庫事務

管理事務

使用默認的管理事務

Django中提供了一種默認的方式,只需要在Settting中將ATOMIC_REQUESTS設置為True,其原理就是將把每一個請求用事務包裝起來,在調用一個view里面的方法之前Django先創建一個事務,如果發出的響應沒有問題,Django就會提交這個事務。如果在view這里產生一個異常,Django就會回滾這次事務。

但是,這也存在一個效率問題,對每個視圖開啟一個事務是有所耗費的。其對性能的影響依賴於應用程序對數據庫的查詢語句效率和數據庫當前的鎖競爭情況。

如果想要阻止視圖運行一個事務,則可以在view上使用non_atomic_requests裝飾器,那么對應的view則不會執行一個事務。

from django.db import transaction
@transaction.non_atomic_requests(using='other')
def my_other_view(request):
    do_stuff_on_the_other_database()

自定義管理事務

通過atomic(using=None, savepoint=True)裝飾器對具體的view進行管理事務,它也可以作為上下文管理器。

from django.db import transaction
@transaction.atomic
def viewfunc(request):
    # This code executes inside a transaction.
    do_stuff()
def viewfunc(request):
    # This code executes in autocommit mode (Django's default).
    do_stuff()
    with transaction.atomic():
        # This code executes inside a transaction.
        do_more_stuff()

在底層,Django的事務管理代碼:

  • 當進入到最外層的 atomic 代碼塊時會打開一個事務;
  • 當進入到內層atomic代碼塊時會創建一個保存點;
  • 當退出內部塊時會釋放或回滾保存點;
  • 當退出外部塊時提交或回退事物。

同樣的存在一個性能的考慮,所有打開的事務會對數據庫帶來性能成本。要盡量減少這種開銷,盡量保持您的交易盡可能短。 在Django的請求/響應周期,如果你使用 atomic()來執行長運行的進程,這尤其重要。

使用原生的api

具體參考

數據庫訪問優化

在模版中使用with標簽

{% with total=business.employees.count %}
    {{ total }} employee{{ total|pluralize }}
{% endwith %}

在數據庫中操作而不是在Python中操作

  • 在最基礎的層面上,使用過濾器和返現過濾器對數據庫進行過濾;
  • 使用**F表達式**在相同模型中基於其它字段進行過濾;
  • 使用數據庫中的aggregate和annotate;

用唯一的被索引的列來當作檢索的對象

比如,上面的就快過於下面,因為id被數據庫索引,而且是唯一的:

entry = Entry.objects.get(id=10)
entry = Entry.object.get(headline="News Item Title")

一次性檢索需要的東西

通過使用select_relatedprefetch_related,前者限於單值關系 - 外鍵和一對一關系,后者允許它預取多對多和多對一對象。它們都可以實現對數據的緩存。

獲取你想要的

使用QuerySet.values()和values_list()

當你僅僅想要一個帶有值的字典或者列表,並不需要使用ORM模型對象時,可以適當使用values()。對於在模板代碼中替換模型對象,這樣會非常有用 —— 只要字典中帶有的屬性和模板中使用的一致,就沒問題。

使用QuerySet.defer()和only()

如果一些數據庫的列你並不需要(或者大多數情況下並不需要),使用defer()和only()來避免加載它們。注意如果你確實要用到它們,ORM會在另外的查詢之中獲取它們。如果你不能夠合理地使用這些函數,不如不用。

另外,當建立起一個帶有延遲字段的模型時,要意識到一些(小的、額外的)消耗會在Django內部產生。不要不分析數據庫就盲目使用延遲字段,因為數據庫必須從磁盤中讀取大多數非text和VARCHAR數據,在結果中作為單獨的一行,即使其中的列很少。 defer()和only()方法在你可以避免加載大量文本數據,或者可能要花大量時間處理而返回給Python的字段時,特別有幫助。像往常一樣,應該先寫出個大概,之后再優化。

使用QuerySet.count()

如果你想要獲取大小,不要使用 len(queryset)

使用QuerySet.exists()

如果你想要知道是否存在至少一個結果,不要使用if queryset

不要過度使用count和exists

如果前面已經將某個數據進行了緩存,如果再使用count或者exist則會造成額外的查詢。比如下面的情況就是比較好的使用方法。

{% if display_inbox %}
  {% with emails=user.emails.all %}
    {% if emails %}
      <p>You have {{ emails|length }} email(s)</p>
      {% for email in emails %}
        <p>{{ email.body }}</p>
      {% endfor %}
    {% else %}
      <p>No messages today.</p>
    {% endif %}
  {% endwith %}
{% endif %}

使用QuerySet.update()和delete()

通過QuerySet.update()使用批量的SQL UPDATE語句,而不是獲取大量對象,設置一些值再單獨保存。與此相似,在可能的地方使用批量deletes。

但是要注意,這些批量的更新方法不會在單獨的實例上面調用save()或者delete()方法,意思是任何你向這些方法添加的自定義行為都不會被執行,包括由普通數據庫對象的信號驅動的任何方法。

直接使用外鍵的值

如果你僅僅需要外鍵當中的一個值,要使用對象上你已經取得的外鍵的值,而不是獲取整個關聯對象再得到它的主鍵。例如,執行:

entry.blog_id # 正確
entry.blog.id # 不好

沒有需要就不需要進行排序

排序並不是沒有代價的;每個需要排序的字段都是數據庫必須執行的操作。如果一個模型具有默認的順序(Meta.ordering),並且你並不需要它,通過在查詢集上無參調用order_by() 來移除它。

向你的數據庫添加索引可能有助於提升排序性能。

整體插入

創建對象時,盡可能使用bulk_create()來減少SQL查詢的數量。或者是在ManyToManyFields上。

Entry.objects.bulk_create([
    Entry(headline="Python 3.0 Released"),
    Entry(headline="Python 3.1 Planned")
])
my_band.members.add(me, my_friend)


免責聲明!

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



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