Django高階進階03--模型的多表連線
Django框架學習03—
一.知識回顧
1.模型
(1)欄位型別
·AutoField·一個根據實際ID自動增長的IntegerField,通常不指定。如果不指定,一個主鍵欄位將自動新增到模型中
·CharField(max_length=字元長度)·字串,預設的表單樣式是 TextInput
·TextField 大文字欄位,一般超過4000使用,預設的表單控制元件是Textarea
·IntegerField 整數
DateField([auto_now=False, auto_now_add=False])
·使用Python的datetime.date例項表示的日期
DateField.auto_now每次儲存物件時,自動設定該欄位為當前時間,用於"最後一次修改" 的時間戳,它 總是使用當前日期,預設為false
·DateField.auto_now_add當物件第一次被建立時自動設定當前時間,它總是使用當前日期,預設為 false,設定為true則不改變
BooleanField true/false 欄位,此欄位的預設表單控制是CheckboxInput
(2)引數
null ·如果為True,則該欄位在資料庫中是空資料,預設值是 False
·blank ·如果為True,則該欄位允許為空白,預設值是 False
【注意】null是資料庫範疇的概念,blank是表單驗證證範疇的
default ·預設值
primary_key ·若為 True, 則該欄位會成為模型的主鍵欄位
unique ·如果為 True, 這個欄位在表中必須有唯一值
【例】
2.ORM概念(物件關係對映)
通過模型去操作資料庫。通過模型的object物件,操作資料庫中對應的表,相當於是封裝的操作資料庫的方法。所有使用Django開發的專案無需關心程式底層使用的是MySQL、Oracle、sqlite….,如果資料庫遷移,只需要更換Django的資料庫引擎即可。
3.通過檢視實現資料庫Crud操作
多種方法操作的只選擇一種就可以,防止衝突
現在urls.py中設定好url,實現的功能
urlpatterns = [
url(r'^admin/', admin.site.urls),
url('create_stu/', views.create_stu),
url('select_stu/', views.select_stu),
url('delete_stu/', views.delete_stu),
url('update_stu/', views.update_stu),
]
(1)建立(增加資料)三種方式
def create_stu(request):
# create方法:建立學生的資訊,操作資料庫(三種建立方式)
#引入ORM概念:物件關係對映
#方式一:
Student.objects.create(s_name='小李')
Student.objects.create(s_name='小草')
Student.objects.create(s_name='晁蓋')
Student.objects.create(s_name='宋江')
Student.objects.create(s_name='武松')
Student.objects.create(s_name='盧俊義')
Student.objects.create(s_name='林沖')
Student.objects.create(s_name='吳用')
# 方式二:建立s_name屬性
# stu = Student
# stu.s_name ='小明'
# stu.save()
#方式三:最好不用,問題較多
# stu =Student('小草', 18, 1)
# stu.save()
return HttpResponse('建立學生方法')
(2)刪除
#刪除操作
def delete_stu():
# 寫法一:分步寫
# stu = Student.objects.get(pk=5)
# stu = Student.objects.filter(pk=3).first()
# stu.delete()
# 寫法二:連寫
Student.objects.filter(id=2).first().delete()
return HttpResponse('刪除')
(3)更新資料(改)
def update_stu(request):
# 更新
# 第一種
stu = Student.objects.get(pk=1)
stu.s_name = '帥哥'
stu.save()
# 第二種:寫法
# Student.objects.filter(id=1).update(s_name='哈哈')
return HttpResponse('修改')
(4)查詢
查詢所有===模型名.objects.all()
查詢滿足條件:filter(條件1,條件2,條件3)
filter(條件1).filter(條件2).fileter(條件3
查詢不滿足條件:exclude(條件1)
獲取單條資訊:、
a)返回結果不同:
filter(id=1)或filter(pk=1)
queryset 物件
b)獲取不到結果:
filter(id=100) ==>超出範圍結果為空
get(id=100) ====超出範圍結果會報錯,或者有多個結果
排序
升序:模型名.objects.all().order_by('id')
降序:模型名.objects.all().orde_by('-id')
模糊查詢
icontains:大小寫不敏感(ignore忽略大小寫)
contains:大小寫敏感
模型名.objects.filter(s_name_ _icontains='小')
startswith:以什麼開始
endswith:以什麼結束
運算子
gt gte:大於,大於等於
lt lte:小於,小於等於
切片
通過切片獲取,直接寫下標[n]若不存在會報錯,可以寫成[n:]或[:n]
in:在範圍之內
解析結果 模型名.objects.all.values() 執行效率比單純.all效率高
Q函式
# Q(),且、或、非操作
# 查詢姓名叫小花的,或者年齡為18
# stus=Student.objects.filter(Q(s_name='小李') | Q(s_age=20))
# stus = Student.objects.filter(Q(s_name='小李') & Q(s_age=20))
# 查詢姓名不叫小花的,或者年齡為18
# stus = Student.objects.filter(~Q(s_name='小李') | Q(s_age=20))
二、模型查詢補充
用之前都需要從django中匯入
1.過濾器
查詢集表示從資料庫獲取的物件集合,查詢集可以有多個過濾器,過濾器就是一個函式,基於所給的引數限制查詢的結果。上一節中已經演示過過濾用filter,
從SQL角度來說,查詢集合和select語句等價,過濾器就像where條件
Django有兩種過濾器用於篩選記錄
filter : 返回符合篩選條件的資料集
exclude : 返回不符合篩選條件的資料集
除此以外還有以下幾個
all() 返回所有資料
filter() 返回符合條件的資料
exclude() 過濾掉符合條件的資料
order_by() 排序
values() 一條資料就是一個字典,返回一個列表
2.Q物件
Q()物件就是為了將過濾條件組合起來,當我們在查詢的條件中需要組合條件時(例如兩個條件“且”或者“或”)時。我們可以使用Q()查詢物件,使用符號&或者|將多個Q()物件組合起來傳遞給filter(),exclude(),get()等函式
Q()物件的前面使用字元“~”來代表意義“非”
例子1:
查詢學生中不是12歲的或者姓名叫張三的學生
student = Student.objects.filter(~Q(age=12) | Q(name='張三'))
例子2:
查詢python班語文小於80並且數學小於等於80的學生
grade = Grade.objects.filter(g_name='python').first()
students = grade.student_set.all()
stu = students.filter(~Q(s_yuwen__gte=80) & Q(s_shuxue__lte=80))
例子3:
查詢python班語文大於等於80或者數學小於等於80的學生
grade = Grade.objects.filter(g_name='python').first()
students = grade.student_set.all()
stu = students.filter(Q(s_yuwen__gte=80) | Q(s_shuxue__lte=80))
3.F物件
F物件:可以使用模型的A屬性與B屬性進行比較(不要忘記雙下劃線的操作)
背景:在模型中有兩個欄位,分別表示學生成績A與成績B,要對成績AB進行比較計算,就需要使用到F物件。
例如有如下例子1:
班級中有女生個數字段以及男生個數字段,統計女生數大於男生數的班級可以如下操作:
grades = Grade.objects.filter(girlnum__gt=F('boynum'))
F物件支援算數運算
grades = Grade.objects.filter(girlnum__gt=F(‘boynum’) + 10)
例子2:
查詢python班下語文成績超過數學成績10分的學生
grade = Grade.objects.filter(g_name='python').first()
students = grade.student_set.all()
stu = students.filter(s_yuwen__gt= F('s_shuxue') + 10)
4.聚合函式
都要引入
gregate()函式返回聚合函式的值
Avg:平均值
Count:數量
Max:最大
Min:最小
Sum:求和
例如: Student.objects.aggregate(Max('age'))
三、模型關聯關係:一對一
一個表中的欄位不要太多,儘量使用關聯關係。常見的幾種資料關係,django都提供了很好的支援 模型關係主要介紹模型的對應關係,一對一,一對多,以及多對多的關係。並且舉例說明 模型對應關係描述如下:
一對一 OneToOneField
1:N 一對多 ForeignKey
M:N 多對多 ManyToManyField。
1.學生模型新增成績欄位(DecimalField的使用 )
類DecimalField
(max_digits =無,decimal_places =無),固定精度的十進位制數,在Python中表示一個 十進位制的
例項。有兩個必需的引數
# 代表最大四位數字,小數部分是2位
math = models.DecimalField(max_digits=4, decimal_places=2, null=True) # 最大為99.99
chinese = models.DecimalField(max_digits=4, decimal_places=2, null=True)
2.定義一個學生資訊模型
定義了學生模型只有年齡姓名等基本資訊,不包含電話號碼和地址欄位,所以建立一個學生資訊模型,新增電話號碼和地址欄位
class StudentInfo(models.Model):
phone = models.CharField(max_length=11, null=True, unique=True, verbose_name='電話號碼')
address = models.CharField(max_length=31,null=True, verbose_name='地址')
class Meta:
db_table = 'student_info'
注意:(1)定義這個模型要放到之前的學生模型(類)上方,否則接下來建立關係會報錯
(2)防止關聯的表一起被刪除==on_delete引數
設定on_delete引數為空
stu = models.OneToOneField(Student,on_delete='')
3.二者做關聯(一對一)
因為是一對一,二者中任意一個都可以寫,這裡在學生表中寫
stu_info = models.OneToOneField(StudentInfo,null=True,related_name='stu')
4.設定好URL
建立好關聯要實現以下功能
url('create_stu_info/', views.create_stu_info),
url('stu_add_stuinfo/', views.stu_add_stuinfo),
url('sel_phone_by_stu/', views.sel_phone_by_stu),
url('sel_stu_by_phone/', views.sel_stu_by_phone),
5.在檢視中定義方法
def stu_add_stuinfo(request):
if request.method == 'GET':
# 給id為1的學生新增拓展表中id=2的資訊,
stu = Student.objects.get(id=1)
# 繫結關係1:
# stu.stu_info_id = 2
# 繫結關係2:
stu.stu_info = StudentInfo.objects.get(id=2)
stu.save()
return HttpResponse('繫結學生和拓展表的關聯關係')
def sel_phone_by_stu(request):
if request.method == 'GET':
# 獲取id=2的學生的手機號
# 方法1:
stu = Student.objects.filter(id=2).first()
info_id = stu.stu_info_id
stu_info = StudentInfo.objects.get(pk=info_id)
phone = stu_info.phone
# 方法2:
stu = Student.objects.get(id=2)
stu_info = stu.stu_info
phone = stu_info.phone
return HttpResponse('通過學生查詢手機號')
def sel_stu_by_phone(request):
if request.method == 'GET':
stu_info = StudentInfo.objects.get(phone='13551677977')
# stu_info.student和stu_info.stu只能用一個
stu = stu_info.student
s_name = stu.s_name
return HttpResponse('通過手機號查詢學生')
四、python斷點除錯(debug使用)
1.使用方式
用debug模式執行到紅點位置會終止程式執行,防止後面的程式不確定是否有錯誤時候報錯
2.要求
不要開多個debug
不要和run一起執行
很多時候會出現打斷點埠被佔用,可以改一個埠訪問
五、模型關聯關係:一對多
學生和班級的關係就是一對多關係,注意:使用models.ForeignKey關聯 獲取物件元素 grade.student_set
g = models.ForeignKey(unique=True) #設定唯一時,一對多變成一對一
1.建立一個班級模型(寫到學生表上方)
class Grade(models.Model):
g_name = models.CharField(max_length=10, unique=True, verbose_name='班級名稱')
class Meta:
db_table = 'grade'
2.和學生模型建立一對多(foreignkey)
注意:設定外來鍵,在nivicat中將外來鍵刪除時設定為not null,可以讓資料刪除時聯合刪除
g = models.ForeignKey(Grade, null=True, related_name='stu')
3.設定Url
url('create_grade/', views.create_grade),
url('sel_stu_by_grade/', views.sel_stu_by_grade),
url('create_course/', views.create_course),
url('create_stu_course/', views.create_stu_course),
4.檢視中定義方法,實現上述功能
ef create_grade(request):
if request.method == 'GET':
# 建立班級
grade_name = ['Python', 'Java', 'Php', 'VHDL']
for name in grade_name:
Grade.objects.create(g_name=name)
return HttpResponse('建立班級成功')
def sel_stu_by_grade(request):
if request.method == 'GET':
# 查詢叫小花5的學生對於的班級名稱
stu = Student.objects.filter(s_name='小花5').first()
grade = stu.g
# 查詢java班級下有多少學生,獲取學生的姓名
grade = Grade.objects.filter(g_name='Java').first()
# stus = grade.student_set.all()
stus = grade.stu.all()
pass
5.遷移
五、模型關聯關係:多對多
對多關係:
1. 生成表的時候會多生成一張表(實際會有三張表)
2. 生成的表是專門用來維護關係的
3. 生成的表是使用兩個外來鍵來維護多對多的關係
4. 兩個一對多的關係來實現多對多的實現
5. 刪除一個表的資料的話,中間關聯表也要刪除相關的資訊
建立課程模型做遷移,除了課程表會多出一張關聯表
class Course(models.Model):
c_name = models.CharField(max_length=10, null=True)
class Meta:
db_table = 'course'
class Student(models.Model):
s_name = models.CharField(max_length=10, unique=True, verbose_name='姓名')
s_age = models.IntegerField(default=19, verbose_name='年齡')
s_sex = models.BooleanField(default=1, verbose_name='性別')
create_time = models.DateTimeField(auto_now_add=True, verbose_name='建立時間')
operate_time = models.DateTimeField(auto_now=True, verbose_name='修改時間')
math = models.DecimalField(max_digits=4, decimal_places=2, null=True) # 99.99
chinese = models.DecimalField(max_digits=4, decimal_places=2, null=True)
stu_info = models.OneToOneField(StudentInfo, null=True, related_name='stu')
g = models.ForeignKey(Grade, null=True, related_name='stu')
c = models.ManyToManyField(Course, null=True)
class Meta:
db_table = 'app_student'
2.向中間表中新增資料
def create_course(request):
if request.method == 'GET':
# 新增課程
courses = ['線代', '高數', '大學物理', '概率論']
for i in courses:
Course.objects.create(c_name=i)
return HttpResponse('新增課程成功')
def create_stu_course(request):
if request.method == 'GET':
# 新增學生對於的課程資訊
# 讓id=2的學生選擇課程(id=1,2)
stu = Student.objects.get(id=2)
# 新增add()方法
# stu.c.add(2)
# 新增概率論和id=4的學生關聯關係
# cou = Course.objects.get(c_name='概率論')
# 新增add()
# cou.student_set.add(4)
# 刪除id=2的學生選的id=2的課程
stu.c.remove(2)
return HttpResponse('新增學生課程資訊')