1. 程式人生 > >Django的學習進階(三)————ORM

Django的學習進階(三)————ORM

django框架是將資料庫資訊進行了封裝,採取了

類——>資料表

物件——>記錄

屬性——>欄位

通過這種一一對應方式完成了orm的基本對映
官方文件:https://docs.djangoproject.com/en/2.2/

一、表單
models中每一個繼承於models.Model的類就是一張資料表
如:class AddressInfo就是一張關於地址的資料表
官方文件:https://docs.djangoproject.com/en/2.2/topics/db/models/

二、欄位
文件地址:https://docs.djangoproject.com/en/2.2/ref/models/fields/

(1)欄位設計
1.自增長欄位(default=int)

# 自增長欄位
Auto = models.AutoField()  # 預設為整型
BigAuto = models.BigAutoField()  # 比Auto大

 

2.二進位制的資料

# 二進位制欄位
Binary = models.BinaryField()  # 二進位制欄位

 

3.boolean型別

# Boolean型別
Boolean = models.BooleanField()  # 不為空
NullBoolean = models.NullBooleanField()  # 為空

 

4.整型

# 整型
PositiveSmallInteger = models.PositiveSmallIntegerField()  # 能存取五個位元組的大小
SmallInteger = models.SmallIntegerField()  # 能存取六個位元組的大小  可以是正整數也可以是負整數
PositiveInteger = models.PositiveIntegerField()  # 10個位元組大小的正整數
Integer = models.IntegerField()  # 11個位元組大小的正整數
BigInteger = models.BigIntegerField()  # 20個位元組大小的整形


5.字元型

# 字串型別
Char = models.CharField()  # varchar
Text = models.TextField()  # longtext

 

6.時間型別

# 時間日期型別
Date = models.DateField()  # 年月日
DateTime = models.DateTimeField()  # 年月日時分秒
Duration = models.DurationField()  # 一段時間 int 底層用Python timedelta實現

 

7.浮點型

# 浮點型
Float = models.FloatField()  # 浮點型
Decimal = models.DecimalField()  # 需要指定整數多少位  小數多少位

 

8.其他欄位

# 其他欄位
Email = models.EmailField()  # 郵箱
Image = models.ImageField()  # 圖片
File = models.FileField()  # 檔案
FilePath = models.FilePathField()  # 檔案路徑
URL = models.URLField()  # 網址
UUID = models.UUIDField()  # 通用唯一識別碼
GenericIpAddress = models.GenericIPAddressField()  # ip地址  ipv4的地址 或者是ipv6的地址


(2)欄位引數設計
1.通用引數

# db_column="" 指定在資料庫中的引數
# primary_key=True 設定主鍵 True
# verbose_name="" 設定別名
# unique=True 設定欄位是否唯一
# null=True, blank=True, db_index=True null是表中的欄位是否為空 blank是表單提交的資料要和null保持一致 否則就會出現錯誤 同時給欄位建立索引
# help_text="" 建立幫助文件
# editable=False 使使用者不可以修改

 

2.個別引數具有的欄位

# Char型別: max_length 指定最大長度
# date型別: unique_for_date=True 設定日期必須唯一 還有月和年
# date型別: auto_now_add=True 增加記錄時的時間 插入資料的時間
# date型別: auto_now=True 更新當前記錄的時間 更新資料的時間
# Decimal型別: max_digits=4 總共多少位, decimal_places=2 小數的位數

 

3.關係型欄位

# related_name='' 外來鍵查詢的資訊
# on_delete: 當外來鍵不在的時候進行什麼操作 作為關係型欄位的必須引數(預設順序是外來鍵表to和on_delete)
# on_delete的六種模式
"""
models.CASCADE: 刪除級聯  A表記錄被刪除B表記錄也會被刪除 預設 要設定null=True blank=True
models.PROTECT: 刪除時 會報PROTECT ERROR異常
models.SET: 傳一個SET值或者回調函式值
models.SET_NULL: 刪除置空 父表記錄被刪除子表記錄設定成NULL 同時需要指定null=True blank=True
models.SET_DEFAULT: 當父表字段被刪除的時候我們給子表字段設定一個預設值 用default引數指定值
models.DO_NOTHING: 當父表被刪除子表什麼也不做
"""

 
(3)關聯關係
關聯關係分為三種:一對一,一對多,多對多
1.基類

class Teacher(models.Model):
    # 教師類
    objects = models.Manager()

    class Meta:
        verbose_name = "講師資訊表"
        verbose_name_plural = verbose_name

    def __str__(self):
        return self.nickname

 

2.一對一

其中的to和on_delete是必須引數,且要設計null和blank都要為空

class TeacherAssistant(models.Model):
    # 助教類
    objects = models.Manager()

    # 外來鍵關聯
    # 一對一  助教和教師
    teacher = models.OneToOneField(to=Teacher, null=True, blank=True, on_delete=models.SET_NULL, verbose_name="講師")

 

2.一對多
其中的to和on_delete是必須引數,且要設計null和blank都為空

class Course(models.Model):
    objects = models.Manager()

    # 外來鍵關聯
    # 一對多  一個講師對應多個課程
    # 其中to和on_delete是必須引數
    teacher = models.ForeignKey(to=Teacher, null=True, blank=True, on_delete=models.CASCADE, verbose_name='課程講師')

 

3.多對多
其中的to是必須引數

class Student(models.Model):
    # 學生類
    objects = models.Manager()

    # 外來鍵關聯
    # 多對多 學生和課程
    course = models.ManyToManyField(to=Course, verbose_name='課程資訊')

 

(4)自關聯
利用自關聯的特性構建一個類似於省市縣的方法
關聯的時候可以使用‘self’或者是模型名

class AddressInfo(models.Model):
    address = models.CharField(max_length=200, null=True, blank=True, verbose_name='地址')
    pid = models.ForeignKey('self', models.CASCADE, null=True, blank=True, verbose_name='自關聯')
    # pid = models.ForeignKey('AddressInfo', null=True, blank=True, verbose_name='自關聯')

    def __str__(self):
        return self.address

 
三、元資料
文件地址:https://docs.djangoproject.com/en/2.2/ref/models/options/
設定資料庫的表名等資訊,對資料進行一個操作等
一些meta中的例項,官網有更多的欄位介紹和更加詳細的欄位資訊

class AddressInfo(models.Model):
    class Meta:
        ordering = ['pid']  # 指定按照什麼 欄位進行排序:-pid 是降序 沒有-表示升序 新增欄位的順序表示排序的先後結果
        verbose_name = '省市縣'  # 設定成一個直觀的名字在admin中
        verbose_name_plural = verbose_name  # 設定成複數
        abstract = True  # 不生成資料表 作為其他類的基類
        permissions = [('定義好的許可權', '給許可權的說明'), ]  # 二元的列表或者是元組
        managed = False  # 是否按照Django既定的模型類管理 比如是否建立資料表
        unique_together = []  # 聯合唯一鍵, 可以使用一元列表:只使用一組欄位作為約束條件 二元列表:[[], []]
        db_table = 'address'  # 修改資料庫的表名
        app_label = 'app_name'  # 定義模型類屬於哪一個應用, 在app沒有新增到setting的配置環境中
        db_tablespace = 'db_tablespace_name'  # 定義資料庫表空間的名字

 

四、Django的資料表
(1)models生成流程
1.資料表的程式碼

class Teacher(models.Model):
    nickname = models.CharField(max_length=30, primary_key=True, db_index=True, verbose_name='暱稱', )
    introduction = models.TextField(default="這位同學很懶,什麼也沒有留下來", verbose_name="簡介", )
    fans = models.PositiveIntegerField(default=0, verbose_name="粉絲數")
    create_date = models.DateField(auto_now_add=True, verbose_name='建立時間', )
    update_date = models.DateField(auto_now=True, verbose_name='更新時間', )
    objects = models.Manager()

    class Meta:
        verbose_name = "講師資訊表"
        verbose_name_plural = verbose_name

    def __str__(self):
        return self.nickname


class Course(models.Model):
    title = models.CharField(max_length=100, primary_key=True, db_index=True, verbose_name="課程名")
    course_type = models.CharField(choices=((0, '其他'), (1, "實戰課"), (2, "免費課程")), max_length=1, default=0, verbose_name="課程型別")
    price = models.PositiveSmallIntegerField(verbose_name="價格")
    volume = models.BigIntegerField(verbose_name="銷量")
    online = models.DateField(verbose_name="上線時間")
    create_date = models.DateField(auto_now_add=True, verbose_name='建立時間', )  # 系統自己新增
    update_date = models.DateField(auto_now=True, verbose_name='更新時間', )  # 系統自己新增
    objects = models.Manager()

    # 外來鍵關聯
    # 一對多  一個講師對應多個課程
    teacher = models.ForeignKey(to=Teacher, null=True, blank=True, on_delete=models.CASCADE, verbose_name='課程講師')

    class Meta:
        verbose_name = "課程資訊表"
        verbose_name_plural = verbose_name

    def __str__(self):
        # _get_FIELD_display可以展示Filed的型別
        return f"{self._get_FIELD_display(self.course_type)}-{self.title}"


class Student(models.Model):
    nickname = models.CharField(max_length=30, primary_key=True, db_index=True, verbose_name='暱稱', )
    age = models.PositiveSmallIntegerField(verbose_name="年齡")
    gender = models.CharField(choices=((1, "男"), (2, "女"), (0, "保密")), max_length=1, default=0, verbose_name="性別")
    study_time = models.PositiveIntegerField(default=0, verbose_name="學習時長(h)")
    create_date = models.DateField(auto_now_add=True, verbose_name='建立時間', )
    update_date = models.DateField(auto_now=True, verbose_name='更新時間', )
    objects = models.Manager()

    # 外來鍵關聯
    # 多對多 學生和課程
    course = models.ManyToManyField(to=Course, verbose_name='課程資訊')

    class Meta:
        verbose_name = "學生資訊表"
        verbose_name_plural = verbose_name

    def __str__(self):
        return self.nickname


class TeacherAssistant(models.Model):
    nickname = models.CharField(max_length=30, primary_key=True, db_index=True, verbose_name='暱稱', )
    hobby = models.CharField(max_length=30, null=True, blank=True, verbose_name='愛好', )
    create_date = models.DateField(auto_now_add=True, verbose_name='建立時間', )
    update_date = models.DateField(auto_now=True, verbose_name='更新時間', )
    objects = models.Manager()

    # 外來鍵關聯
    # 一對一
    teacher = models.OneToOneField(to=Teacher, null=True, blank=True, on_delete=models.SET_NULL, verbose_name="講師")

    class Meta:
        verbose_name = "講師助手資訊表"
        verbose_name_plural = verbose_name

    def __str__(self):
        return self.nickname
View Code

 

2.在對應的應用的migration中生成對應的migrations檔案
通過使用指令:【python manage.py makemigrations】完成資料的遷移,在對應的APP下面的migrations裡面生成遷移資料日誌


3.在django_migrations下面的生成記錄

通過指令:【python manage.py migrate】完成資料的建表資訊,將migrations裡面的資料日誌轉成資料庫語言存入資料庫中

 

4.在資料庫中生成的資料表

 
5.刪除資料表
因此再刪除的時候按照上面的四步就可以刪除一個models類

(2)匯入資料
1.Django-shell
使用【python manage.py shell】進入到命令列,匯入對應的類建立物件完成資料的儲存,【from [appname].models import [模板類]】

 

2.指令碼
按照sys、os——>配置環境檔案——>匯入Django——>匯入資料表.嚴格按照這個順序匯入資料資訊,否則就會報錯
其中settings前面的是專案的名字
參考blog:https://blog.csdn.net/qq_40999403/article/details/80694545

# -*- coding:utf-8 -*-
# __author__ == pzq
# @email: [email protected]

import os
import sys
import random
from datetime import date

# 將django專案根目錄加入環境變數
parent_path = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
sys.path.append(parent_path)

# 引入django配置檔案
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "film.settings")
# 啟動django
import django

django.setup()

from index.models import Student, Course, TeacherAssistant, Teacher


def import_data():
    # 使用Django ORM匯入資料
    # 講師資料 create()
    Teacher.objects.create(nickname='Jack', introduction="Python工程師", fans=random.randint(500, 1000))
    Teacher.objects.create(nickname="Jerry", introduction="Java工程師", fans=random.randint(200, 800))
    Teacher.objects.create(nickname="Peter", introduction="PHP工程師", fans=random.randint(400, 700))
    Teacher.objects.create(nickname="Kate", introduction="C++工程師", fans=random.randint(100, 400))

    # 課程資料 bulk_create() 批量匯入資料
    # 外來鍵的連線通過物件
    Course.objects.bulk_create([Course(title=f"python入門課程{i}", course_type=random.choice((0, 1, 2)), price=random.randint(100, 1000),
                                       volume=random.randint(1000, 10000), online=date(random.randint(2010, 2019), random.randint(1, 12), random.randint(1, 28)),
                                       teacher=Teacher.objects.get(nickname="Jack"))
                                for i in range(1, 4)])

    Course.objects.bulk_create([Course(title=f"Java入門課程{i}", course_type=random.choice((0, 1, 2)), price=random.randint(100, 1000),
                                       volume=random.randint(2000, 9000), online=date(random.randint(2010, 2019), random.randint(1, 12), random.randint(1, 28)),
                                       teacher=Teacher.objects.get(nickname="Jerry"))
                                for i in range(1, 5)])

    Course.objects.bulk_create([Course(title=f"PHP進階課程{i}", course_type=random.choice((0, 1, 2)), price=random.randint(100, 1000),
                                       volume=random.randint(1000, 4000), online=date(random.randint(2010, 2019), random.randint(1, 12), random.randint(1, 28)),
                                       teacher=Teacher.objects.get(nickname="Peter"))
                                for i in range(1, 3)])

    Course.objects.bulk_create([Course(title=f"C++高階課程{i}", course_type=random.choice((0, 1, 2)), price=random.randint(100, 1000),
                                       volume=random.randint(1000, 2000), online=date(random.randint(2010, 2019), random.randint(1, 12), random.randint(1, 28)),
                                       teacher=Teacher.objects.get(nickname="Kate"))
                                for i in range(1, 4)])

    # 學生資料
    # update_or_create()  先通過nickname現在資料庫中找尋這個資料  如果存在就update如果不存在就create
    # 把主鍵或者唯一鍵放在外面 把其他引數放在裡面
    Student.objects.update_or_create(nickname="A同學", defaults={"age": random.randint(18, 28),
                                                               "gender": random.choice((0, 1, 2)),
                                                               "study_time": random.randint(1000, 2000)})

    Student.objects.update_or_create(nickname="B同學", defaults={"age": random.randint(18, 28),
                                                               "gender": random.choice((0, 1, 2)),
                                                               "study_time": random.randint(1000, 2000)})

    Student.objects.update_or_create(nickname="C同學", defaults={"age": random.randint(18, 28),
                                                               "gender": random.choice((0, 1, 2)),
                                                               "study_time": random.randint(1000, 2000)})

    Student.objects.update_or_create(nickname="D同學", defaults={"age": random.randint(18, 28),
                                                               "gender": random.choice((0, 1, 2)),
                                                               "study_time": random.randint(1000, 2000)})

    # 接下來新增外來鍵欄位
    # 正向新增 pk可以代替主鍵查詢  子表關聯到父表
    # 銷量大於等於1000的課程
    Student.objects.get(nickname="A同學").course.add(*Course.objects.filter(volume__gte=1000))
    # 銷量大於5000的課程
    Student.objects.get(nickname="B同學").course.add(*Course.objects.filter(volume__gt=5000))
    # 反向新增  通過課程關聯到學生
    # 學習時間大於等於500小時的同學
    Course.objects.get(title="python入門課程1").student_set.add(*Student.objects.filter(study_time__gte=1500))
    # 學習時間小於等於500小時的同學
    Course.objects.get(title="python入門課程2").student_set.add(*Student.objects.filter(study_time__lte=1500))

    # 助教資料 get_or_create() 先通過nickname的關鍵字或者是主鍵進行查詢 如果有就獲取沒有就建立
    TeacherAssistant.objects.update_or_create(nickname="助教1", defaults={"hobby": "慕課網學習", "teacher": Teacher.objects.get(nickname="Jack")})
    TeacherAssistant.objects.update_or_create(nickname="助教2", defaults={"hobby": "中國Mooc學習", "teacher": Teacher.objects.get(nickname="Jerry")})
    TeacherAssistant.objects.update_or_create(nickname="助教3", defaults={"hobby": "程式設計師客棧", "teacher": Teacher.objects.get(nickname="Peter")})
    TeacherAssistant.objects.update_or_create(nickname="助教4", defaults={"hobby": "牛客網", "teacher": Teacher.objects.get(nickname="Kate")})

    return True


if __name__ == '__main__':
    try:
        if import_data():
            print("資料匯入成功!")
    except Exception as AddError:
        print(AddError)
View Code

 

3.fixtures  Django serialization ——>  model  儲存到資料庫
使用指令【python manage.py dumpdata > film.json】輸出資料庫檔案


使用指令【python manage.py loaddata film.json】輸入資料到資料庫

 

4.通過資料庫層面來實現
匯入SQL檔案等

(3)匯出資料
1.mange.py dumpdata > [檔名]
2.使用pycharm或者是Navicat等資料工具來匯出
3.使用資料庫層面:MySQL  dumpdata來實現

五、models API
queryset文件:https://docs.djangoproject.com/en/2.2/ref/models/querysets/
(1)查詢介紹

def start(request):
    """
    int型別的操作函式:
    gte:大於等於
    exact:等於
    gt:大於
    in:在某某之內
    isnull:是否為空
    lt:小於
    lte:小於等於
    range:在什麼範圍內
    字元型更多:其中i是忽略大小寫敏感
    """
    # 1.查詢 檢索 過濾
    # 返回的是物件
    teacher = Teacher.objects.filter(fans__gte=500)  # 是個query集 給欄位匹配資料的時候一定要用雙下劃線
    # 其中pk是主鍵 在這裡就是nickname的關鍵字
    t1 = Teacher.objects.get(pk="Jack")  # get只能返回一條結果 所有采取主鍵或者是唯一鍵
    t2 = Teacher.objects.all()  # 查詢所有資料 返回所有資料的物件集
    # # 2.欄位匹配大小寫敏感
    t3 = Teacher.objects.filter(pk__icontains="A")  # 有很多可以去檢視一下官網
    # # 3.結果切片  排序 鏈式查詢
    # 切片
    t3_1 = Teacher.objects.all().order_by('-fans')[1:]
    # 排序
    t4 = Teacher.objects.all().order_by('-fans')  # -代表降序 按照老師的粉絲數進行排序
    t4_1 = Teacher.objects.all().order_by('fans')  # 預設升序
    # # 鏈式查詢
    t5 = Teacher.objects.filter(fans__gte=500).order_by('fans')  # 先獲取一個欄位的屬性 在對獲取的資料集在採取升序排序
    t6 = Teacher.objects.filter(fans__gte=500).order_by('-fans')  # 先獲取一個欄位的屬性 在對獲取的資料集在採取降序排序
    # 4.查詢原生sql語句 通過query進行查詢
    print(f"我是查詢語句{str(t6.query)}")
    return render(request, 'learn_set.html')
View Code

 

(2)返回新的queryset的API

def start(request):
"""  查詢介紹  返回新的 Query API  """
    # 1.all()  filter()  order_by():排序  exclude():除了xx元素以外  reverse():反向排序  distinct():去重
    # 可以用pk代替關鍵字  exclude除去含有關鍵字的資訊
    st_0 = Student.objects.all().exclude(pk="A同學")
    # print(f"我是exclude:{st_0}")
    # 使用reverse的時候可以在Meta中用ordering指定排序的欄位 多個ordering的時候取第一個 預設按照關鍵字的順序輸出
    st_0_1 = Student.objects.reverse()
    # print(f"我是reverse:{st_0_1}")

    # 2.extra():給欄位取別名   defer():排除一些欄位   only():選擇一些欄位
    # extra(): extra(select={"[要取的別名]": "[原來欄位名]"})
    st_1 = Student.objects.all().extra(select={"name": "nickname"})
    # for i in st_1:
    #     print(f"我是extra:{i.name}")
    st_2 = Student.objects.all().only('nickname', 'age')
    # print(f"我是only_query:{str(st_2.query)}")

    # 3.values():字典 values_list():元組  獲取字典或者是元組形式的queryset
    # values() 輸出的是dict型別的
    st_3_0 = TeacherAssistant.objects.values('nickname', 'hobby')
    # print(f"我是values:{st_3_0}")
    # values_list() 輸出的是元組型別的資料
    st_3_1 = TeacherAssistant.objects.values_list('nickname', flat=True)  # flat:將單個欄位的資料直接放到列表裡面  只限於獲取單個數據的資訊
    # print(f"我是values_list:{st_3_1}")

    # 4.根據時間和日期獲取查詢集  dates:年月日  datetimes年月日時分秒查詢欄位多一點有時分秒  使用什麼查詢方式取決於定義欄位的型別
    # datetimes('[查詢時間的欄位]', 'month', order='DESC')
    st_4 = Course.objects.dates('online', 'year', order='DESC')  # ASC 升序排列(預設)  DESC降序排列
    # print(f"我是dates:{st_4}")

    # 5.集合的運算  union():並集   intersection():交集   difference():差集
    s_1 = Student.objects.filter(study_time__gte=1600)  # 大於等於1500
    s_2 = Student.objects.filter(study_time__lte=1500)  # 小於等於1600
    # print(f"我是union:{s_1.union(s_2)}")  # 只支援取並集
    # print(f"我是intersection:{s_1.intersection(s_2)}")  # 資料庫不支援
    # print(f"我是difference:{s_1.difference(s_2)}")  # 資料庫不支援

    # 6.優化查詢api  select_related() 一對一 多對一的優化查詢   prefetch_related() 一對多 多對多的優化查詢
    # select_related()
    # 通過課程獲取講師資訊 查詢相關資訊通過外接欄位進行連線
    c_1 = Course.objects.all().select_related('teacher')
    for c in c_1:
        print(f"課程資訊:{c.title}--{c.teacher.nickname}--{c.teacher.fans}")
    # prefetch_related() 多對多
    s_1 = Student.objects.filter(age__lte=30).prefetch_related('course')
    for s in s_1:
        for i in s.course.all():  # 獲取到的是managerelmanage的物件
            print(f"{s.nickname}--{i.title}")  # 輸出課程的資訊
    # 反向查詢:根據父表查詢子表
    # 通過在資料段的對應關係  [字表的表名]_set可以替換為related_name的值
    t_1 = Teacher.objects.get(nickname='Jack').teach.all()
    print(f"我是反向查詢{t_1}")

    # 7.annotate() 使用聚合計數、求和、平均數、raw()、執行原生的SQL
    # 求和 sum_1 = Course.objects.values('[處理表單]').annotate(vol=Sum('[處理欄位]'))
    sum_1 = Course.objects.values('teacher').annotate(vol=Sum('volume'))
    print(f"我是求和:{sum_1}")
    # 平均值
    ave_1 = Student.objects.values('course').annotate(time=Avg('study_time'))
    print(f"我是求平均值:{ave_1}")
    # row可以寫原生資料語句 裡面執行原生的SQL語句
    # 參考文件
    # https://docs.djangoproject.com/en/2.2/topics/db/sql/
View Code

 

(3)不返回新的query的API

def start(request):
"""  不返回查詢集的API """
    # 參考文件:https://docs.djangoproject.com/en/2.2/ref/models/querysets/#raw
    # 1.獲取物件 get() get_or_create() first() last()  latest()  earliest()  in_bulk()
    # get() 獲取物件
    # get_or_create() 有資料就通過get獲取沒有就建立資料
    # first()  # 第一條記錄
    # print(f"我是first:{Course.objects.first()}")
    # last()  # 最後一條記錄
    # print(f"我是last:{Course.objects.last()}")
    # latest()  # 最近的記錄 需要在模型類裡面設定 get_latest_by = [建立的欄位] 代表根據建立的欄位進行排序
    # 也可以在排序的時候自己指定 更加方便我們自己的操作
    # print(f"我是latest{Course.objects.latest('online')}")
    # earliest() # 最早的記錄
    # print(f"我是earliest{Course.objects.earliest('update_date')}")
    # in_bulk() 批量返回物件 根據主鍵的值傳遞一個列表 列表中傳遞主鍵的值
    # print(Course.objects.in_bulk(['Java入門課程1', 'Java入門課程2', 'python入門課程2']))
    # 2.建立物件  create():建立物件  bulk_create():批量建立物件  create_or_update():如果沒有就建立有就更新
    # bulk_create:給函式建立一個列表
    # 3.更新物件 update():更新  update_or_create():更新或建立
    # update()
    # print(f"我是更新前的價格:{Course.objects.get(title='C++高階課程1').price}")
    # Course.objects.filter(title="C++高階課程1").update(price=568)
    # print(f"我是更新後的價格:{Course.objects.get(title='C++高階課程1').price}")
    # 4.刪除物件 delete():使用filter過濾
    # print(Course.objects.filter(title="test_1").delete())
    # 5.其他操作 exist():是否存在  count():統計個數  aggregate():聚合
    # exist()
    # print(Course.objects.filter(title="test_1").exists())
    # print(Course.objects.filter(title="PHP進階課程2").exists())
    # count()記錄資料表中的資料個數
    # print(Course.objects.count())
    # annotate():和value配合使用 對分組結果進行排序  aggregate():對資料庫中的資料結果進行處理
    # print(Course.objects.aggregate(Max('price'), Min('price'), Avg('price'), Sum('volume')))
    return render(request, 'learn_set.html')
View Code

 
(4)自定義聚類查詢
1.自定義查詢方法
在individual.py中加入以下程式碼

from django.db import models


class Concat(models.Aggregate):
    """ORM用來分組顯示其他欄位 相當於group_concat"""
    function = 'GROUP_CONCAT'
    template = '%(function)s(%(distinct)s%(expressions)s)'

    def __init__(self, expression, distinct=False, **extra):
        super(Concat, self).__init__(
            expression,
            distinct='DISTINCT ' if distinct else '',
            output_field=models.CharField(),
            **extra)

 
2.引用

在views.py中的引用

from .individual import Concat
def start(request):
""" 自定義聚合查詢 """
    # 這個title對應查詢結果中的key Concat裡面的才是我們需要查詢的欄位
    course = Course.objects.values('teacher').annotate(title=Concat('title'))
    for c in course:
        print(c)
    return render(request, 'learn_set.html')

 
(5)F物件查詢
官方文件:https://docs.djangoproject.com/en/2.2/ref/models/expressions/#django.db.models.F

def start(request):
""" F查詢 """
    # 操作欄位資料或者是將一個欄位與另一個欄位進行比較
    # # 將所有的價格減11
    # Course.objects.update(price=F('price') - 11)
    # # 獲取銷量大於價格10倍的欄位
    # course = Course.objects.filter(volume__gte=F('price') * 10)
    # for c in course:
    #     print(f"{c.title}--{c.price}--{c.volume}")
    return render(request, 'learn_set.html')

 


(6)Q物件查詢
官方文件:https://docs.djangoproject.com/en/2.2/ref/models/querysets/#q-objects

def start(request):
    """ Q物件結合 &:and |:or :not 實現複雜的查詢 """
    # 查詢所有Java課程  並且銷量大於等於5000
    print(Course.objects.filter(Q(title__icontains='java') & Q(volume__gte=5000)))
    # 查詢所有Python語言或者是銷量小於2000的課程
    print(Course.objects.filter(Q(title__icontains='python') | Q(volume__lte=2000)))
    return render(request, 'learn_set.html')

 

 

(7)模型類例項:

class Teacher(models.Model):
    nickname = models.CharField(max_length=30, primary_key=True, db_index=True, verbose_name='暱稱', )
    introduction = models.TextField(default="這位同學很懶,什麼也沒有留下來", verbose_name="簡介", )
    fans = models.PositiveIntegerField(default=0, verbose_name="粉絲數")
    create_date = models.DateField(auto_now_add=True, verbose_name='建立時間', )
    update_date = models.DateField(auto_now=True, verbose_name='更新時間', )
    # 每一個非抽象model類必須Manager新增一個例項
    objects = models.Manager()

    class Meta:
        verbose_name = "講師資訊表"
        verbose_name_plural = verbose_name

    def __str__(self):
        return self.nickname


class Course(models.Model):
    title = models.CharField(max_length=100, primary_key=True, db_index=True, verbose_name="課程名")
    course_type = models.CharField(choices=((0, '其他'), (1, "實戰課"), (2, "免費課程")), max_length=1, default=0, verbose_name="課程型別")
    price = models.PositiveSmallIntegerField(verbose_name="價格")
    volume = models.BigIntegerField(verbose_name="銷量")
    online = models.DateField(verbose_name="上線時間")
    create_date = models.DateField(auto_now_add=True, verbose_name='建立時間', )  # 系統自己新增
    update_date = models.DateField(auto_now=True, verbose_name='更新時間', )  # 系統自己新增
    objects = models.Manager()

    # 外來鍵關聯
    # 多對一  多個課程對應一個講師
    teacher = models.ForeignKey(to=Teacher, null=True, blank=True, on_delete=models.CASCADE, verbose_name='課程講師', related_name='teach')

    class Meta:
        verbose_name = "課程資訊表"
        verbose_name_plural = verbose_name
        # 根據建立的欄位進行排序  方便latest和earliest進行排序  也可以在排序時指定
        # get_latest_by = 'online'

    def __str__(self):
        # get_[要展示的欄位]_display()就可以輸出了  如2--python入門課程1>,
        return f"{self.get_course_type_display()}--{self.title}"


class Student(models.Model):
    nickname = models.CharField(max_length=30, primary_key=True, db_index=True, verbose_name='暱稱', )
    age = models.PositiveSmallIntegerField(verbose_name="年齡")
    gender = models.CharField(choices=((1, "男"), (2, "女"), (0, "保密")), max_length=1, default=0, verbose_name="性別")
    study_time = models.PositiveIntegerField(default=0, verbose_name="學習時長(h)")
    create_date = models.DateField(auto_now_add=True, verbose_name='建立時間', )
    update_date = models.DateField(auto_now=True, verbose_name='更新時間', )
    objects = models.Manager()

    # 外來鍵關聯
    # 多對多 學生和課程
    course = models.ManyToManyField(to=Course, verbose_name='課程資訊')

    class Meta:
        # 指定多個時  按第一個進行排序
        # 不指定根據關鍵字的順序進行排序  如在資料表中新增的資料順序
        ordering = ['study_time']
        verbose_name = "學生資訊表"
        verbose_name_plural = verbose_name

    def __str__(self):
        return self.nickname


class TeacherAssistant(models.Model):
    nickname = models.CharField(max_length=30, primary_key=True, db_index=True, verbose_name='暱稱', )
    hobby = models.CharField(max_length=30, null=True, blank=True, verbose_name='愛好', )
    create_date = models.DateField(auto_now_add=True, verbose_name='建立時間', )
    update_date = models.DateField(auto_now=True, verbose_name='更新時間', )
    objects = models.Manager()

    # 外來鍵關聯
    # 一對一  如果on_delete置空就要將null, blank都設定為空
    teacher = models.OneToOneField(to=Teacher, null=True, blank=True, on_delete=models.SET_NULL, verbose_name="講師")

    class Meta:
        verbose_name = "講師助手資訊表"
        verbose_name_plural = verbose_name

    def __str__(self):
        return self.nickname
View Code

 

 六、總結
本篇blog簡單的介紹了orm的內容,也是Django後端內容中最為重要的一個部分,其他詳情請參考Django的官方文件

&n