Models#1

  • model是Django中的數據模型
    • 每個model都是繼承自django.db.models.Model的子類
    • 每個model都映射一個數據表
    • model中的每個類屬性對應著數據表中的一列
    • django支持ORM
  • 創建model并進行migrate后
    • Django會自動生成表名(可以自定義
    • Django會自動增加主鍵一列(可以自定義)
    • Django會根據不同數據庫創建不同的SQL語句
  • Field中的常見選項
    • null:允許該列數據為空(默認為False)
    • blank:主要用于是否允許表單為空(默認為False)
    • choices:為一個Field提供可選項(并且默認生成的表單為一個選項)
      from django.db import models
      
      class Person(models.Model):
          # choices的對象是一個可迭代對象,其元素為‘含有兩個元素的元組’
          SHIRT_SIZES = (
              ('S', 'Small'),
              ('M', 'Medium'),
              ('L', 'Large'),
          )
          name = models.CharField(max_length=60)
          shirt_size = models.CharField(max_length=1, choices=SHIRT_SIZES)
        
      # choice API
      >>> p = Person(name="Fred Flintstone", shirt_size="L")
      >>> p.save()
      >>> p.shirt_size
      'L'
      >>> p.get_shirt_size_display()   # get_FOO_display()方法可以顯示具體內容
      'Large'
      
    • default:既可以是一個數值對象,也可以是一個可調用對象
    • help_text:在生成的表單中展示‘幫助’信息
    • primary_key:將某一列設置為主鍵(該列變為只讀);默認為False,即Django會自動創建一個整型主鍵
    • unique:該列中的每個數據必須獨一無二(默認為False)
  • 自動生成主鍵
    默認情況下,如果不顯式指定主鍵,Django會在model中自動添加以下屬性
    id = models.AutoField(primary_key=True)
    
  • 顯式指定列名
    對于非關系型列(即非ForeignKeyField,ManyToManyField,OneToOneField),第一個位置參數為空時,將默認屬性名為列名;否則使用位置參數作為列名
    對于關系型列,需要指定位置參數以表明關聯的數據表
    # 列名為"person's first name"
    first_name = models.CharField("person's first name", max_length=30)
    
    # 列名為"first_name"
    first_name = models.CharField(max_length=30)
    
    # 關聯表為"Poll"
    poll = models.ForeignKey(
        Poll,
        on_delete=models.CASCADE,
        verbose_name="the related poll",
    )
    
  • 關聯
    • Many-to-one 關聯
      使用django.db.models.ForeignKey,第一個位置參數需要指定關聯表名
    • Many-to-many 關聯
      使用django.db.models.ManyToManyField(相關的兩個表中,只需要在一個表中指定即可)
      可以顯式的創建many-to-many的關聯數據表
      from django.db import models
      
      class Person(models.Model):
          name = models.CharField(max_length=128)
      
          def __str__(self):              # __unicode__ on Python 2
              return self.name
      
      class Group(models.Model):
          name = models.CharField(max_length=128)
          # 通過through指定關聯表
          members = models.ManyToManyField(Person, through='Membership')
      
          def __str__(self):              # __unicode__ on Python 2
              return self.name
      
      class Membership(models.Model):
          person = models.ForeignKey(Person, on_delete=models.CASCADE)
          group = models.ForeignKey(Group, on_delete=models.CASCADE)
          date_joined = models.DateField()
          invite_reason = models.CharField(max_length=64)
      
    • One-to-one 關聯
      使用django.db.models.OneToOneField,可以用于擴展某一model
  • Meta 選項
    Model的Meta中保存著所有非列的屬性(比如ordering(默認排序)、db_table(數據表名稱)等等)
    from django.db import models
    
    class Ox(models.Model):
        horn_length = models.IntegerField()
        
        # class Meta 是可選項
        class Meta:
            ordering = ["horn_length"]
            verbose_name_plural = "oxen"
    
  • Model 的方法
    我們可以在Model中自定義方法,也可以使用或者重載Model中已有的方法
    有兩個方法在大多數情況下需要我們自己定義
    • __ str__()
    • get_absolute_url()
      該方法告訴Django如何得到一個對象的URL(一般使用django的reverse()函數)
      def get_absolute_url(self):
          from django.urls import reverse
          return reverse('people.views.details', args=[str(self.id)])
      
    重載Model中已定義的方法
    from django.db import models
    
    class Blog(models.Model):
        name = models.CharField(max_length=100)
        tagline = models.TextField()
    
        def save(self, *args, **kwargs):
            do_something()
            # 關鍵在于對Model.save()方法的繼承上,另外通過使用(*args, **kwargs)參數可以自動獲取相關參數
            super(Blog, self).save(*args, **kwargs) # Call the "real" save() method.
            do_something_else()
    

  • Model的繼承
    django中存在三種繼承
    • Abstract base classes
    • Multitable inheritance
    • Proxy models
  • Abstract base classes
    在class Meta中設置abstract = True,就可以將該model變為抽象類——該類中定義的列屬性可以被子類所繼承而無需重新定義,且class Meta中的屬性亦會被繼承(除了abstract = True)
    Abstract base classes并不會產生數據表,也不能直接用于創建實例
    from django.db import models
    
    class CommonInfo(models.Model):
        name = models.CharField(max_length=100)
        age = models.PositiveIntegerField()
        
        # 將CommonInfo聲明為一個abc類
        class Meta:
            abstract = True
            ordering = ['name']
    
    class Student(CommonInfo):
        # Student 類自動繼承name和age列
        home_group = models.CharField(max_length=5)
    
        class Meta: 
            # Student 類會繼承CommonInfo中的Meta的信息
            # 不過在此之前會自動設置abstract=False(當然也可以自己顯式地設置abstract=True從而成為abc類)
            db_table = 'student_info'
    
    為了指定子類關聯表列的relate_name,可以在abc類的關聯表列中進行設置
    # common/models.py
    from django.db import models
    
    class Base(models.Model):
        m2m = models.ManyToManyField(
            OtherModel,
            # 若不設置related_name,則默認為"子類名 + '_set'"
            # %(app_label)s 指代當前應用名稱
            # %(class)s 指代當前類的類名
            related_name="%(app_label)s_%(class)s_related",
            related_query_name="%(app_label)s_%(class)ss",
        )
    
        class Meta:
            abstract = True
    
    # OtherModel 使用 ChildA 類時的屬性名將是'common_childa_related'
    class ChildA(Base):
        pass
    
    class ChildB(Base):
        pass
    
  • Multi-table inheritance
    父類和子類都可以生成數據表,且子類會繼承父類的類屬性(列屬性),但父類和子類是兩個不同的表
    此外,不同于abc類,子類不會繼承父類class Meta中的屬性
  • Proxy models
    Proxy model用于當你只想為一個表增加一些方法或者Meta屬性,而不想改變原model的代碼時
    from django.db import models
    
    class Person(models.Model):
        first_name = models.CharField(max_length=30)
        last_name = models.CharField(max_length=30)
    
    class MyPerson(Person):
        class Meta:
            # 指定該類為Person的代理數據模型
            proxy = True
            # 在該proxy model中可以增加一個額外的Meta屬性
            odering = ['last_name']
    
        # 在該proxy model中可以增加一些額外的方法
        def do_something(self):
            # ...
            pass
    
    # 需要注意的一點是Person和MyPerson類都可以調用Person數據表中的數據
    # 不同之處在于通過Person類創建/查找到的實例中沒有ordering屬性,也不能調用do_something方法
    
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 229,565評論 6 539
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,115評論 3 423
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 177,577評論 0 382
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,514評論 1 316
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,234評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,621評論 1 326
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,641評論 3 444
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,822評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,380評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,128評論 3 356
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,319評論 1 371
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,879評論 5 362
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,548評論 3 348
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,970評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,229評論 1 291
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,048評論 3 397
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,285評論 2 376

推薦閱讀更多精彩內容