第6天:數據庫配置與模型

  •  數據庫配置
  •  Django模型類定義
  •  字段類型與選項
  •  模型遷移
  •  Django交互環境
  •  增
  •  刪
  •  改
  •  基本查詢
  •  過濾查詢
  •  F對象
  •  Q對象
  •  排序
  •  聚合
  •  關聯查詢
  •  查詢集QuerySet
  •  自定義模型管理器

 

數據庫配置

ORM Object relational mapping 對象關係映射,把類和數據庫表對應,把對象和表記錄對應,經過類和對象操做數據庫表中的數據,而不須要編寫SQL語句python

一、使用MySQL數據庫首先須要安裝驅動程序mysql

pip install PyMySQL

二、在Django的工程同名子目錄的__init__.py中添加以下語句,做用是讓Django的ORM能以mysqldb的方式來調用PyMySQLgit

from pymysql import install_as_MySQLdb

install_as_MySQLdb()

三、編輯settings.py,修改DATABASE配置信息sql

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'HOST': '127.0.0.1',#主機 
        'PORT': 3306,       #端口
        'USER': 'root',     #數據庫用戶名
        'PASSWORD': 'root', #數據庫用戶密碼
        'NAME': 'demo'   #數據名字
    }
}
settings.py

四、在MySQL中建立數據庫shell

create database demo default charset=utf8;

 

Django模型類的定義

  • 模型類被定義到‘應用/models.py文件中’
  • 模型類必須繼承Model類,位於包django.db.models中

建立應用book,在models.py文件中定義模型數據庫

from django.db import models


class Book(models.Model):
    title = models.CharField(max_length=20, verbose_name='名稱')
    pub_date = models.DateField(verbose_name='發佈日期')
    read_num = models.IntegerField(default=0, verbose_name='閱讀量')
    comment_num = models.IntegerField(default=0, verbose_name='評論量')
    is_delete = models.BooleanField(default=False, verbose_name='邏輯刪除')

    class Meta:
        db_table = 'book'   #指明數據庫表名
        verbose_name = '圖書'  #在admin站點中顯示的名稱
        verbose_name_plural = verbose_name #顯示覆數的名稱

    def __str__(self):
        """定義每一個數據對象的顯示信息"""
        return self.title


class Hero(models.Model):
    GENDER_CHOICES = (
        (0, 'male'),
        (1, 'female')
    )
    name = models.CharField(max_length=20, verbose_name='名稱')
    gender = models.SmallIntegerField(choices=GENDER_CHOICES, default=0, verbose_name='性別')
    comment = models.CharField(max_length=200, null=True, verbose_name='描述信息')
    book = models.ForeignKey(Book, on_delete=models.CASCADE, verbose_name='圖書') #CASCADE級聯,刪除主表數據時連同一塊兒刪除外鍵表中的數據
    is_delete = models.BooleanField(default=False, verbose_name='邏輯刪除')

    class Meta:
        db_table = 'hero'
        verbose_name = '英雄'
        verbose_name_plural = verbose_name

    def __str__(self):
        return self.name
book.models

 關於主鍵django

  • 主鍵:primary key,簡寫 pk
  • 不須要主動定義,django會自動生成自增加的主鍵,屬性名叫 id,
  • 若是開發者本身定義了主鍵,則django不會再生成默認的主鍵

 

字段類型與選項

類型 說明
AutoField 自動增加的IntegerField,一般不用指定,不指定時Django會自動建立名爲id的自動增加屬性
BooleanField 布爾字段,值爲True或False
NullBooleanField 支持Null、True、False三種值
CharField 字符串,必須指定:max_length,表示最大字符個數
TextField 大文本字段,通常超過4000個字符時使用
IntegerField 整數
DecimalField 十進制浮點數,用python中的Decimal實例來表示
必須指定: max_digits總位數,decimal_places小數位數。 
FloatField 浮點數
DateField 日期 
1) 參數auto_now表示每次修改保存對象時,自動設置該字段爲當前時間,用於保存"最後一次修改"時間,默認爲False; 
2) 參數auto_now_add表示當對象第一次被建立時自動設置保存當前時間,用於保存"建立時間"時間,默認爲值爲False; 
3) 參數auto_now_addauto_now是相互排斥的,不能同時用到一個屬性中
TimeField 時間,參數同DateField
DateTimeField 日期時間,參數同DateField
FileField 上傳文件字段
ImageField 繼承於FileField,對上傳的內容進行校驗,確保是有效的圖片

 

選項 默認值 描述 是否要遷移修改表結構
null False True表示表字段容許爲空
unique False True表示表字段不能重複
db_column 屬性名稱 表字段名稱
primary_key False True表示字段設置爲了主鍵,通常做爲AutoField的選項使用
default - 默認值
blank False 在django管理後臺新增或編輯一條表數據時,該字段是否容許爲空;
null是數據庫範疇的概念,blank是表單驗證範疇的
choices - 在django管理後臺新增或編輯一條表數據時,該字段顯示爲下拉框,默認爲編輯框
  • choices: 性別屬性使用了choices選項後,在錄入一條數據時,會如下拉框顯示
  • blank:blank屬性默認值爲false, 表示錄入一條數據時,當前字段必須填寫,不能爲空,不然js端js校驗不經過,例如:下圖的comment員工備註信息字段。緩存

外鍵app

  • ForeignKey: 一對多,將 關聯屬性 定義在多的一端中
  • ManyToManyField: 多對多,將 關聯屬性 定義任意一方中
  • OneToOneField: 一對一,將 關聯屬性 定義在任意一方中

 

模型遷移

定義完模型類之後,咱們須要把模型生成到數據庫裏面去ide

python manage.py mikemigrations
python manage.py migrate

 

Django交互環境

在Django交互環境中,能夠直接執行django項目代碼,相似ipython交換環境

經過shell命令進入Django交換環境

insert into book(name,pub_date,read_num,comment_num,is_delete) values
('射鵰英雄傳','1980-5-1',12,34,0),
('天龍八部','1986-7-24',36,40,0),
('笑傲江湖','1995-12-24',28,18,0),
('雪山飛狐','1987-11-11',58,24,0);

insert into hero(name,gender,book_id,comment,is_delete) 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);
給數據庫添加測試數據

 

如今咱們能夠在Django交互環境測試數據庫操做,首先咱們來對數據庫進行增長操做,有兩種方式

1)模型類對象.save()

from book.models import Book, Hero
from datetime import date


book = Book(
  title='西遊記',
  pu_date=date(1988,1,1),
  read_num=10,
  comment_num=10
)

book.save
增長一個圖書

2)經過模型類.objects.creare()保存

from book.models import Book, Hero 

b = Book.objects.get(title='西遊記')

Hero.objects.create(
  name='沙悟淨',
  gender=0,
  book=book
)

或者
Hero.objects.create(
  name='沙悟淨',
  gender=0,
  book_id=book.id
)
增長一個英雄

 

刪除記錄有兩種方式

1)模型類對象.delete()

book = Book.objects.get(id=1)
book.delete()
刪除id爲1的圖書

2)模型類.filter(條件).delete()

Book.objects.filter(id=1).delete()
刪除id爲1的圖書

注意事項: on_delete選項

  • 默認值爲models.CASCADE,當刪除圖書時,會刪除相關聯的英雄
  • 若是不想刪除關聯數據,可設置on_delete爲 PROTECT

 

修改記錄有如下兩種方式

1)模型類對象.save()

h = Hero.objects.get(name='沙悟淨')
h.name = '沙僧'
h.save()
把沙悟淨的名字改成沙僧

2)模型類.filter()條件.update(屬性1=值1, 屬性2=值2, ...)

Hero.objetcs.filter(name='豬八戒').update(name='豬悟能')
把豬八戒的名字改成豬悟能

 

基本查詢

get 查詢單一結果,若是不存在或拋出模型類.DoesNotExist異常,經過存在多條記錄會拋出MultipleObjectsReturned異常

#查詢id爲3的圖書
In [7]: Book.objects.get(id=3)
Out[7]: <Book: 笑傲江湖>

#查詢id爲100的圖書,該圖書其實不存在
In [8]: Book.objects.get(id=100)
---------------------------------------------------------------------------
DoesNotExist                              Traceback (most recent call last)
...

#查詢is_delete爲false的圖書,有多條
In [9]: Book.objects.get(is_delete=0)
---------------------------------------------------------------------------
MultipleObjectsReturned                   Traceback (most recent call last)
示例

all 查詢多個結果

In [6]: Book.objects.all()
Out[6]: <QuerySet [<Book: 射鵰英雄傳>, <Book: 天龍八部>, <Book: 笑傲江湖>, <Book: 雪山飛狐>, <Book: 西遊記>]>
查詢出全部的圖書

count 查詢結果數量

In [10]: Hero.objects.count()
Out[10]: 20
查詢英雄的總數

 

過濾查詢

  •  調用filter方法:模型類.objects.filter(模型屬性名__條件名=值)
  •  返回包含查詢結果數據的QuerySet對象

1)判等: exact

In [11]: Book.objects.filter(id__exact=1)
Out[11]: <QuerySet [<Book: 射鵰英雄傳>]>

可簡寫爲
In [12]: Book.objects.filter(id=1)
Out[12]: <QuerySet [<Book: 射鵰英雄傳>]>
查詢id爲1的圖書

2)模糊查詢: contains / endswith / startswith

In [13]: Hero.objects.filter(name__contains='')
Out[13]: <QuerySet [<Hero: 嶽不羣>, <Hero: 東方不敗>]>
查詢名字包含"不"的英雄
In [14]: Hero.objects.filter(name__startswith='')
Out[14]: <QuerySet [<Hero: 黃蓉>, <Hero: 黃藥師>]>
查詢名字以'黃'開頭的英雄
  • 上面查詢都是區分大小寫的,若是不想區分大小寫,只須要加個i,如 iexact、icontains、iendstartswith、istartswith
  • 如何想查詢包含%的字符,%不須要轉義

3)空查詢: isnull

In [17]: Book.objects.filter(title__isnull=False)
Out[17]: <QuerySet [<Book: 射鵰英雄傳>, <Book: 天龍八部>, <Book: 笑傲江湖>, <Book: 雪山飛狐>, <Book: 西遊記>]>
查看圖書名不爲空的圖書

4)範圍查詢: in

In [20]: Book.objects.filter(id__in=[1,3,5])
Out[20]: <QuerySet [<Book: 射鵰英雄傳>, <Book: 笑傲江湖>, <Book: 西遊記>]>
查詢id編號爲1,3,5的圖書

5)比較查詢: gt、lt、gte、lte

In [21]: Book.objects.filter(read_num__gt=20)
Out[21]: <QuerySet [<Book: 天龍八部>, <Book: 雪山飛狐>]>
查詢閱讀量大於20的圖書

6)日期查詢: year、month、day、week_day、hour、minute、second

In [22]: Book.objects.filter(pub_date__year=1980)                                                                                                               
Out[22]: <QuerySet [<Book: 射鵰英雄傳>]>
查詢1980年發表的圖書
In [23]: Book.objects.filter(pub_date__gt=date(1980,1,1))
Out[23]: <QuerySet [<Book: 射鵰英雄傳>, <Book: 西遊記>]>
查詢1980年1月1往後發表的圖書

 

F對象

以前查詢都是對象的屬性與常量值比較,兩個屬性怎麼比較?這就須要用到F對象

須要導包: from django.db.models import F

語法: F(屬性名)

In [25]: from django.db.models import F

In [26]: Book.objects.filter(read_num__gte=F('comment_num'))
Out[26]: <QuerySet [<Book: 雪山飛狐>, <Book: 西遊記>]>
查詢閱讀量大於等於評論量的圖書

能夠在F對象上使用算數運算

In [27]: from django.db.models import F

In [28]: Book.objects.filter(read_num__gt=F('comment_num') * 2)
Out[28]: <QuerySet [<Book: 雪山飛狐>]>
查詢閱讀量大於2倍評論量的圖書

 

Q對象

做用: 對查詢條件進行與 或 非(& | ~)的邏輯操做

須要導包: from django.db.models import Q

與: Q(查詢條件1) & Q(查詢條件2)

In [29]: from django.db.models import Q

In [30]: Hero.objects.filter(Q(id__gt=2) & Q(name__contains=''))
Out[30]: <QuerySet [<Hero: 黃藥師>]>

能夠簡寫爲
In [31]: Hero.objects.filter(id__gt=2, name__contains='')
Out[31]: <QuerySet [<Hero: 黃藥師>]>
查詢id大於2且名字包含'黃'的英雄

或: Q(查詢條件1) | Q(查詢條件2)

In [34]: Hero.objects.filter(Q(id__lt=2) | Q(name__contains=''))
Out[34]: <QuerySet [<Hero: 郭靖>, <Hero: 嶽不羣>, <Hero: 東方不敗>]>
查詢id小於2或名字包含'不'的英雄

非: ~Q(查詢條件)

Hero.objects.filter(~Q(id=3))
查詢id不等於3的英雄

 

 排序

做用: 對查詢結果進行排序,默認爲升序

用法:

  • 升序: 模型類.objects.order_by('屬性名')
  • 降序: 模型類.objects.order_by('-屬性名')
In [37]: Book.objects.all().order_by('-id')
Out[37]: <QuerySet [<Book: 西遊記>, <Book: 雪山飛狐>, <Book: 笑傲江湖>, <Book: 天龍八部>, <Book: 射鵰英雄傳>]>
查詢全部圖書,按照id從到小進行排序

 

聚合

做用: 聚合操做,對多行查詢結果中的一列進行操做,返回一個值
用法: 模型類.objects.aggregate(聚合類('屬性名'))

  • 經常使用聚合類有:Sum, Count, Max, Min, Avg等
  • 返回值是一個字典, 格式: {'屬性名__聚合函數': 值}
  • 使用時須要先導入聚合類: from django.db.models import Sum, Count, Max, Min, Avg
In [38]: from django.db.models import Avg

In [39]: Book.objects.aggregate(Avg('read_num'))
Out[39]: {'read_num__avg': 25.2}
查詢全部圖書的平均閱讀量

 

關聯查詢

1)、由 一類對象 查詢 多類對象: 一類對象.多類名小寫_set.all()

In [42]: b = Book.objects.get(title='西遊記')

In [43]: b.hero_set.all()
Out[43]: <QuerySet [<Hero: 孫悟空>, <Hero: 豬悟能>, <Hero: 沙僧>]>
查詢圖書'西遊記'的全部英雄

2)、由 多類對象 查詢 一類對象: 多類對象.關聯屬性

In [44]: h = Hero.objects.get(name='郭靖')

In [45]: h.book
Out[45]: <Book: 射鵰英雄傳>
查詢"郭靖"所屬圖書信息

 經過模型類實現上述兩個案例

  • 一類名.objects.filter(多類名小寫__多類屬性名__條件名=值)
  • 多類名.objects.filter(關聯屬性__一類屬性名__條件名=值)
In [48]: Hero.objects.filter(book__title='西遊記')
Out[48]: <QuerySet [<Hero: 孫悟空>, <Hero: 豬悟能>, <Hero: 沙僧>]>

In [49]: Book.objects.filter(hero__name='郭靖')
Out[49]: <QuerySet [<Book: 射鵰英雄傳>]>

 

查詢集 QuerySet

查詢集,也稱查詢結果集、QuerySet,表示從數據庫中獲取的對象集合,當調用一下過濾器方法時,Django會返回查詢集(而不是簡單的列表)

  • all(): 返回全部數據
  • filter(): 返回知足條件的數據
  • exclude(): 返回知足條件以外的數據
  • order_by(): 對結果進行排序

 

對查詢集能夠再次調用過濾器進行過濾

Book.objects.filter(read_num__gt=30).order_by('pub_date')

查詢集兩大特性

1)惰性執行

建立查詢集不會訪問數據庫,直到調用數據時,纔會訪問數據庫,調用數據的狀況包括迭代、序列化、與if合用

例如,當執行以下語句時,並未進行數據庫查詢,只是建立了一個查詢集qs

qs = Book.objects.all()

繼續執行遍歷迭代操做後,才真正的進行數據庫查詢

for book in qs:
    print(book.title)

2)緩存

  • 第一次查詢數據後,Django會將查詢集緩存起來,並返回請求的結果
  • 再次查詢相同數據時將重用緩存的結果
  from Book.models import Book

  [book.id for book in Book.objects.all()]
  [book.id for book in Book.objects.all()]
無緩存:查詢集有兩個
 from Book.models import Book

  list=Book.objects.all()
  [book.id for objects in list]
  [book.id for objectsin list]
有緩存:查詢集只有一個

限制查詢集

能夠對查詢集進行取下標或切片操做,等同於sql中的limit和offset子句(注意,不支持負數索引)

對查詢集進行切片後返回一個新的查詢集,不會當即執行查詢

若是獲取一個對象,直接使用[0],等同於[0:1].get(),可是若是沒有數據,[0]引起IndexError異常,[0:1].get()引起DoesNotExist異常

qs = Book.objects.all()[0:2]
獲取第一、2項

 

自定義模型管理器

能夠自定義模型管理器,好比如下兩種場景:

  •  須要重寫模型管理器中現有的方法
    • 需求:調用Book.objects.all()時,返回的是is_delete等於False的圖書
  • 封裝增刪改查的方法
    • 需求:在管理器類中,封裝一個建立圖書的方法,方便直接調用

注意:自定義後模型管理器後, Django 將再也不自動生成默認的 objects

 # 在book.models.py文件添加如下代碼, 自定義模型管理器
 class BookManager(Manager):

     def all(self):
         """重寫all方法:只返回沒有刪除的部門"""
         return super().all().filter(is_delete=False)

     def create_book(self, title, pub_date):
         """封裝新增圖書的方法,方便調用"""

         book = Book()
         book.title = title
         book.pub_date = pub_date
         book.save()
         return book



# 自定義模型管理器
 class Book(models.Model):
     """部門類"""
     ...

     # 自定義模型管理器
     objects = BookManager()
實現參考
相關文章
相關標籤/搜索