django-模型

2.模型

ORM簡介

  • · MVC框架中包括一個重要的部分,就是ORM,它實現了數據模型與數據庫的解耦,即數據模型的設計不須要依賴於特定的數據庫,經過簡單的配置就能夠輕鬆更換數據庫
  • · ORM是「對象-關係-映射」的簡稱,主要任務是:
    •  根據對象的類型生成表結構
    • 將對象、列表的操做,轉換爲sql語句
    • 將sql查詢到的結果轉換爲對象、列表
  • · 這極大的減輕了開發人員的工做量,不須要面對因數據庫變動而致使的無效勞動
  • · Django中的模型包含存儲數據的字段和約束,對應着數據庫中惟一的表

 

使用MySql數據庫

  • · 在虛擬環境中安裝mysql包
    pip install mysql-python
    pip install pymysql
  • · 在mysql中建立數據庫
    create database test2 charset=utf8
  • · 打開settings.py文件,修改DATABASES項
DATABASES = {

    'default': {

        'ENGINE': 'django.db.backends.mysql',

        'NAME': 'test2',

        'USER': '用戶名',

        'PASSWORD': '密碼',

        'HOST': '數據庫服務器ip,本地可使用localhost',

        'PORT': '端口,默認爲3306',

    }

}

開發流程

1. 在models.py中定義模型類,要求繼承自models.Modelhtml

2. 把應用加入settings.py文件的installed_app項python

3. 生成遷移文件mysql

4. 執行遷移生成表git

5. 使用模型類進行crud操做sql

使用數據庫生成模型類

python manage.py inspectdb > booktest/models.py

 

2.1.定義模型

  • 在模型中定義屬性,會生成表中的字段
  • django根據屬性的類型肯定如下信息:
    • 當前選擇的數據庫支持字段的類型
    • 渲染管理表單時使用的默認html控件
    • 在管理站點最低限度的驗證
  • django會爲表增長自動增加的主鍵列,每一個模型只能有一個主鍵列,若是使用選項設置某屬性爲主鍵列後,則django不會再生成默認的主鍵列
  • 屬性命名限制
    • 不能是python的保留關鍵字
    • 因爲django的查詢方式,不容許使用連續的下劃線

定義屬性

  • 定義屬性時,須要字段類型
  • 字段類型被定義在django.db.models.fields目錄下,爲了方便使用,被導入到django.db.models中
  • 使用方式
    •  導入from django.db import models數據庫

    • 經過models.Field建立字段類型的對象,賦值給屬性django

  • 對於重要數據都作邏輯刪除,不作物理刪除,實現方法是定義isDelete屬性,類型爲BooleanField,默認值爲False

字段類型

  • 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:小數點後的數字位數app

  • 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 這些設置是相互排斥的,他們之間的任何組合將會發生錯誤的結果

  • TimeField:使用Python的datetime.time實例表示的時間,參數同DateField
  • DateTimeField:使用Python的datetime.datetime實例表示的日期和時間,參數同DateField
  • FileField:一個上傳文件的字段
  • ImageField:繼承了FileField的全部屬性和方法,但對上傳的對象進行校驗,確保它是個有效的image

字段選項

  • 經過字段選項,能夠實現對字段的約束
  • 在字段對象時經過關鍵字參數指定
  • null:若是爲True,Django 將空值以NULL 存儲到數據庫中,默認值是 False
  • blank:若是爲True,則該字段容許爲空白,默認值是 False
  • 對比:null是數據庫範疇的概念,blank是表單驗證證範疇的
  • db_column:字段的名稱,若是未指定,則使用屬性的名稱
  • db_index:若值爲 True, 則在表中會爲此字段建立索引
  • default:默認值
  • primary_key:若爲 True, 則該字段會成爲模型的主鍵字段
  • unique:若是爲 True, 這個字段在表中必須有惟一值

關係

  • 關係的類型包括
    •  ForeignKey:一對多,將字段定義在多的端中
    • ManyToManyField:多對多,將字段定義在兩端中
    •  OneToOneField:一對一,將字段定義在任意一端中
  • 能夠維護遞歸的關聯關係,使用'self'指定,詳見「自關聯」
  • 能夠維護遞歸的關聯關係,使用'self'指定,詳見「自關聯」
  • 用一訪問多:對象.模型類小寫_set
    bookinfo.heroinfo_set
  • 用一訪問一:對象.模型類小寫
    heroinfo.bookinfo
  • 訪問id:對象.屬性_id
    heroinfo.book_id

     

元選項

  • 在模型類中定義類Meta,用於設置元信息
  • 元信息db_table:定義數據表名稱,推薦使用小寫字母,數據表的默認名稱
    <app_name>_<model_name>
    class Meta():
        db_table = 'HeroInfo'
  • ordering:對象的默認排序字段,獲取對象的列表時使用,接收屬性構成的列表
    class BookInfo(models.Model):
        ...
        class Meta():
            ordering = ['id']
  • 字符串前加-表示倒序,不加-表示正序
    class BookInfo(models.Model):
        ...
        class Meta():
            ordering = ['-id']
  • 排序會增長數據庫的開銷

示例演示

  • 建立test2項目,並建立booktest應用,使用mysql數據庫
  • 定義圖書模型
    class BookInfo(models.Model):
        btitle = models.CharField(max_length=20)
        bpub_date = models.DateTimeField()
        bread = models.IntegerField(default=0)
        bcommet = models.IntegerField(default=0)
        isDelete = models.BooleanField(default=False)
  • 英雄模型
    class HeroInfo(models.Model):
        hname = models.CharField(max_length=20)
        hgender = models.BooleanField(default=True)
        isDelete = models.BooleanField(default=False)
        hcontent = models.CharField(max_length=100)
        hbook = models.ForeignKey('BookInfo')
  • 定義index、detail視圖
  • index.html、detail.html模板
  • 配置url,可以完成圖書及英雄的展現

測試數據

  • 模型BookInfo的測試數據
    insert into booktest_bookinfo(btitle,bpub_date,bread,bcommet,isDelete) values
    ('射鵰英雄傳','1980-5-1',12,34,0),
    ('天龍八部','1986-7-24',36,40,0),
    ('笑傲江湖','1995-12-24',20,80,0),
    ('雪山飛狐','1987-11-11',58,24,0)
    BookInfo
  • 模型HeroInfo的測試數據
    insert into booktest_heroinfo(hname,hgender,hbook_id,hcontent,isDelete) values
    ('郭靖',1,1,'降龍十八掌',0),
    ('黃蓉',0,1,'打狗棍法',0),
    ('黃藥師',1,1,'彈指神通',0),
    ('歐陽鋒',1,1,'蛤蟆功',0),
    ('梅超風',0,1,'九陰白骨爪',0),
    ('喬峯',1,2,'降龍十八掌',0),
    ('段譽',1,2,'六脈神劍',0),
    ('虛竹',1,2,'天山六陽掌',0),
    ('王語嫣',0,2,'神仙姐姐',0),
    ('令狐沖',1,3,'獨孤九劍',0),
    ('任盈盈',0,3,'彈琴',0),
    ('嶽不羣',1,3,'華山劍法',0),
    ('東方不敗',0,3,'葵花寶典',0),
    ('胡斐',1,4,'胡家刀法',0),
    ('苗若蘭',0,4,'黃衣',0),
    ('程靈素',0,4,'醫術',0),
    ('袁紫衣',0,4,'六合拳',0)
    HeroInfo

     

2.2.模型成員

類的屬性

  •  objects:是Manager類型的對象,用於與數據庫進行交互
  • 當定義模型類時沒有指定管理器,則Django會爲模型類提供一個名爲objects的管理器
  •  支持明確指定模型類的管理器
    class BookInfo(models.Model):
        ...
        books = models.Manager()
  • 當爲模型類指定管理器後,django再也不爲模型類生成名爲objects的默認管理器

管理器Manager

  • 管理器是Django的模型進行數據庫的查詢操做的接口,Django應用的每一個模型都擁有至少一個管理器
  • 自定義管理器類主要用於兩種狀況
  • 狀況一:向管理器類中添加額外的方法:見下面「建立對象」中的方式二
  • 狀況二:修改管理器返回的原始查詢集:重寫get_queryset()方法
    class BookInfoManager(models.Manager):
        def get_queryset(self):
            return super(BookInfoManager, self).get_queryset().filter(isDelete=False)
    class BookInfo(models.Model):
        ...
        books = BookInfoManager()

建立對象

  • 當建立對象時,django不會對數據庫進行讀寫操做
  • 調用save()方法才與數據庫交互,將對象保存到數據庫中
  • 使用關鍵字參數構造模型對象很麻煩,推薦使用下面的兩種之式
  • 說明: _init _方法已經在基類models.Model中使用,在自定義模型中沒法使用,
  • 方式一:在模型類中增長一個類方法
    class BookInfo(models.Model):
        ...
        @classmethod
        def create(cls, title, pub_date):
            book = cls(btitle=title, bpub_date=pub_date)
            book.bread=0
            book.bcommet=0
            book.isDelete = False
            return book
    引入時間包:from datetime import *
    調用:book=BookInfo.create("hello",datetime(1980,10,11));
    保存:book.save()
    方法一
  • 方式二:在自定義管理器中添加一個方法
  • 在管理器的方法中,能夠經過self.model來獲得它所屬的模型類
class BookInfoManager(models.Manager):
    def create_book(self, title, pub_date):
        book = BookInfo()
        book.btitle = title
        book.bpub_date = pub_date
        book.bread=0
        book.bcommet=0
        book.isDelete = False
        return book

class BookInfo(models.Model):
    ...
    books = BookInfoManager()
調用:book=BookInfo.books.create_book("abc",datetime(1980,1,1))
保存:book.save()

#  在方式二中,能夠調用self.create()建立並保存對象,不須要再手動save()
class BookInfoManager(models.Manager):
    def create_book(self, title, pub_date):
        book = self.create(btitle = title,bpub_date = pub_date,bread=0,bcommet=0,isDelete = False)
        return book

class BookInfo(models.Model):
    ...
    books = BookInfoManager()
調用:book=Book.books.create_book("abc",datetime(1980,1,1))
查看:book.pk
View Code

 

實例的屬性

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

實例的方法

  • str (self):重寫object方法,此方法在將對象轉換成字符串時會被調用
  • save():將模型對象保存到數據表中
  • delete():將模型對象從數據表中刪除

2.3.模型查詢

簡介

  • 查詢集表示從數據庫中獲取的對象集合
  • 查詢集能夠含有零個、一個或多個過濾器
  • 濾器基於所給的參數限制查詢的結果
  • 從Sql的角度,查詢集和select語句等價,過濾器像where和limit子句
  • 接下來主要討論以下知識點
    • 查詢集
    • 字段查詢:比較運算符,F對象,Q對象

查詢集

  • 在管理器上調用過濾器方法會返回查詢集
  • 查詢集通過過濾器篩選後返回新的查詢集,所以能夠寫成鏈式過濾
  • 惰性執行:建立查詢集不會帶來任何數據庫的訪問,直到調用數據時,纔會訪問數據庫
  • 什麼時候對查詢集求值:迭代,序列化,與if合用
  • 返回查詢集的方法,稱爲過濾器
    • all()
    • filter()
    • exclude()
    •  order_by()
    • values():一個對象構成一個字典,而後構成一個列表返回
  • 寫法:
    filter(鍵1=值1,鍵2=值2)
    等價於
    filter(鍵1=值1).filter(鍵2=值2)
  • 返回單個值的方法
    • get():返回單個知足條件的對象
      • 若是未找到會引起"模型類.DoesNotExist"異常
      • 若是多條被返回,會引起"模型類.MultipleObjectsReturned"異常
    • count():返回當前查詢的總條數
    • first():返回第一個對象
    •  last():返回最後一個對象
    • exists():判斷查詢集中是否有數據,若是有則返回True

限制查詢集

  • 查詢集返回列表,可使用下標的方式進行限制,等同於sql中的limit和offset子句
  • 注意:不支持負數索引
  • 使用下標後返回一個新的查詢集,不會當即執行查詢
  • 若是獲取一個對象,直接使用[0],等同於[0:1].get(),可是若是沒有數據,[0]引起IndexError異常,[0:1].get()引起DoesNotExist異常

查詢集的緩存

  • 每一個查詢集都包含一個緩存來最小化對數據庫的訪問
  • 在新建的查詢集中,緩存爲空,首次對查詢集求值時,會發生數據庫查詢,django會將查詢的結果存在查詢集的緩存中,並返回請求的結果,接下來對查詢集求值將重用緩存的結果
  • 狀況一:這構成了兩個查詢集,沒法重用緩存,每次查詢都會與數據庫進行一次交互,增長了數據庫的負載
    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])
  • 什麼時候查詢集不會被緩存:當只對查詢集的部分進行求值時會檢查緩存,可是若是這部分不在緩存中,那麼接下來查詢返回的記錄將不會被緩存,這意味着使用索引來限制查詢集將不會填充緩存,若是這部分數據已經被緩存,則直接使用緩存中的數據

字段查詢

  • 實現where子句,做爲方法filter()、exclude()、get()的參數
  • 語法:屬性名稱__比較運算符=值
  • 表示兩個下劃線,左側是屬性名稱,右側是比較類型
  • 對於外鍵,使用「屬性名_id」表示外鍵的原始值
  • 轉義:like語句中使用了%與,匹配數據中的%,在過濾器中直接寫,例如:filter(title__contains="%")=>where title like '%\%%',表示查找標題中包含%的

比較運算符

# 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_date__year=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)
    

聚合(aggregate)函數   

  • 使用aggregate()函數返回聚合函數的值
  • 函數:Avg,Count,Max,Min,Sum
    from django.db.models import Max
    maxDate = list.aggregate(Max('bpub_date'))
  • count的通常用法:
    count = list.count()

     

F對象

# 可使用模型的字段A與字段B進行比較,若是A寫在了等號的左邊,則B出如今等號的右邊,須要經過F對象構造
list.filter(bread__gte=F('bcommet'))

# django支持對F()對象使用算數運算
list.filter(bread__gte=F('bcommet') * 2)

# F()對象中還能夠寫做「模型類__列名」進行關聯查詢
list.filter(isDelete=F('heroinfo__isDelete'))

# 對於date/time字段,可與timedelta()進行運算
list.filter(bpub_date__lt=F('bpub_date') + timedelta(days=1))

 

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對象必須位於關鍵字參數的前面

 

2.4.自鏈接

  • 對於地區信息,屬於一對多關係,使用一張表,存儲全部的信息
  • 相似的表結構還應用於分類信息,能夠實現無限級分類
  • 新建模型AreaInfo,生成遷移
    class AreaInfo(models.Model):
        atitle = models.CharField(max_length=20)
        aparent = models.ForeignKey('self', null=True, blank=True)
    )
  • 訪問關聯對象
    上級對象:area.aparent
    下級對象:area.areainfo_set.all()
  • 加入測試數據
  • 在booktest/views.py中定義視圖area
    from models import AreaInfo
    def area(request):
        area = AreaInfo.objects.get(id=10)
        context = {'area': area}
        return render(request, 'booktest/area.html', context)
  • 定義模板area.html
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>地區</title>
    </head>
    <body>
    <p>當前地區:{{area.atitle}}</p>
    <hr />
    <p>上級地區:{{area.aparent.atitle}}</p>
    <hr />
    下級地區:
    <ul>
        {%for a in area.areainfo_set.all%}
        <li>{{a.atitle}}</li>
        {%endfor%}
    </ul>
    </body>
    </html>
  • 在booktest/urls.py中配置一個新的urlconf
    urlpatterns = [
    
           url(r'^area/$', views.area, name='area')
    
    ]
相關文章
相關標籤/搜索