必備知識點 模型層ORM

Formerly0^0發表於2024-03-28

模型層ORM

1.Django連線MySQL資料庫

1.1 配置mysql引數

# MySQL配置項
DATABASES = {
    'default': {
        # ENGINE :預設的引擎 mysql
        'ENGINE': 'django.db.backends.mysql',
        # HOST : 主機地址127.0.0.1 / localhost
        "HOST": "47.100.88.80",
        # PORT : mysql 的服務埠
        "PORT": 3306,
        # USER : 使用者名稱
        "USER": "root",
        # PASSWORD : 資料庫密碼
        "PASSWORD": "123456",
        # NAME  : 資料庫名字
        "NAME":"django_02",
        # CHARSET : 預設編碼集
        "CHARSET": "utf8mb4"
    }
}

1.2 啟動Django報錯

  • Did you install mysqlclient?

1.3 啟動mysql報錯

1.3.1 解決辦法一
  • 猴子補丁
  • 可以放在任意位置的 __init__.py檔案中
import pymysql

pymysql.install_as_MySQLdb()
1.3.2 下載第三方模組
  • 3.x版本以後建議你使用 mysqlclient
pip install mysqlclient
  • 運氣
    • win 電腦給力一點,安裝就不會報錯
  • mac系統安裝 mysqlclient 費勁
1.3.3 win報錯解決辦法
  • 訪問 whl檔案的官網
  • https://pypi.org/project/mysqlclient/#files
pip install mysqlclient-2.2.4-cp310-cp310-win_amd64.whl

2. Django中的orm框架

2.1 什麼是ORM

  • ORM是一種將物件與關係型資料庫之間的對映的技術,主要實現了以下三個方面的功能:
    • 資料庫中的表對映為Python中的類
    • 資料庫中的欄位對映為Python中的屬性
    • 資料庫中的記錄對映為Python中的例項
  • ORM的主要優點是可以減少開發人員編寫重複的SQL語句的時間和工作量,並且可以減少由於SQL語句的調整和更改所帶來的錯誤。

2.2 DjangoORM框架的優點

  • 與其他ORM框架相比,Django ORM擁有以下優點:
  • 簡單易用:Django ORM的API非常簡單,易於掌握和使用。
  • 豐富的API:Django ORM提供了豐富的API來完成常見的資料庫操作,如增刪改查等,同時也支援高階查詢和聚合查詢等操作。
  • 具有良好的擴充套件性:Django ORM可以與其他第三方庫進行無縫整合,如Django REST framework、Django-Oscar等。
  • 自動對映:Django ORM支援自動對映,開發者只需要定義資料庫表的結構,就可以自動生成相應的Python類,從而減少開發過程中的重複程式碼量。

2.3 ORM之建表操作

2.3.1 建立模型表
class User(models.Model):
    # 資料庫中的欄位對映未puthon的屬性
    # 定義一個使用者名稱,字串型別,長度
    # mysql 字串型別,varchar char
    # CharField字串型別,max_length最大長度,verbose_name註釋
    username = models.CharField(max_length=32, verbose_name="使用者名稱")
    password = models.CharField(max_length=32, verbose_name="密碼")
    # IntegerField相當於mysql的int欄位
    age = models.IntegerField(verbose_name="年齡")
    # FloatField相當於mysql的float欄位
    salary = models.FloatField(verbose_name="薪資")
2.3.2 遷移檔案
  • 生成遷移檔案
# 命令列
python manage.py makemigrations
chenxu@chenxudeMacBook-Pro new_djangoProject % python3.10 manage.py makemigrations

Migrations for 'app01':
  app01/migrations/0001_initial.py
    - Create model User
  • 遷移檔案生效
# 遷移記錄生效
python manage.py migrate

3. ORM操作

3.1 建立模型表

from django.db import models


# Create your models here.
class User(models.Model):
    name = models.CharField(max_length=32, verbose_name="姓名")
    age = models.IntegerField(verbose_name="年齡")

    # DateTimeField時間日期型別
    # auto_now_add 第一次註冊資料的時候自動新增的時間和日期
    # auto_now 每一次更新資料的最後時間
    register_time = models.DateTimeField(auto_now_add=True, verbose_name="註冊時間")
    update_time = models.DateTimeField(auto_now=True, verbose_name="更新時間")
  • 建立一對一表關係,
  • models.OneToOneField(to=UserInfo, on_delete=models.CASCADE)
class UserInfo(models.Model):
    name = models.CharField(max_length=32, verbose_name='姓名')
    # 一對多
    dp = models.ForeignKey(to=Depart, on_delete=models.CASCADE, verbose_name='標題id')

    class Meta:
        db_table = 'userinfo'


class Blog(models.Model):
  # 一對一
    user = models.OneToOneField(to=UserInfo, on_delete=models.CASCADE)
    blog = models.CharField(max_length=32, verbose_name='部落格地址')
    desc = models.TextField(verbose_name='簡介')

  • 一對多關係
  • models.ForeignKey(to=Depart, on_delete=models.CASCADE, verbose_name='標題id')
class Depart(models.Model):
    title = models.CharField(max_length=32, verbose_name='標題')

    class Meta:
        db_table = 'depart'

# 使用者表
class UserInfo(models.Model):
    name = models.CharField(max_length=32, verbose_name='姓名')
    # 一對多
    dp = models.ForeignKey(to=Depart, on_delete=models.CASCADE, verbose_name='標題id')

    class Meta:
        db_table = 'userinfo'
  • 遷移資料庫
python manage.py makemigrations
python manage.py migrate

3.2 操作模型層

import os

from django.test import TestCase

# Create your tests here.
if __name__ == '__main__':
    os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'orm_project.settings')
    import django

    django.setup()
    from app01.models import User

    # 1.增加資料
    # user_obj = User.objects.create(name='serein', age=20)
    # print(user_obj)

    # 2.刪除資料
    # 2.1.先查詢直接刪除
    # User.objects.filter(pk=1).delete()
    # 2.2 查詢後在刪除
    # user_obj = User.objects.filter(pk=3)
    # user_obj.delete()

    # 3.修改資料
    # 3.1 查詢直接修改
    # User.objects.filter(pk=2).update(age=22)
    # 3.2 查詢後在修改,用.屬性修改,修改完必須物件.save儲存,不然不生效
    # user_obj = User.objects.filter(pk=2).first()
    # user_obj.age = 30
    # user_obj.save()

    # 4.查詢資料
    # 4.1 filter()方法,查詢不到資料會返回null
    # .first()查詢第一個
    # .last()最後一個
    # user_object = User.objects.filter(pk=2).first()
    # print(user_object)  # <QuerySet [<User: User object (2)>]>
    # 4.2 get()方法,查不到就報錯
    # user_obj = User.objects.get(pk=2)
    # print(user_obj)  # User object (2)  查到的是user物件

    # 5.查詢欄位的值和鍵,查詢當前表中所有的資料
    # 5.1 獲取到的是字典型別的帶鍵值的
    # user_data = User.objects.values()
    # print(user_data)
    # 5.2 values_list(),獲得的是元祖,沒有鍵,只有值
    # user_object1 = User.objects.filter(pk=2).values_list()
    # print(user_object1)

    # 6.對查詢到的資料進行去重
    # user_obj = User.objects.values('age').distinct()
    # print(user_obj)  # <QuerySet [{'age': 30}, {'age': 40}, {'age': 28}]>

    # 7.排序
    # 排序對排序條件欄位不加-號時代表從小到大,正序
    # user_object = User.objects.order_by('age').values()
    # print(user_object)
    # # 排序對排序條件欄位加-號時代表從大到小,倒序
    # user_object = User.objects.order_by('-age').values()
    # print(user_object)

    # 8.統計個數
    # 直接統計表裡的資料
    # user_obj = User.objects.count()
    # print(user_obj)
    # # 統計過濾條件篩選後的資料
    # user_obj = User.objects.filter(pk=2).count()
    # print(user_obj)

    # 9.剔除指定資料,相當於mysql中的不等於,
    # mysql中的SELECT * FROM User WHERE age != 40
    # user_obj = User.objects.exclude(age=40)
    # print(user_obj)

    # 10.校驗資料是否存在
    user_exist = User.objects.filter(pk=1).exists()
    print(user_exist)
總結
    # (1) .create() : 建立資料
    # (2) .delete() : 刪除資料
    # (3) .filter() : 查詢指定資料,查不到不會報錯,查出來是 queryset 物件
    # .filter().first()
    # .filter().last()
    # (3.1) .all() : 獲取到當前表的所有資料物件 , queryset
    # (4) .get() : 查不到直接報錯 ,查出來直接是使用者 obj 物件
    # (5) .filter().update() : 修改資料(前提是查資料)
    # (6) .values() : 將所有的資料查出來,格式是字典
    # (7) .value_list() :  將所有的資料查出來,格式是元組
    # (8) .values().distinct() : 去重
    # (9) .order_by() : 按照指定欄位排序 正序不加符號 ,倒序加 -
    # (9.1) .order_by().reverse()也可以排序
    # (10) .count() : 統計資料條數,可以統計整張表的資料量,也可以先過濾,統計過濾後的資料量
    # (11) .exclude() : 剔除符合條件的指定資料
    # (12) .filter().exist() : 判斷當前資料是否存在

3.3 雙下劃線查詢

# -*-coding: utf-8 -*-
# Project: orm_project
# @File : 02test__.py
# author : Serein
# Time: 2024-03-05 17:09
# IDE : PyCharm

import os
import random

from django.test import TestCase

# Create your tests here.
if __name__ == '__main__':
    os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'orm_project.settings')
    import django

    django.setup()
    from app01 import models

    # 隨機生成10條資料
    # for i in range(10):
    #     age = random.randint(20, 99)
    #     user_obj = User.objects.create(name=f"serein_{age}", age=age)

    # 1.條件運算
    # 1.1 大於28,__gt大於
    # user_obj = models.User.objects.filter(age__gt=28).values_list().count()
    # print(user_obj)  # 11
    # 1.2 小於28,__lt小於
    # user_obj = models.User.objects.filter(age__lt=28).values_list().count()
    # print(user_obj)  # 1
    # 1.3 大於等於28, __gte
    # user_obj = models.User.objects.filter(age__gte=28).values_list().count()
    # print(user_obj) # 12
    # 1.4 小於等於28,__lte
    # user_obj = models.User.objects.filter(age__lte=28).values_list().count()
    # print(user_obj)  # 2
    # 1.5 或條件,__in=(條件)
    # user_obj = models.User.objects.filter(age__in=(28, 35, 74, 98)).values()
    # print(user_obj)
    # 1.6 兩個條件之間,__range=()
    # user_obj = models.User.objects.filter(age__range=(28, 98)).values().count()
    # print(user_obj)  # 11
    # 1.7 模糊查詢,預設區分大小寫 __contains=條件,只對字串生效
    # user_obj = models.User.objects.filter(name__contains='_').values().count()
    # print(user_obj)
    # # 取消大小寫限制 icontains
    # user_obj = models.User.objects.filter(name__icontains="S").count()
    # print(user_obj)
    # 1.8 以指定字元開頭/結尾,__startswith,__endswith
    # user_obj = models.User.objects.filter(name__startswith="s").values()
    # print(user_obj)  # 11
    # user_obj = models.User.objects.filter(name__endswith="k").values()
    # print(user_obj)  # 1
    # 1.9 過濾指定時間區間
    # current_time = datetime.datetime.now()
    # user_obj = models.User.objects.filter(register_time__lt=current_time)
    # print(user_obj)

3.4 多表查詢

3.4.1 建立表
from django.db import models


# 圖書表
class Book(models.Model):
    # 書名
    title = models.CharField(max_length=32)
    # 書價格
    price = models.IntegerField()
    # 出版日期
    publish_date = models.DateTimeField()
    # 多對多的建立方式的第一種,直接建立一個ManyToManyField,指向需要關聯的另一張表,django內部幫你自動完成第三張表的建立
    author = models.ManyToManyField('Author')
    publish = models.ForeignKey('Publish', on_delete=models.CASCADE)

    # 多對多的建立方式的第二種,半自動建立第三張表,透過引數關聯,
    # author = models.ManyToManyField('Author', through='BookAuthor', through_fields=('book', 'author'))

    # 圖書和作者:多對多,需要建立第三張表
    # 圖書和作者,一本書可以背多個作者寫,
    # 一個作者也可以寫多本書

    # 圖書和出版者之間,一對多
    # 一本書只能有一個出版社出版

# 多對多的建立方式的第三種,直接建立第三張表,建立外來鍵關係(不推薦)
# class BookAuthor(models.Model):
#     book = models.ForeignKey('Book', on_delete=models.CASCADE)
#     author = models.ForeignKey('Author', on_delete=models.CASCADE)


# 出版社表
class Publish(models.Model):
    # 出版社名字
    name = models.CharField(max_length=32)
    # 出版社地址
    addr = models.CharField(max_length=255)
    # 出版社郵箱
    email = models.EmailField()


# 作者表
class Author(models.Model):
    # 作者姓名
    name = models.CharField(max_length=21)
    # 作者年齡
    age = models.IntegerField()

    # 作者和作者詳情,一對一的關係
    # 建立外建欄位`
    author_detail = models.ForeignKey('AuthorDetail', on_delete=models.CASCADE)


# 作者詳細資訊表
class AuthorDetail(models.Model):
    # 作者電話
    phone = models.CharField(max_length=11)
    # 作者地址
    addr = models.CharField(max_length=255)

3.4.2 多對多關係第三張表的建立方式
  • 全自動
class Book(models.Model):
    # 多對多的建立方式的第一種,直接建立一個ManyToManyField,指向需要關聯的另一張表,django內部幫你自動完成第三張表的建立
    author = models.ManyToManyField('Author')
  • 半自動
class Book(models.Model):
    name = models.CharField(max_length=32)
    # 全自動
    # through_fields : 當前表是誰,第一個引數就是誰
    # 判斷的本質:透過第三張表查詢對應的表,需要用到哪個欄位就把哪個欄位放在前面
    authors = models.ManyToManyField(to='Author', through='BookAuthor', through_fields=('book', 'author'))


class Author(models.Model):
    name = models.CharField(max_length=32)


class BookAuthor(models.Model):
    book_id = models.ForeignKey(to='Book')
    author_id = models.ForeignKey(to='Author')
  • 手動,自己建立第三張表並建立外建
class BookAuthor(models.Model):
     book = models.ForeignKey('Book', on_delete=models.CASCADE)
     author = models.ForeignKey('Author', on_delete=models.CASCADE)

3.4.3 操作一對多和多對多關係
  • 多對多關係
# -*-coding: utf-8 -*-
# Project: orm_project
# @File : 多對多外建關係.py
# author : Serein
# Time: 2024-03-05 18:42
# IDE : PyCharm
import os
import random

from django.test import TestCase

# Create your tests here.
if __name__ == '__main__':
    os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'orm_project.settings')
    import django

    django.setup()
    from app01 import models

    # 插入資料
    # 1.建立作者詳情
    # detail_obj_serein = models.AuthorDetail.objects.create(phone="13023056160", addr='北京朝陽')
    # models.Author.objects.create(name='serein', age=18, author_detail=detail_obj_serein)
    # 2.建立作者
    # detail_obj_zzp = models.AuthorDetail.objects.create(phone="18712059833", addr='北京三平')
    # models.Author.objects.create(name='zzp', age=18, author_detail=detail_obj_zzp)
    #
    # # 3.建立出版社
    # models.Publish.objects.create(name='朝陽出版社', addr='北京朝陽', email='123@qq.com')
    # models.Publish.objects.create(name='上海出版社', addr='上海虹橋', email='456@qq.com')

    # 4.建立圖書
    # models.Book.objects.create(title='西遊記', price=999, publish_id=1)
    # models.Book.objects.create(title='水滸傳', price=888, publish_id=1)
    # models.Book.objects.create(title='白蛇傳', price=666, publish_id=2)
    #
    # 5. 圖書關聯作者和操作第三張表
    # (1)新增外來鍵關係:在建立外建關係的表物件中獲取到第三張表,利用add方法新增外來鍵
    # 拿作者
    # author_obj = models.Author.objects.get(pk=1)
    # # 拿圖書物件
    # book_obj = models.Book.objects.get(pk=1)
    # book_obj.author.add(author_obj)
    # (2) 刪除外來鍵關係,在建立外來鍵關係的表物件中獲得第三張表,利用remove方法刪除外建關係
    # 獲取到西遊記,
    # author_obj = models.Author.objects.get(pk=1)
    # book_obj = models.Book.objects.get(pk=1)
    # book_obj.author.remove(author_obj)
    # (3) 修改多對多外建關係,在建立外建關係的表物件中獲取到第三章表,利用set方法修改外建關係,set引數為列表
    # 按照上述先刪除外建關係,在新增外建關係
    # author_obj_serein = models.Author.objects.get(pk=1)
    # author_obj_zzp = models.Author.objects.get(pk=2)
    # book_obj = models.Book.objects.get(pk=1)
    # # 自動刪除外建關係然後自動關聯外建關係
    # book_obj.author.set([author_obj_serein,author_obj_zzp])
    # (4) 清空第三張表的外建關係,在建立外建關係的表物件中獲取到第三章表,利用clear清空表外建關係
    book_obj = models.Book.objects.get(pk=1)
    book_obj.author.clear()

  • 一對多的關係
   # 5.操作一對多關係
    # (1) 新增外建關係
    # 方式一:獲取到物件在建立資料的時候指定publish=物件
    # 方式二: 建立資料時指定 publish_id = id
    # publish_obj = models.Publish.objects.get(pk=1)
    # book_obj = models.Book.objects.get(pk=1)
    # # 方式三: 先拿到物件,然後物件.屬性=id
    # book_obj.publish_id = 2
    # # 需要sava儲存,否則不生效
    # book_obj.save()
    # (2) 刪除外建關係,過濾後直接刪除
    # (3) 查詢
    # book_obj = models.Book.objects.get(pk=1)
    # print(book_obj.publish.name)
    # (4) 改
    # 方式一: 先查詢直接修改
    # models.Book.objects.filter(pk=1).update(publish_id=1)
    # 方式二:先拿到物件,然後物件.屬性=id
    # book_obj = models.Book.objects.get(pk=1)
    # book_obj.publish_id = 2
    # book_obj.save()

3.5 正反向概念

# 正向:從有外間關係的這張表出發去被關聯的那種表中插資料
# 圖書表和出版社表:圖書表出版社版表
# 圖書.出版社.出版社名字
# 正向查詢直接透過 .欄位就能查到

# 反向: 從被關聯的那種表中去有外間關係的那張表中查資料
# 圖書表和出版社表:出版社表去查圖書表
# 出版社表.圖書表.圖書名字 
# 反向查詢需要按表名小寫 ,__set 查詢

3.6 正反向案例


import os
import random

from django.test import TestCase

# Create your tests here.
if __name__ == '__main__':
    os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'orm_project.settings')
    import django

    django.setup()
    from app01 import models

    # (1)查詢資料id為1的出版社,這是正向查詢
    # book_obj = models.Book.objects.filter(pk=1).first()
    # book_obj = models.Book.objects.get(pk=1)
    # print(book_obj)
    # print(book_obj.publish.name) # 上海出版社

    # (2)查詢資料逐漸id為2的作者
    # 透過第三張表.all可以獲取所有關聯的第三張表的資料
    # book_obj = models.Book.objects.get(pk=2)
    # print(book_obj)
    # print(book_obj.author.all())

    # (3)查詢作者的電話號碼
    # author_obj = models.Author.objects.get(pk=1)
    # print(author_obj)
    # print(author_obj.author_detail.phone) # 13023056160

    # 反向查詢
    # (4)查詢出版社為朝陽出版社出版的圖書
    # 出版社去圖書表裡查詢資料
    # publish_obj = models.Publish.objects.get(name="朝陽出版社")
    # print(publish_obj)
    # # 查詢出版的圖書
    # print(publish_obj.book_set.all())

    # (5)查詢作者serein寫過的書
    # 從作者表出發去圖書表查詢 --反向查詢
    # author_obj = models.Author.objects.get(name='serein')
    # print(author_obj)
    # # 反向查圖書
    # print(author_obj.book_set.all().values())

    # (6)查詢電話號 13023056160 的作者姓名
    # 作者詳情出發去作者表中查詢資料
    # author_detail_obj = models.AuthorDetail.objects.get(phone='13023056160')
    # print(author_detail_obj.author_set.all().first())

    # 小結
    # 正向查詢直接 .欄位 直接查
    # 反向查詢(反向就是有外間關係但是外間欄位不在我這表表裡,去有外間關係的那張表中查詢資料就是反向查詢)
    # 反向查詢資料 沒有外建的表明.有外建的表明_set.all() # 

3.7 跨表查詢案例

【五】跨表查詢案例
    # (1)查詢serein的手機號和作者的姓名
    # values() 獲取使用者資料的鍵和值
    # [1]正向查詢 : 從有外來鍵欄位的表出發去沒有外來鍵欄位的表中查詢
    # 先過濾篩選得到使用者的queryset物件.values("沒有外來鍵欄位的表名__表欄位","自己有的欄位名")
    # author_obj = models.Author.objects.filter(name="serein").values("author_detail__phone","name")
    # print(author_obj)
    # [2]反向查詢 : 從沒有外來鍵欄位的表向有外來鍵欄位的表查詢
    # 先過濾出符合名字的使用者物件資料.filter(有外來鍵欄位的表名__欄位名=篩選值).values("有外來鍵欄位的表名__欄位名","自己有的欄位名")
    # author_obj = models.AuthorDetail.objects.filter(author__name="serein").values("author__name","phone")
    # print(author_obj)

    # (2)查詢書籍ID為1的出版社名字和書的名字
    # 書籍表 --> 出版社查 : 正向
    # book_obj = models.Book.objects.filter(pk=1).values("publish__name","title")
    # print(book_obj) # <QuerySet [{'publish__name': '上海出版社', 'title': '西遊記'}]>
    # 出版社  --> 圖書查 : 反向
    # publish_obj = models.Publish.objects.filter(book__id=1).values("book__title","name")
    # print(publish_obj) # <QuerySet [{'book__title': '西遊記', 'name': '上海出版社'}]>

    # (3)查詢書籍ID為1的作者名字和作者電話
    # 書籍 ---> 作者表 : 正向
    # book_obj = models.Book.objects.filter(pk=1).values("author__name","author__author_detail__phone")
    # print(book_obj) # <QuerySet [{'author__name': 'serein', 'author__author_detail__phone': '15869699696'}]>
    # 作者 ---> 書籍 : 反向
    # author_obj = models.Author.objects.filter(book__id=1).values("book__title","name","author_detail__phone")
    # print(author_obj) # <QuerySet [{'book__title': '西遊記', 'name': 'serein', 'author_detail__phone': '15869699696'}]>

3.8 聚合函式

# 【五】聚合函式
    # 【1】聚合函式的位置
    from django.db.models import Sum, Max, Min, Count, Avg
    # 使用聚合函式的前提是先分組再聚合 , Django提供了一個方法可以完成分組 aggregate
    # 【2】計算所有書的平均價格
    result_avg = models.Book.objects.aggregate(Avg("price"))
    print(result_avg) # {'price__avg': 851.0}
    result_sum = models.Book.objects.aggregate(Sum("price"))
    print(result_sum) # {'price__sum': 2553}

    # 【3】可以直接連著使用聚合函式
    res = models.Book.objects.aggregate(Avg('price'), Max('price'), Min('price'), Sum('price'), Count('pk'))
    print(res) # {'price__avg': 851.0, 'price__max': 999, 'price__min': 666, 'price__sum': 2553, 'pk__count': 3}

3.9 分組查詢

# 【五】分組查詢
    # 【1】MySQL中的分組查詢 group_by ---> 嚴格模式
    # 【2】藉助第三方模組
    # (1)統計一本書的作者的個數
    from django.db.models import Count, Min

    # book_author_num = models.Book.objects.annotate(author_number=Count("author")).values('title','author_number')
    # print(book_author_num) # <QuerySet [{'title': '西遊記', 'author_number': 1}, {'title': '水滸傳', 'author_number': 2}, {'title': '白蛇傳', 'author_number': 0}]>
    # 如果不按照上面起別名,預設就是 欄位名__聚合函式名
    # book_author_num = models.Book.objects.annotate(Count("author")).values()
    # print(book_author_num) #  <QuerySet [{'id': 1, 'title': '西遊記', 'price': 999, 'publish_date': datetime.datetime(2024, 3, 5, 2, 28, 58, 607392, tzinfo=<UTC>), 'publish_id': 2, 'author__count': 1}

    # (2)統計價格最低的書
    # book_obj = models.Book.objects.annotate(Min("price")).values()
    # print(book_obj)
    # book_obj = models.Book.objects.annotate(book_min_price=Min("price")).values("title", "book_min_price")
    # print(book_obj)

    # (3)統計不止一個作者的書的名字
    book_obj = models.Book.objects.annotate(author_num=Count("author")).filter(author_num__gt=1).values()
    print(book_obj)

3.9 F查詢與Q查詢

   # F查詢和Q查詢,需匯入第三方模組
   from django.db.models import F,Q
    # 【1】F查詢
    # (1)賣出數量大於庫存數量的資料
    # 獲取指定欄位的資料:賣出數,庫存數
    # book_obj = models.Book.objects.filter(sale_num__gte=F('stock_num')).values()
    # print(book_obj)

    # (2)講所有圖書的價格提高100
    # book_obj = models.Book.objects.update(price=F('price') + 100)

    # (3)給你的書新增上爆款
    # book_obj= models.Book.objects.update(title = Concat(F("title"),Value('爆款')))

    # Q查詢
    # (1)查詢賣出數量大於80 庫存數小於70 的資料
    # filter 可以放兩個引數,但是兩個引數不能是同一個欄位

    # and的關係關係相容二者
    # book_obj = models.Book.objects.filter(sale_num__gt=80,stock_num__lt=70).values()
    # book_obj = models.Book.objects.filter(Q(sale_num__gt=80),Q(stock_num__lt=70)).values()
    # print(book_obj)

    # or 表示and的關係
    # book_obj = models.Book.objects.filter(Q(sale_num__gt=80) | Q(stock_num__lt=70)).values()
    # print(book_obj)

    # |表示或的關係
    # book_obj = models.Book.objects.filter(Q(sale_num__gt=80) or Q(stock_num__lt=70)).values()
    # print(book_obj)


4. django開啟事務

    # django 開始事務
    from django.db import transaction

try:
    # 開啟事務
    with transaction.atomic():
        # 在事務開始前建立儲存點
        save_id = transaction.savepoint()
        # 這部分程式碼會在事務中執行
        ...
        transaction.savepoint_commit(save_id)

except Exception as e:
    transaction.savepoint_rollback(save_id)

5. choices引數

# 建立作者表
class Author(models.Model):
    gender_choice = (
        (0, "male"),
        (1, "female"),
        (2, "other"),
    )
    # 作者名字
    name = models.CharField(max_length=32)
    # 作者年齡
    age = models.IntegerField()
    # 0 女 1 男 2 保密
    gender = models.IntegerField(choices=gender_choice, default=2)

    # 作者和作者詳情:一對一
    # 建立外來鍵欄位
    author_detail = models.ForeignKey("AuthorDetail", on_delete=models.CASCADE)

    class Meta():
        # 預設表名是 app01_book
        # book
        db_table = "Author"
        verbose_name_plural = "作者表"
        


author_obj = models.Author.object.filter(pk=1).values()
author_obj = models.Author.object.get(pk=1)

# 拿到的是數字
print(author_obj.gender)
# gender.choice,拿到的是所有資料的備選項
print(author_obj.gender_choice)
# 獲取到數字對應的文字
print(author_obj.get_gender_display())

相關文章