創(chuàng)建一個Django工程及app
PS D:\test> django-admin startproject modelExplore
PS D:\test> cd modelExplore
PS D:\test\modelExplore> python manage.py startapp modelExample
PS D:\test\modelExplore>
添加app 到settings.py文件中的INSTALLED_APPS配置項中
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'modelExample',
]
配置數(shù)據(jù)庫
使用默認(rèn)的數(shù)據(jù)庫:sqlite3
數(shù)據(jù)庫的配置方法我在 [Django介紹與框架整合掘托,并使用MySQL實現(xiàn)增刪改查] 這篇文章中有過介紹灰粮。
模型
Django為了對各種數(shù)據(jù)庫提供支持沟蔑,因此抽象出一種模型的概念,并提供一套統(tǒng)一的調(diào)用API撞牢。這樣你就可以根據(jù)業(yè)務(wù)需求去選擇數(shù)據(jù)庫祸穷,而不需要面對因數(shù)據(jù)庫的變更而修改代碼,極大地減輕了開發(fā)人員的工作量读恃。
在學(xué)習(xí)模型前,我們先了解ORM(Object Relational Mapping:對象關(guān)系映射)的概念:
用于實現(xiàn)面向?qū)ο缶幊陶Z言里不同類型系統(tǒng)的數(shù)據(jù)之間的轉(zhuǎn)換代态。從效果上說寺惫,它其實是創(chuàng)建了一個可在編程語言里使用的“虛擬對象數(shù)據(jù)庫”。簡單理解蹦疑,就是根據(jù)對象的類型生成表結(jié)構(gòu)西雀,將對象、列表操作轉(zhuǎn)換為sql語句必尼,將sql語句查詢到的結(jié)果轉(zhuǎn)換為對象蒋搜、列表篡撵。
模型實現(xiàn)的就是一種對象關(guān)系映射判莉,那么模型豆挽、屬性、表券盅、字段他們又有哪些不為人知的秘密呢帮哈?
- 一個模型類在數(shù)據(jù)庫中對應(yīng)一張表
- 在模型類中定義的屬性對應(yīng)模型對照表中的一個字段。
Django根據(jù)屬性的類型確定以下信息锰镀。
- 當(dāng)前選擇的數(shù)據(jù)庫支持字段的類型
- 渲染管理表單時使用的默認(rèn)html控件
- 在管理站點最低限度的驗證
屬性命名限制
- 不能是Python的保留關(guān)鍵字(遵循標(biāo)識符規(guī)則)
- 由于Django的查詢方式娘侍,不允許使用連續(xù)的下劃線
定義模型
我們在modelExample這個目錄下的models.py定義模型,定義模型需要引入django.db中的models,模型類要繼承models.Model類泳炉,一個模型就是一個類憾筏。定義屬性時,需要字段類型花鹅,字段類型被定義在django.db.models.fields目錄下氧腰,為了方便使用,我們將整個django.db.models導(dǎo)入刨肃,我們以創(chuàng)建一個簡單的用戶表為例:
from django.db import models
# Create your models here.
class User(models.Model):
acocunt = models.CharField(max_length=20)
name = models.CharField(max_length=20)
passwd = models.CharField(max_length=16)
email = models.CharField(max_length=50)
sex = models.BooleanField(max_length=1, choices=((0, '男'),(1, '女'),),default=0)
說明:不需要定義主鍵古拴,在生成表時自動添加。
關(guān)系
分類:
- ForeignKey:一對多真友,將字段定義在多的端中
- ManyToOneField:多對多黄痪,將字段定義在兩端中
- OneToOneField:一對一,將字段定義在任意一端中
用一訪問多
- 格式:對象.模型類小寫_set
- 示例:grade.students_set
用一訪問一
- 格式:對象.模型類小寫
- 示例:grade.students
訪問id
- 格式:對象.屬性_id
- 示例:student.sgrade_id
屬性類型
- AutoField:一個根據(jù)實際ID自動增長的IntegerField盔然,通常不指定桅打,如果不指定一個主鍵字段將自動添加到模型中
Django會為表增加自動增長的主鍵列,每個模型只能有一個主鍵列愈案,如果使用選項設(shè)置某屬性為主鍵列后挺尾,則Django不會再生成默認(rèn)的主鍵列。
- CharField(max_length=字符長度):字符創(chuàng)刻帚,默認(rèn)的表單樣式是TextInput
- TextField:大文本字段潦嘶,一般超過4000使用,默認(rèn)的表單控件是Textarea
- IntegerField:整數(shù)
- DecimalField(max_digits=None, decimal_places=None):
使用Python的Decimal實例表示的十進(jìn)制的浮點數(shù) 參數(shù)說明: DecimalField.max_digits:位數(shù)總數(shù) DecimalField.decimal_places:小數(shù)點后的數(shù)字位數(shù)
- FloatField:用Python的float實例來表示的浮點數(shù)
- BooleanField:True/False字段崇众,此字段的默認(rèn)表單控制是CheckboxInput
- NullBooleanField:支持null.true,false三種字段
- DateField([auto_now=False,auto_now_add=False]):
使用Python的datetime.date實例表示的日期 參數(shù)說明: DateField.auto_now:每次保存對象時掂僵,自動設(shè)置該字段為當(dāng)前時間,用于“最后一次修改“的時間戳顷歌,他總是使用當(dāng)前日期锰蓬,默認(rèn)為False DateField.auto_now_add:當(dāng)前對象第一次被創(chuàng)建時設(shè)置當(dāng)前時間,用于創(chuàng)建的時間戳眯漩,他總是使用當(dāng)前日期芹扭,默認(rèn)為False 說明: 該字段默認(rèn)對應(yīng)的表單控件是一個TextInput麻顶。在管理員站點添加了一個JavaScript寫的日歷控件,和一個Today的快捷按鈕舱卡,包含了一個額外的invalid_date錯誤信息鍵 注意: Auto_now_add,auto_now and default 這些設(shè)置是相互排斥的辅肾,他們之間的任何組合將會發(fā)生錯誤的結(jié)果。
TimeField:使用Python的datetime.time實例表示的時間轮锥,參數(shù)同DateField
DateTimeField:使用Python的datetime矫钓,datetime實例表示的日期和時間,參數(shù)同DateField
FileField:一個上傳文件的字段
ImageField:繼承了FileField的所有屬性和方法舍杜,但對上傳的對象進(jìn)行校驗新娜,確保他是個有效的image
外鍵ForeignKey
from django.db import models
class Grades(models.Model):
class_name = models.CharField(max_length=20)
headteacher = models.CharField(max_length=20)
students_count = models.IntegerField(2)
class student(models.Model):
student_num = models.CharField(max_length=20)
student_name = models.CharField(max_length=20)
student_sex = models.BooleanField(max_length=1, choices=((0, '男'),(1, '女'),),default=0)
student_birth = models.DateField(auto_now_add=true)
student_grade = models.ForeignKey('Grades')
屬性選項
- 通過屬性選項,可以實現(xiàn)對屬性的約束
- 在屬性對象通過關(guān)鍵字參數(shù)指定
Null:如果為True既绩,Django將控制以null存儲到數(shù)據(jù)庫中概龄,默認(rèn)值是False
-
Blank:如果為True,則該字段允許為空白饲握,默認(rèn)值是False
注意:null是數(shù)據(jù)庫范疇的概念私杜,blank是表單驗證范疇的
Db_column:字段的名稱,如果未指定互拾,則使用屬性的名稱
Db_index:若值為True歪今,則在表中會為此字段創(chuàng)建索引
Default:默認(rèn)值
Primary_key:若為True,則該字段會成為模型的主鍵字段
Unique:如果為True颜矿,這個字段在表中必須有唯一值
元選項:在模型類定義中定義Meta類寄猩,用于設(shè)置元信息
Class Stucent(models.Model):
# someField
Class Meta:
db_table = 'stucents' # 定義數(shù)據(jù)表名,推薦使用小寫字母骑疆,如果不寫田篇,數(shù)據(jù)表名默認(rèn)為項目名小寫_類名小寫
ordering=['id'] # 對象的默認(rèn)排序字段,獲取對象的列表時使用箍铭。
# ordering = ['id']:升序泊柬;ordering = ['-id']:降序
# 注意:排序會增加數(shù)據(jù)庫的開銷。
生成遷移文件并執(zhí)行遷移
在以往的開發(fā)模式中诈火,我們通常都是設(shè)計好數(shù)據(jù)庫表后兽赁,將其創(chuàng)建出來,然后通過sql來進(jìn)行查詢冷守,而在Django中刀崖,我們可以省去數(shù)據(jù)庫表的設(shè)計和創(chuàng)建步驟,我們定義模型其實就是對表的設(shè)計拍摇,執(zhí)行遷移就是創(chuàng)建數(shù)據(jù)庫表亮钦。修改模型后只需要再遷移即可
第一步:生成遷移文件
在我們的工程目錄下執(zhí)行以下命令:python manage.py makemigrations
PS D:\modelExplore> python manage.py makemigrations
Database version : 5.5.53
Migrations for 'firstApp': firstApp\migrations\0001_initial.py
- Create model User
PS D:\modelExplore>
如果控制臺會打印出類似以上的內(nèi)容,此時會在modelExample app目錄下的migrations目錄下生成一個遷移文件充活,但是現(xiàn)在還沒有在數(shù)據(jù)庫中創(chuàng)建表蜂莉。
第二步:執(zhí)行遷移
在執(zhí)行完上一步后蜡娶,只是生成了一個遷移文件,此時還沒有在數(shù)據(jù)庫中創(chuàng)建表映穗,我們需要執(zhí)行以下命令來生成數(shù)據(jù)表:python manage.py migrate
PS D:\modelExplore> python manage.py migrate
Database version : 5.5.53
Operations to perform: Apply all migrations: admin, auth, contenttypes, firstApp, sessions Running migrations:
Applying firstApp.0001_initial... OK
PS D:\modelExplore>
執(zhí)行以上的命令相當(dāng)于執(zhí)行SQL語句創(chuàng)建了數(shù)據(jù)表窖张。看到類似于上文的結(jié)果表示成功男公,可以去數(shù)據(jù)庫中查看是否已經(jīng)創(chuàng)建了這張表荤堪。表名是你的appName_modelName連接在一起的合陵,當(dāng)然了枢赔,表名也是可以自定義的(在元選項中有過說明)。
模型成員
類屬性: objects,他是Manager類型的一個對象拥知,作用是與數(shù)據(jù)庫進(jìn)行交互踏拜。當(dāng)定義模型類時,沒有指定管理器則Django默認(rèn)為模型創(chuàng)建一個名為objects的管理器低剔。
自定義模型管理器:
class student(models.Model):
stuObj = models.Manager() # 自定義模型管理器,此時再去使用objects就會報錯了
student_num = models.CharField(max_length=20)
student_name = models.CharField(max_length=20)
student_sex = models.BooleanField(max_length=1, choices=((0, '男'),(1, '女'),),default=0)
student_birth = models.DateField(auto_now_add=true)
student_grade = models.ForeignKey('Grades')
當(dāng)模型指定模型管理器速梗。Django就不在為模型類生成objects模型管理器了。模型管理器可以創(chuàng)建多個襟齿。
自定義管理器Manager類: 模型管理器是Django的模型進(jìn)行與數(shù)據(jù)庫進(jìn)行交互的接口姻锁,一個模型類可以有多個模型管理器
作用:
- 向管理器中添加額外的方法
- 修改管理器返回的原始查詢集----重寫get_queryset()方法。
實例:
Class StudentsManager(models.Manager):
get_queryset(self):
return super(StudentsManager,self).getqueryset().filter(isDelete=False)
class student(models.Model):
# 為對象創(chuàng)建一個模型管理器
stuObj = objects_new = StudnetsManager()
student_num = models.CharField(max_length=20)
student_name = models.CharField(max_length=20)
student_sex = models.BooleanField(max_length=1, choices=((0, '男'),(1, '女'),),default=0)
student_birth = models.DateField(auto_now_add=true)
student_grade = models.ForeignKey('Grades')
創(chuàng)建對象:
目的:向數(shù)據(jù)庫中添加數(shù)據(jù) 當(dāng)創(chuàng)建對象時猜欺,Django不會對數(shù)據(jù)庫進(jìn)行讀寫操作位隶,當(dāng)調(diào)用save()方法時才與數(shù)據(jù)庫交互,將對象保存到數(shù)據(jù)庫开皿。
注意:__init__方法已經(jīng)在基類(父類)中使用涧黄,在自定義的模型中無法使用
方法:
- 在模型類中增加一個類方法
- 在自定義管理器中添加一個方法
此處亂七八糟的呢
@classmethod
def createStudents(cls,name,age , gender, contend…):
student = cls(sname = name , sage = age…)
return student
stu.createStudents(…)
# 在自定義管理器中添加一個方法 在StudentsManager中創(chuàng)建一個方法
def createStudents(self,name,age , gender, contend…):
# 可以直接創(chuàng)建一個對象,但是這種方式不通用赋荆,限制了這個管理器笋妥。
stu = Students()
# 在通常情況下,我們使用以下的方法創(chuàng)建窄潭,這樣什么對象調(diào)用就是什么對象
stu2 = self.model()
stu2.sname = name … Print(type(stu2))
student = cls(sname = name , sage = age…)
return student stu.obj.createStudents
# 定義一個類方法創(chuàng)建對象,此方法要創(chuàng)建在Students類中
模型查詢
查詢集:
查詢集是表示從數(shù)據(jù)庫中獲取的對象的集合春宣,查詢集可以有多個過濾器,過濾器就是一個函數(shù)嫉你,基于所給的參數(shù)限制查詢集結(jié)果月帝。從sql角度來說,查詢集合select語句等價均抽,過濾器就像where條件嫁赏。
1在管理器上調(diào)用過濾器方法返回結(jié)果集
2查詢集經(jīng)過過濾器篩選后返回新的查詢集,所以我們可以寫成鏈?zhǔn)秸{(diào)用
3惰性執(zhí)行:創(chuàng)建查詢集不會帶來任何數(shù)據(jù)庫的訪問油挥,直到調(diào)數(shù)據(jù)時潦蝇,才會訪問數(shù)據(jù)庫
4直接訪問數(shù)據(jù)的情況:
迭代:
序列化:
與if合用:
5返回查詢集的方法稱為過濾器
all():返回查詢集中的所有數(shù)據(jù)
filter():返回符合條件的數(shù)據(jù) :
filter(鍵=值);
filter(鍵=值款熬,鍵=值);
filter(鍵=值).filter(鍵=值)
-
多條件是and查詢
exclude():過濾掉符合條件的數(shù)據(jù)
order_by():排序
values():一條數(shù)據(jù)就是一個對象(字典)攘乒,返回一個列表
6返回單個數(shù)據(jù)
get():返回一個滿足條件的對象
注意:如果沒有找到符合條件的對象贤牛,會引發(fā)‘模型類DoesNotExist’異常
如果找到了多個對象,也會引發(fā)‘模型類MultipleObjectsReturned’異常
count():返回當(dāng)前查詢集中的對象個數(shù)
first():返回當(dāng)前查詢集中的第一個對象
last():返回當(dāng)前查詢集中的最后一個對象
exists():判斷查詢集中是否有數(shù)據(jù)则酝,如果有返回True殉簸,否則返回False
7限制查詢集:查詢集返回列表,可以使用下標(biāo)的方法進(jìn)行限制沽讹,等同于SQL中的limits
students.objects.all()[0:5]注意下標(biāo)不能是負(fù)數(shù)
實現(xiàn)分頁功能
8查詢集的緩存
概述:每個查詢集都包含一個緩存般卑,來最小化的對數(shù)據(jù)庫訪問
在新建的查詢集中,緩存首次為空爽雄,第一次對查詢集求值蝠检,會發(fā)生數(shù)據(jù)緩存。挚瘟,django會將查詢出來的數(shù)據(jù)做緩存叹谁,并返回查詢結(jié)構(gòu),以后的查詢直接使用查詢緩存的方式查詢乘盖。
9字段查詢
概述:
1實現(xiàn)了SQL中的where語句作為方法filter()焰檩、exclude()、get()的參數(shù)
2語法:屬性名稱比較運算符=值
3外鍵:屬性名id
4轉(zhuǎn)義:類似SQL中的like語句中使用%為了匹配占位订框。
例:filter(sname__contains=”%”)
比較運算符:
1exact判斷析苫,大小寫敏感,例filter(isDelete=False)
2contailns:是否包含布蔗,大小寫敏感:例:student.objects.filter(sname__contains=’于’)
3startswith/endswith:以value開頭或結(jié)尾藤违,大小寫敏感
以上四個在前面加上一個I,就表示不區(qū)分大小寫:iexact/icontains/istartswith
4isnull/isnotnull :是否為空;filter(sname__isnull=False)
5in : 是否包含纵揍。filter(pk__in=[2,4,6,8,])
6gt/gte/lt/lte : 大于/大于等于/小于/小于等于顿乒;filter(sage__gt=50)
7year/month/day/week_day/hour/minute/second : 日期 filter(last_time__year = 2018)
8跨關(guān)聯(lián)查詢:
處理join語句:
語法:模型類名屬性名_比較運算符
# 描述中帶有小白兔關(guān)鍵字的數(shù)據(jù)屬于哪個班級
Grades.objects.filter(Students__scontend__contains=’小白兔’)
9快速查詢:pk:代表的主鍵
聚合函數(shù):使用aggregate()函數(shù)返回聚合函數(shù)的值
1Avg:
2Count
3Max/Min/Sum
from django.db.model import Max
Students.objects.aggregate(Max(‘sage’))
F對象:可以使用模型的A屬性與B屬性進(jìn)行比較
from django.db.model import F
Grades.objects.filter(ggirlnum__gt=F(‘gboynum’) + 20)
支持F對象算數(shù)運算和時間運算
Q對象
概述:過濾器的方法中的關(guān)鍵字參數(shù),條件為and方式
需求:進(jìn)行or查詢
解決:使用Q對象
from django.db.model import Q
Students.objects.filter(Q(pk__lt=3) | Q(sage__gt=50))
# 只有一個Q的時候泽谨,與沒有Q相同
Students.objects.filter(Q(pk__lt=3))
# 在Q前加一個~璧榄,表示取反
Students.objects.filter(~Q(pk__lt=3))