1. 程式人生 > >Django高階進階03--模型的多表連線

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('新增學生課程資訊')