Django模型model

JCSON就是我發表於2017-11-12

前言

  • 根據前幾篇文章的分享已經瞭解djangoWeb開發一般步驟為:
    • 建立虛擬環境
    • 安裝django
    • 建立專案
    • 建立應用
    • 在model.py中建立模型類
    • 定義檢視
    • 配置url
    • 建立模板

1. ORM簡介

  • MVC框架中有一個重要的部分,就是ORM,它實現了資料模型與資料庫的解耦,即資料模型的設計不需要依賴於特定的資料庫,通過簡單的配置就可以輕鬆更換資料庫
  • ORM是“物件-關係-對映”的簡稱,主要任務是:
    • 根據物件的型別生成資料庫表結構
    • 將物件、列表的操作,轉換為sql語句
    • 將sql查詢到的結果轉換為物件、列表
  • Django中的模型包含儲存資料的欄位和約束,對應著資料庫中唯一的表
    ORM.png
    ORM.png

2. 使用MySql資料庫

  • 在虛擬環境中安裝mysql包

    pip install mysql-python

  • 在mysql中建立資料庫

    create databases test charset=utf8

  • 開啟settings.py檔案,修改DATABASES項

    DATABASES = {
    'default': {

      'ENGINE': 'django.db.backends.mysql',
      'NAME': 'test',
      'USER': '使用者名稱',
      'PASSWORD': '密碼',
      'HOST': '資料庫伺服器ip,本地可以使用localhost',
      'PORT': '埠,預設為3306',複製程式碼

    }
    }

3. Django模型類開發流程

  • 在models.py中定義模型類,要求繼承自models.Model
  • 把應用加入settings.py檔案的installed_app項
  • 生成遷移檔案
  • 執行遷移生成表
  • 使用模型類進行CRUD操作

4. 定義模型類

  • 在模型中定義屬性,會生成資料庫表中的欄位
  • django根據屬性的型別確定以下資訊:
    • 當前選擇的資料庫支援欄位的型別
      • 渲染管理表單時使用的預設html控制元件
      • 在管理站點最低限度的驗證
  • django會為表增加自動增長的主鍵列,每個模型只能有一個主鍵列,如果使用選項設定某屬性為主鍵列後,則django不會再生成預設的主鍵列
  • 屬性命名限制
    • 不能是python的保留關鍵字
    • 由於django的查詢方式,不允許使用連續的下劃線

      5. 定義模型屬性

  • 定義屬性時,需要欄位型別
  • 欄位型別被定義在django.db.models.fields目錄下,為了方便使用,被匯入到django.db.models中
  • 使用方式
    • 匯入from django.db import models
    • 通過models.Field建立欄位型別的物件,賦值給屬性
  • 對於重要資料都做邏輯刪除,不做物理刪除,實現方法是定義isDelete屬性,型別為BooleanField,預設值為False

    6. 定義欄位型別

  • TimeField:使用Python的datetime.time例項表示的時間,引數同DateField

  • DateTimeField:使用Python的datetime.datetime例項表示的日期和時間,引數同DateField
  • FileField:一個上傳檔案的欄位
  • ImageField:繼承了FileField的所有屬性和方法,但對上傳的物件進行校驗,確保它是個有效的image
  • AutoField:一個根據實際ID自動增長的IntegerField,通常不指定
    • 如果不指定,一個主鍵欄位將自動新增到模型中
  • BooleanField:true/false 欄位,此欄位的預設表單控制是CheckboxInput
  • NullBooleanField:支援null、true、false三種值
  • CharField(max_length=字元長度):字串,預設的表單樣式是 TextInput
  • TextField:大文字欄位,一般超過4000使用,預設的表單控制元件是Textarea
  • IntegerField:整數
  • DecimalField(max_digits=None, decimal_places=None):使用python的Decimal例項表示的十進位制浮點數
  • DecimalField.max_digits:位數總數
  • DecimalField.decimal_places:小數點後的數字位數
  • FloatField:用Python的float例項來表示的浮點數
  • DateField[auto_now=False, auto_now_add=False]):使用Python的datetime.date例項表示的日期
    • 引數DateField.auto_now:每次儲存物件時,自動設定該欄位為當前時間,用於"最後一次修改"的時間戳,它總是使用當前日期,預設為false
      • 引數DateField.auto_now_add:當物件第一次被建立時自動設定當前時間,用於建立的時間戳,它總是使用當前日期,預設為false
      • 該欄位預設對應的表單控制元件是一個TextInput. 在管理員站點新增了一個JavaScript寫的日曆控制元件,和一個“Today"的快捷按鈕,包含了一個額外的invalid_date錯誤訊息鍵
      • auto_now_add, auto_now, and default 這些設定是相互排斥的,他們之間的任何組合將會發生錯誤的結果

7. 模型類中欄位選項

  • 通過欄位選項,可以實現對欄位的約束
  • 在欄位物件時通過關鍵字引數指定
  • null:如果為True,Django 將空值以NULL 儲存到資料庫中,預設值是 False
  • blank:如果為True,則該欄位允許為空白,預設值是 False
  • 對比:null是資料庫範疇的概念,blank是表單驗證證範疇的
  • db_column:欄位的名稱,如果未指定,則使用屬性的名稱
  • db_index:若值為 True, 則在表中會為此欄位建立索引
  • default:預設值
  • primary_key:若為 True, 則該欄位會成為模型的主鍵欄位
  • unique:如果為 True, 這個欄位在表中必須有唯一值

8. 模型類之間關係

  • 關係的型別包括
    • ForeignKey:一對多,將欄位定義在多的端中
    • ManyToManyField:多對多,將欄位定義在兩端中
    • OneToOneField:一對一,將欄位定義在任意一端中
  • 可以維護遞迴的關聯關係,使用'self'指定,就是“自關聯”
  • 用一訪問多:物件.模型類小寫_set

    mytestinfo.testinfo_set.all()

  • 用一訪問一:物件.模型類小寫

    testinfo.mytestinfo

  • 訪問id:物件.屬性_id

    testinfo.mytest_id

9. 模型類中定義類Meta

  • 元資訊db_table:定義資料表名稱,推薦使用小寫字母,資料表的預設名稱

    <應用名稱>_<模型類名稱>

  • ordering:物件的預設排序欄位,獲取物件的列表時使用,接收屬性構成的列表

    class TestInfo(models.Model):

               class Meta():
                         ordering = ['id']複製程式碼
  • 字串前加-表示倒序,不加-表示正序

    class TestInfo(models.Model):
    class Meta():

      ordering = ['-id']複製程式碼

10. 模型類的管理器

  • objects:是Manager型別的物件,用於與資料庫進行互動
  • 當定義模型類時沒有指定管理器,則Django會為模型類提供一個名為objects的管理器
  • 支援明確指定模型類的管理器

    class BookInfo(models.Model):
    books = models.Manager()

  • 當為模型類指定管理器後,django不再為模型類生成名為objects的預設管理器

  • 管理器是Django的模型進行資料庫的查詢操作的介面,Django應用的每個模型都擁有至少一個管理器

  • 自定義管理器類主要用於兩種情況

    • 向管理器類中新增額外的方法建立管理器物件儲存資料到資料庫

      class TestInfoManager(models.Manager):
      def create_test(self, title, update):
      test = self.model()
      test.isDelete = False
      return test

      class TestInfo(models.Model):
      tests = TestInfoManager()
      方法呼叫:book=TestInfo. tests.create_ test("abc",datetime(1980,1,1))
      儲存:test.save()

    • 修改管理器返回的原始查詢集:重寫get_queryset()方法

      class TestInfoManager(models.Manager):
      def get_queryset(self):
      return super(TestInfoManager, self).get_queryset().filter(isDelete=False)
      class TestInfo(models.Model):
      tests = TestInfoManager()

  • 當建立物件時,django不會對資料庫進行讀寫操作

  • 在管理器的方法中,可以通過self.model來得到它所屬的模型類
  • 呼叫save()方法才與資料庫互動,將物件儲存到資料庫中
  • 使用關鍵字引數構造模型物件很麻煩,推薦使用下面的兩種之式
  • 說明: init 方法已經在基類models.Model中使用,在自定義模型中無法使用
  • 在模型類中增加一個類方法儲存資料到資料庫

    class BookInfo(models.Model):
    @classmethod
    def create(cls, title):

      test = cls(btitle=title)
      test.isDelete = False
      return test複製程式碼

    引入時間包:from datetime import *
    呼叫:test=TestInfo.create("hello");
    儲存:test.save()

  • DoesNotExist:在進行單個查詢時,模型的物件不存在時會引發此異常,結合try/except使用

  • 例項方法
    • str (self):重寫object方法,此方法在將物件轉換成字串時會被呼叫
      • delete():將模型物件從資料表中刪除

11. 模型類的查詢

  • 查詢集表示從資料庫中獲取的物件集合
  • 查詢集可以含有零個、一個或多個過濾器
  • 過濾器基於所給的引數限制查詢的結果
  • 從Sql的角度,查詢集和select語句等價,過濾器像where和limit子句
  • 接下來主要討論如下知識點
    • 查詢集
    • 欄位查詢:比較運算子,F物件,Q物件
      (1)模型類查詢集合
  • 在管理器上呼叫過濾器方法會返回查詢集
  • 查詢集經過過濾器篩選後返回新的查詢集,因此可以寫成鏈式過濾
  • 惰性執行:建立查詢集不會帶來任何資料庫的訪問,直到呼叫資料時,才會訪問資料庫
  • 何時對查詢集求值:迭代,序列化,與if合用
  • 返回查詢集的方法,稱為過濾器,管理器物件方法有all()、filter()、exclude()、order_by()、values()

  • 返回單個值的方法

    • get():返回單個滿足條件的物件
    • 如果未找到會引發"模型類.DoesNotExist"異常
    • 如果多條被返回,會引發"模型類.MultipleObjectsReturned"異常
    • count():返回當前查詢的總條數
    • first():返回第一個物件
    • last():返回最後一個物件
    • exists():判斷查詢集中是否有資料,如果有則返回True
  • 限制查詢集,如果獲取一個物件,直接使用[0]
  • 模型查詢集的快取

    • 這構成了兩個查詢集,無法重用快取,每次查詢都會與資料庫進行一次互動,增加了資料庫的負載

      print([e.title for e in Entry.objects.all()])
      print([e.title for e in Entry.objects.all()])

      • 兩次迴圈使用同一個查詢集,第二次使用快取中的資料

        querylist=Entry.objects.all()
        print([e.title for e in querylist])
        print([e.title for e in querylist])

  • 何時查詢集不會被快取:當只對查詢集的部分進行求值時會檢查快取,但是如果這部分不在快取中,那麼接下來查詢返回的記錄將不會被快取,這意味著使用索引來限制查詢集將不會填充快取,如果這部分資料已經被快取,則直接使用快取中的資料

  • 比較運算子:表示兩個下劃線,左側是屬性名稱,右側是比較型別

    • exact:表示判等,大小寫敏感;如果沒有寫“ 比較運算子”,表示判等

      filter(isDelete=False)

    • contains:是否包含,大小寫敏感

      exclude(btitle__contains='傳')

      • startswith、endswith:以value開頭或結尾,大小寫敏感

        exclude(btitle__endswith='傳')

      • isnull、isnotnull:是否為null

        filter(btitle__isnull=False)

      • 在前面加個i表示不區分大小寫,如iexact、icontains、istarswith、iendswith

      • in:是否包含在範圍內

        filter(pk__in=[1, 2, 3, 4, 5])

      • gt、gte、lt、lte:大於、大於等於、小於、小於等於

        filter(id__gt=3)

      • year、month、day、week_day、hour、minute、second:對日期間型別的屬性進行運算

        filter(bpub_dateyear=1980)
        filter(bpub_date
        gt=date(1980, 12, 31))

      • 跨關聯關係的查詢:處理join查詢

        語法:模型類名 <屬性名> <比較>
        注:可以沒有<比較>部分,表示等於,結果同inner join
        可返向使用,即在關聯的兩個模型中都可以使用
        filter(heroinfo
        hcontent__contains='八')

      • 查詢的快捷方式:pk,pk表示primary key,預設的主鍵是id

        filter(pk__lt=6)

(2)聚合函式
  • 使用aggregate()函式返回聚合函式的值
  • 函式:Avg,Count,Max,Min,Sum

    from django.db.models import Max
    maxDate = list.aggregate(Max('bpub_date'))

  • count的一般用法:

    count = list.count()

(3)F物件
  • 可以使用模型的欄位A與欄位B進行比較,如果A寫在了等號的左邊,則B出現在等號的右邊,需要通過F物件構造

    list.filter(read__gte=F('commet'))

  • django支援對F()物件使用算數運算

    list.filter(read__gte=F('commet') * 2)

  • F()物件中還可以寫作“模型類__列名”進行關聯查詢

    list.filter(isDelete=F('testinfo__isDelete'))

  • 對於date/time欄位,可與timedelta()進行運算

    list.filter(update__lt=F('update') + timedelta(days=1))

(3)Q物件
  • 過濾器的方法中關鍵字引數查詢,會合併為And進行
  • 需要進行or查詢,使用Q()物件
  • Q物件(django.db.models.Q)用於封裝一組關鍵字引數,這些關鍵字引數與“比較運算子”中的相同

    from django.db.models import Q
    list.filter(Q(pk_ _lt=6))

  • Q物件可以使用&(and)、|(or)操作符組合起來

  • 當操作符應用在兩個Q物件時,會產生一個新的Q物件

    list.filter(pk_ lt=6).filter(bcommet gt=10)
    list.filter(Q(pk
    lt=6) | Q(bcommet _gt=10))

  • 使用~(not)操作符在Q物件前表示取反

    list.filter(~Q(pk__lt=6))

  • 可以使用&|~結合括號進行分組,構造做生意複雜的Q物件

  • 過濾器函式可以傳遞一個或多個Q物件作為位置引數,如果有多個Q物件,這些引數的邏輯為and
  • 過濾器函式可以混合使用Q物件和關鍵字引數,所有引數都將and在一起,Q物件必須位於關鍵字引數的前面

12. 模型自關聯

  • 對於地區資訊,屬於一對多關係,使用一張表,儲存所有的資訊
  • 類似的表結構還應用於分類資訊,可以實現無限級分類

    class AreaInfo(models.Model):
    atitle = models.CharField(max_length=20)
    aParent = models.ForeignKey('self', null=True, blank=True)

相關文章