django 及 rest_framework 筆記鏈接如下:
django 入門筆記:環(huán)境及項(xiàng)目搭建
django 入門筆記:數(shù)據(jù)模型
django 入門筆記:視圖及模版
django 入門筆記:Admin 管理系統(tǒng)及表單
django 入門筆記:通用視圖類重構(gòu)視圖
django_rest_framework 入門筆記:Serializer
django_rest_framework 入門筆記:視圖函數(shù)重構(gòu)
django_rest_framework 入門筆記:分頁(yè)轩触,多條件篩選及權(quán)限認(rèn)證設(shè)置
django 自帶 user 字段擴(kuò)展及頭像上傳
上一部分我們介紹了環(huán)境和項(xiàng)目的搭建,以及數(shù)據(jù)庫(kù)的配置脱柱,那這一部分我們介紹和數(shù)據(jù)庫(kù)相關(guān)方面的知識(shí) -- 模型
創(chuàng)建 django 模型
我們需要在 "blog" 應(yīng)用下的 models.py 文件中添加 django 數(shù)據(jù)庫(kù)模型伐弹,模型類需要繼承 models.Model 類,例如
from django.db import models
class Category(models.Model):
# 可以通過(guò)第一個(gè)參數(shù)傳入字符串設(shè)置別名
name = models.CharField("分類", max_length=100)
# 查找 Category 時(shí)榨为,返回為一個(gè) object 如果不重寫 __str__ 方法返回?cái)?shù)據(jù)直接顯示 Category Object掸茅,
# 重寫該方法后,查找返回結(jié)果為該方法返回的值
def __str__(self):
return '<Category>[{}]'.format(self.name)
# 通過(guò) Meta 來(lái)修改數(shù)據(jù)表的信息
class Meta:
db_table = "category" # 修改數(shù)據(jù)庫(kù)表名柠逞,默認(rèn)表名會(huì)是 項(xiàng)目名_模型名 blog_category
ordering = ['-id'] # 修改排序方式,"-" 表示逆序
Model 的常用字段類型還是比較多的景馁,下面將介紹常用的字段類型和關(guān)系類型板壮,以及字段類型的限制參數(shù)。
Model 的常用字段類型
- models.AutoField 自增列 如果沒(méi)有的話合住,默認(rèn)會(huì)生成一個(gè)名稱為 id 的列绰精,如果要顯示的自定義一個(gè)自增列,必須將給列設(shè)置為主鍵 primary_key=True
- models.CharField 字符串 指定 max_length 參數(shù)設(shè)置最大長(zhǎng)度
- models.BooleanField 布爾類型
- models.DateField 日期類型 對(duì)于參數(shù)透葛,auto_now = True 則每次更新都會(huì)更新這個(gè)時(shí)間笨使,auto_now_add 則只是第一次創(chuàng)建添加,之后的更新不再改變
- models.DateTimeField 日期類型 同 models.DateField
- models.EmailField 字符串類型(正則表達(dá)式郵箱)
- models.FloatField 浮點(diǎn)類型
- models.IntegerField 整型
- models.BigIntegerField 長(zhǎng)整型
- models.IPAddressField 字符串類型(ip4正則表達(dá)式)
- models.GenericIPAddressField 字符串類型(ip4和ip6是可選的) 參數(shù)protocol可以是:both僚害、ipv4硫椰、ipv6
- models.TextField 字符串類型 同 CharField, 可以設(shè)置更長(zhǎng)的字符串
- models.TimeField 時(shí)間 HH:MM[:ss[.uuuuuu]]
- models.URLField 字符串萨蚕,地址正則表達(dá)式
- models.ImageField 圖片類型
- models.FilePathField 文件類型
Model 的連表結(jié)構(gòu)
一對(duì)多:models.ForeignKey(其他表) 例如 ModelA 中有個(gè)字段指向 ModelB
# 最好加上 on_delete 屬性, 否則可能會(huì)報(bào)錯(cuò) b = models.ForeignKey(ModelB靶草,on_delete=models.CASCAED)
ModelA 為”多“,ModelB 為”一“
多對(duì)多:models.ManyToManyField(其他表) 例如 ModelA 中有個(gè)字段指向 ModelB
bs = models.ManyToManyField(ModelB)
ModelA 可以對(duì)應(yīng)多個(gè) ModelB 的值岳遥,同樣 ModelB 可以對(duì)應(yīng)多個(gè) ModelA 的值
一對(duì)一:models.OneToOneField(其他表) 例如 ModelA 中有字段指向 ModelB
b = models.OneToOneField(ModelB)
ModelA 只能對(duì)應(yīng) ModelB 中特定的值奕翔,同樣 ModelB 也只能對(duì)應(yīng) ModelA 中特定的值
Model 的常用設(shè)置參數(shù)
- null=(True/False) 數(shù)據(jù)庫(kù)中字段是否可以為空
- blank=(True/False) django的 Admin 中添加數(shù)據(jù)時(shí)是否可允許空值
- primary_key=(True/False) 主鍵,對(duì) AutoField 設(shè)置主鍵后浩蓉,就會(huì)代替原來(lái)的自增 id 列
- auto_now=(True/False) 自動(dòng)創(chuàng)建---無(wú)論添加或修改派继,都是當(dāng)前操作的時(shí)間,在 MySql 下存在過(guò)濾月份時(shí)候數(shù)據(jù)為空捻艳,解決方案參考 MySql 文檔 Section 10.6
- auto_now_add=(True/False) 自動(dòng)創(chuàng)建---永遠(yuǎn)是創(chuàng)建時(shí)的時(shí)間
- choices=(xx,xx,xx) 可選擇列表項(xiàng)驾窟,通常是一個(gè)列表或者元組
- max_length=(int) 最大長(zhǎng)度,多和字符串類型配合使用
- verbose_name='xxxx' Admin 中字段的顯示名稱
- name|db_column 數(shù)據(jù)庫(kù)中的字段名稱
- unique=(True/False) 是否可以重復(fù)
- db_index=(True/False) 是否設(shè)置為索引
- editable=(True/False) 在Admin里是否可編輯
- error_messages='xxxx' 錯(cuò)誤提示
- auto_created=(True/False) 是否自動(dòng)創(chuàng)建
- help_text='xxxx' 在 Admin 中提示幫助信息
- upload-to='xxxx' 上傳到哪個(gè)位置认轨,與 ImageField,FfileField 配合使用
創(chuàng)建完模型后纫普,我們需要根據(jù)模型來(lái)創(chuàng)建數(shù)據(jù)庫(kù),設(shè)計(jì)到數(shù)據(jù)庫(kù)遷移的知識(shí)
數(shù)據(jù)庫(kù)的遷移
我們通過(guò)命令行切換到 manage.py 文件夾,分別運(yùn)行如下命令行
-
python manage.py makemigrations
運(yùn)行后會(huì)在相應(yīng)應(yīng)用下的 migrations 目錄生成一個(gè) 0001_initial.py(0001會(huì)根據(jù)遷移的次數(shù)進(jìn)行遞增)昨稼,用于記錄對(duì)模型的修改 -
python manage.py migrate
運(yùn)行后將 model 中的操作轉(zhuǎn)換成為數(shù)據(jù)庫(kù)語(yǔ)言节视,作用于數(shù)據(jù)庫(kù),對(duì)數(shù)據(jù)庫(kù)進(jìn)行相應(yīng)的修改
如果對(duì)命令行做了什么動(dòng)作假栓,我們可以通過(guò)運(yùn)行如下命令行查看具體的數(shù)據(jù)庫(kù)操作python manage.py sqlmigrate blog 0001
其中 blog 0001 根據(jù)實(shí)際項(xiàng)目進(jìn)行替換
數(shù)據(jù)庫(kù)插入數(shù)據(jù)
創(chuàng)建好數(shù)據(jù)庫(kù)進(jìn)行數(shù)據(jù)添加寻行,可以通過(guò)如下操作進(jìn)行
from blog.models import Category, Tag
c = Category('test category')
c.save()
t = Tag('test tag')
t.save()
打開數(shù)據(jù)庫(kù)可以看到插入的數(shù)據(jù)
數(shù)據(jù)庫(kù)查找數(shù)據(jù)
插入數(shù)據(jù)后,查找數(shù)據(jù)庫(kù)內(nèi)的數(shù)據(jù)可以通過(guò)如下操作進(jìn)行
# 查找某個(gè)表所有的數(shù)據(jù)匾荆,返回<QuerySet[...]>
from blog.models import Category
c_list = Category.objects.all()
# 查找某個(gè)特定的數(shù)據(jù)拌蜘,如果數(shù)據(jù)不存在會(huì)拋出錯(cuò)誤 blog.models.DoesNotExist澜搅,
# 存在則返回 Object垫蛆,如果重寫了 __str__ 方法什燕,則返回該方法所指定的值
c_test = Category.objects.get(name='test category')
# 也可以通過(guò) filter 關(guān)鍵詞進(jìn)行查找
c_test = Category.objects.filter(name='test category, id__lt=10)
c_test = Category.objects.filter(id__range=[0, 10])
# 還可以使用 startswith皮胡,istartswith, endswith, iendswith 等條件
# .values() 和 .values_list() 區(qū)別
# .values() 取出某一列咬荷,每個(gè)元素是一個(gè)字典胁编,.values_list() 取出的元素是一個(gè)個(gè)元組
# 如下語(yǔ)句得到的結(jié)果為 <QuerySet [{'name': 'test category', 'id': 1}]>
print(Category.objects.filter(name='test category').values('name', 'id'))
# 如下語(yǔ)句得到的結(jié)果為 <QuerySet [('test category', 1)]>
print(Category.objects.filter(name='test category').values_list('name', 'id'))
# exclude 查詢條件外的數(shù)據(jù)
Category.objects.exclude(id__gt=2) 即查找 id 不大于 2 的數(shù)據(jù)
# 通過(guò) order_by 進(jìn)行排序
Category.objects.all().order_by('-id') # 逆序排序馒稍,逆序排序只需要在排序字段前加"-"號(hào)即可
# 刪選某個(gè)范圍內(nèi)的數(shù)據(jù) 類似于 SQL 語(yǔ)句中的 OFFSET 10 LIMIT 10
Category.objects.all()[10: 20] # 獲取列表中 10-20 的數(shù)據(jù)
# aggregate 操作符(出了求和 Count 還有 Avg, Max, Min 等礁哄,通過(guò) django.db.models 導(dǎo)入)
print(Category.objects.aggregate(Count('name'))) # {'name__count': 5}
# 也可以指定結(jié)合后的字段名
print(Category.objects.aggregate(category_count=Count('name))) # {'category_count': 5}
# annotate 操作符
# 假設(shè) Post 表中有個(gè)字段指向 Category
# category = models.ForeignKey(Category) 在表 Category 中需要統(tǒng)計(jì)某個(gè) category 下 post 數(shù)量构罗,
# 但是表 Category 中沒(méi)有 post_count 字段铜涉,那么可以通過(guò) annotate 操作符來(lái)進(jìn)行統(tǒng)計(jì)
c_list = Category.objects.annotate(post_count=Count('post'))
print(c_list[0].post_count) # 12
# "__" 的操作
# 大于,小于操作
Categroy.objects.fileter(id__gt=1, id__lt=10) # 查找 id 介于 1 和 10 之間的數(shù)據(jù)
# in
Category.objects.filter(id__in=[11, 22, 33]) # 查找 id 為 11遂唧,22芙代,33 的值
Category.objects.exclude(id__in=[11, 22, 33]) # not in
# contains
Category.objects.filter(name__contains="test") 查找 name 字段包含 test 的值
Category.objects.filter(name__icontains="test") # 大小寫不敏感
# range
Caregory.objects.filter(id__range=[1, 10]) # 查找 id 介于 1 和 10 之間的數(shù)據(jù),即 between and
# 類似的包括 startwith, istartwith, endwith, iendwith 等
數(shù)據(jù)庫(kù)修改數(shù)據(jù)
對(duì)存在的數(shù)據(jù)進(jìn)行修改盖彭,可通過(guò)如下操作進(jìn)行
c = Category.objects.get(name='test category')
c.name = 'new test category'
c.save()
刪除數(shù)據(jù)庫(kù)數(shù)據(jù)
對(duì)存在數(shù)據(jù)庫(kù)中的數(shù)據(jù)進(jìn)行刪除纹烹,可以通過(guò)如下操作進(jìn)行
# 刪除某條特定的數(shù)據(jù)
c = Category.objects.get(name='new test category')
c.delete()
# 刪除全部的數(shù)據(jù)
c_list = Category.objects.get()
for c in c_list:
c.delete()
更多的數(shù)據(jù)庫(kù)操作 API 查看官方的 API django 數(shù)據(jù)庫(kù)操作 API
使用原生 SQL 語(yǔ)句操作數(shù)據(jù)庫(kù)
django 支持使用原生語(yǔ)句操作數(shù)據(jù)庫(kù)
from django.db import connection
cursor = connection.cursor()
# 原生 SQL 語(yǔ)句放在 execute 中使用
cursor.execute("SELECT c.id, c.name FROM blog_category as c")
# 獲取查詢到的第一個(gè)數(shù)據(jù)
row = cursor.fetchone()
# 獲取全部查詢到的數(shù)據(jù)
rows = cursor.fetchall()
最后附上整個(gè)項(xiàng)目的地址:blog_project