联表查询,聚合查询 ,分组查询,F查询与Q查询, Django开启事务,ORM中常用的字段及参数,数据库查询优化,choice参数,多对多三种创建方式
Ⅰ 联表查询(基于双下划线的跨表查询)
【一】查询 silence2的手机号和 作者的名字
- 正向:先查询到作者信息再 .value(需要查询信息的表__需要查询的字段,其他字段)
from django.test import TestCase
import os
if __name__ == '__main__':
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'six.settings')
import django
django.setup()
from user.models import Author, AuthorDetail, Book, Publish
import random
# 查询 silence2 的手机号和 作者的名字
author_obj = Author.objects.get(name="silence2")
print(author_obj.author_detail.phone, author_obj.name)
# 120 silence2
# 方案二 联表查询 : 将两张表合并到一起去查数据
# 如果是正向的另一张表 只需要在字段后面 加 __另一个字段名
author_obj = Author.objects.filter(name="silence2").values(
"name",
"author_detail__phone"
)
print(author_obj)
# <QuerySet [{'name': 'silence2', 'author_detail__phone': '120'}]>
【二】查询书籍id为4的出版社的名字和书籍的名字
from django.db import models
from django.test import TestCase
import os
if __name__ == '__main__':
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'six.settings')
import django
django.setup()
from user.models import Author, AuthorDetail, Book, Publish
import random
# 查询书籍id为1的出版社的名字和书籍的名字
book_name = Book.objects.get(pk=3)
print(book_name) # Book object (3)
print(book_name.title) # 西游记
publish_name = book_name.publish.name
print(publish_name) # 东京出版社
# 方案二 联表查询 : 将两张表合并到一起去查数据
book_name = Book.objects.filter(pk=3).values(
"title",
"publish__name"
)
print(book_name)
# <QuerySet [{'title': '西游记', 'publish__name': '东京出版社'}]>
【三】查询出版社id为4的 书籍名字和出版社名字
from django.db import models
from django.test import TestCase
import os
if __name__ == '__main__':
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'six.settings')
import django
django.setup()
from user.models import Author, AuthorDetail, Book, Publish
import random
# 查询出版社id为4的 书籍名字和出版社名字
publish_obj = Publish.objects.get(pk=4)
print(publish_obj.name)
# 东京出版社
book_name = publish_obj.book_set.all().values("title")
print(book_name)
# <QuerySet [{'title': '西游记'}, {'title': '第 5 本书'}]>
# 方式二 : 联表查询
book_name = Publish.objects.filter(pk=4).values(
"name",
"book__title"
)
print(book_name)
# <QuerySet [{'name': '东京出版社', 'book__title': '西游记'}, {'name': '东京出版社', 'book__title': '第 5 本书'}]>
【四】查询书籍iD为1的作者名字和手机号
from django.db import models
from django.test import TestCase
import os
if __name__ == '__main__':
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'six.settings')
import django
django.setup()
from user.models import Author, AuthorDetail, Book, Publish
import random
# 查询书籍iD为9的作者名字和手机号
book_obj = Book.objects.get(pk=9)
print(book_obj.title)
# 第 2 本书
author_info = book_obj.author.all().values("name", "author_detail__phone")
print(author_info)
# <QuerySet [{'name': 'silence2', 'author_detail__phone': '120'}]>
# 联表查
book_info = Book.objects.filter(id=9).values(
'title',
"author__name",
"author__author_detail__phone"
)
print(book_info)
# <QuerySet [{'title': '第 2 本书', 'author__name': 'silence2', 'author__author_detail__phone': '120'}]>
Ⅱ 聚合查询 aggregate
【一】引入
- 聚合查询通常情况下都是配合分组一起使用的
- 只要是和数据库相关的模块
- 基本上都在 django.db.models****里面
- 如果这里面没有 那大概率可能在 django.db 里面
【二】案例
- 导入聚合函数
from django.db.models import Max, Min, Sum, Count, Avg
【1】计算所有书的平均价格 avg
from django.db import models
from django.test import TestCase
import os
if __name__ == '__main__':
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'six.settings')
import django
django.setup()
from user.models import Author, AuthorDetail, Book, Publish
import random
# 引入聚合函数
from django.db.models import Max, Min, Sum, Count, Avg
# 使用聚合函数 关键字 aggregate
# 计算所有书的平均价格 avg
book_all = Book.objects.all()
print(sum([i.price for i in book_all]) / book_all.count())
# 166.5
# 使用聚合函数
avg_price = Book.objects.aggregate(Avg("price"))
print(avg_price)
# {'price__avg': 166.5}
# 定制聚合函数计算后的结果的字段名
avg_price = Book.objects.aggregate(price=Avg("price"))
print(avg_price)
# {'price': 166.5}
print(avg_price.get("price"))
# 166.5
# 运行报错是因为 导入的时候 price是varchar类型 换为float即可
【2】继续使用其他的聚合函数
from django.db import models
from django.test import TestCase
import os
if __name__ == '__main__':
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'six.settings')
import django
django.setup()
from user.models import Author, AuthorDetail, Book, Publish
import random
# 引入聚合函数
from django.db.models import Max, Min, Sum, Count, Avg
# (2)继续使用其他的聚合函数
book_info = Book.objects.aggregate(
avg_price=Avg("price"),
max_price=Max("price"),
min_price=Min("price"),
sum_price=Sum("price"),
count_price=Count("price"),
)
print(book_info)
# {'avg_price': 166.5, 'max_price': 300.0, 'min_price': 60.0, 'sum_price': 999.0, 'count_price': 6}
Ⅲ 分组查询 annotate
【一】统计每一本书的作者个数
from django.db import models
from django.test import TestCase
import os
if __name__ == '__main__':
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'six.settings')
import django
django.setup()
from user.models import Author, AuthorDetail, Book, Publish
import random
# 引入聚合函数
from django.db.models import Max, Min, Sum, Count, Avg
# 统计每一本书的作者个数
author_number = Book.objects.annotate(author_number=Count("author")).values(
"title",
# 作者的个数
"author_number"
)
print(author_number)
# <QuerySet [{'title': '西游记', 'author_number': 2}, {'title': '第 1 本书', 'author_number': 2}, {'title': '第 2 本书', 'author_number': 1}, {'title': '第 3 本书', 'author_number': 0}, {'title': '第 4 本书', 'author_number': 1}, {'title': '第 5 本书', 'author_number': 0}]>
【二】统计每一家出版社中书籍最贵的那本书
from django.db import models
from django.test import TestCase
import os
if __name__ == '__main__':
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'six.settings')
import django
django.setup()
from user.models import Author, AuthorDetail, Book, Publish
import random
# 引入聚合函数
from django.db.models import Max, Min, Sum, Count, Avg
# 统计每一家出版社中书籍最贵的那本书
book_info = Publish.objects.annotate(max_price=Max("book__price")).values(
"name",
"book__title",
"max_price"
)
print(book_info)
# <QuerySet [{'name': '东京出版社', 'book__title': '西游记', 'max_price': 99.0}, {'name': '河南出版社', 'book__title': '第 1 本书', 'max_price': 60.0}, {'name': '南京出版社', 'book__title': '第 2 本书', 'max_price': 120.0}, {'name': '河南出版社', 'book__title': '第 3 本书', 'max_price': 180.0}, {'name': '河南出版社', 'book__title': '第 4 本书', 'max_price': 240.0}, {'name': '东京出版社', 'book__title': '第 5 本书', 'max_price': 300.0}, {'name': '人民出版社', 'book__title': None, 'max_price': None}, {'name': '上海出版社', 'book__title': None, 'max_price': None}, {'name': '河北出版社', 'book__title': None, 'max_price': None}]>
【三】统计不止一个作者的图书信息 图书名字 数量
from django.db import models
from django.test import TestCase
import os
if __name__ == '__main__':
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'six.settings')
import django
django.setup()
from user.models import Author, AuthorDetail, Book, Publish
import random
# 引入聚合函数
from django.db.models import Max, Min, Sum, Count, Avg
# 【3】统计不止一个作者的图书信息 图书名字 数量
book_info = Book.objects.annotate(
author_number=Count("author")
).filter(
author_number__gt=1
).values(
"title",
"author_number"
)
print(book_info)
# <QuerySet [{'title': '西游记', 'author_number': 2}, {'title': '第 1 本书', 'author_number': 2}]>
【四】查询每个作者出的书的总价格
from django.db import models
from django.test import TestCase
import os
if __name__ == '__main__':
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'six.settings')
import django
django.setup()
from user.models import Author, AuthorDetail, Book, Publish
import random
# 引入聚合函数
from django.db.models import Max, Min, Sum, Count, Avg
# 查询每个作者出的书的总价格
book_info = Author.objects.annotate(
book_price_all=Sum("book__price")
).values(
"name",
"book_price_all"
)
print(book_info)
# <QuerySet [{'name': 'silence', 'book_price_all': 339.0}, {'name': 'silence1', 'book_price_all': 99.0}, {'name': 'silence2', 'book_price_all': 180.0}, {'name': 'silence3', 'book_price_all': None}, {'name': 'silence4', 'book_price_all': 60.0}, {'name': 'silence5', 'book_price_all': None}]>
Ⅳ F查询与Q查询
【一】语法引入
from django.db.models import F, Q
【二】F查询
- 能够帮助你直接获取到列表中某个字段对应的数据
注意: 在操作字符串类型的数据的时候, F不能够直接做到字符串的拼接
【1】book 的名字 给id=3书的名字前面加 爆款_
from django.db import models
from django.test import TestCase
import os
if __name__ == '__main__':
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'six.settings')
import django
django.setup()
from user.models import Author, AuthorDetail, Book, Publish
import random
# 给书的名字加爆款
book_obj = Book.objects.get(id=3)
book_obj.title = '爆款_' + book_obj.title
book_obj.save()
# Book.objects.update 对表中的所有数据进行更新
【2】F查询 帮助你查询到数据并且对数据进行更改
- 书的名称后边加上 爆款两个字
from django.db import models
from django.test import TestCase
import os
if __name__ == '__main__':
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'six.settings')
import django
django.setup()
from user.models import Author, AuthorDetail, Book, Publish
import random
from django.db.models.functions import Concat
from django.db.models import Value
from django.db.models import F, Q
Book.objects.filter(id=3).update(
title=Concat(F('title'), Value("_爆款"))
)
# 爆款_西游记_爆款
【3】查出卖出数大于库存数 的书籍
from django.db import models
from django.test import TestCase
import os
if __name__ == '__main__':
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'six.settings')
import django
django.setup()
from user.models import Author, AuthorDetail, Book, Publish
import random
from django.db.models.functions import Concat
from django.db.models import Value
from django.db.models import F, Q
# 正常 查出卖出数大于库存数 的书籍
book_all = Book.objects.all()
for book_obj in book_all:
if book_obj.sale > book_obj.stock:
print(book_obj.title)
# 借助 F 查询
book_info = Book.objects.filter(
# 两个不同的单独的字段不能同时出现在同一条语句中
# sale__gt=stock
# 使用F查询将制定字段的结果提取
sale__gt=F('stock')
).values("title", "sale", "stock")
print(book_info)
【三】Q查询
【1】所有书籍的价格上涨 500 块钱
from django.db import models
from django.test import TestCase
import os
if __name__ == '__main__':
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'six.settings')
import django
django.setup()
from user.models import Author, AuthorDetail, Book, Publish
import random
from django.db.models.functions import Concat
from django.db.models import Value
from django.db.models import F, Q
# 【2】所有书籍的价格上涨 500 块钱
Book.objects.update(
price=F('price') + 500
)
【2】查询卖出数大于 600 或者 库存数小于 900 的书
- 是且条件 必须符合二者的数据才能被拿出来
from django.db import models
from django.test import TestCase
import os
if __name__ == '__main__':
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'six.settings')
import django
django.setup()
from user.models import Author, AuthorDetail, Book, Publish
import random
from django.db.models.functions import Concat
from django.db.models import Value
from django.db.models import F, Q
# 查询卖出数大于 600 或者 库存数小于 900 的书
# 是且条件 必须符合二者的数据才能被拿出来
book_info = Book.objects.filter(
sale__gt=600,
stock__lt=900
).values("title", "sale", "stock")
print(book_info)
# 或条件 Q查询 同管道符 来链接两个或条件
book_info = Book.objects.filter(
Q(sale__gt=600) |
Q(stock__lt=900)
).values("title", "sale", "stock")
print(book_info)
# or 关键字作为连接符 会阉割条件
book_info = Book.objects.filter(
Q(sale__gt=600) or
Q(stock__lt=900)
).values("title", "sale", "stock")
print(book_info)
【3】另一种使用方式
from django.db import models
from django.test import TestCase
import os
if __name__ == '__main__':
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'six.settings')
import django
django.setup()
from user.models import Author, AuthorDetail, Book, Publish
import random
from django.db.models.functions import Concat
from django.db.models import Value
from django.db.models import F, Q
# 另一种使用方式
q = Q()
# 修改 Q查询的查询方式 and 二者均符合 or 任任一符合即可
q.connector = 'and'
q.connector = 'or'
# 给 你的 q 对象增加约束条件
q.children.append(('sale__gt', 600))
q.children.append(('stock__lt', 900))
book_info = Book.objects.filter(q).values(
"title", "sale", "stock")
print(book_info)
Ⅴ Django开启事务
【一】ACID特性
- 它代表了原子性(Atomicity)、一致性(Consistency)、隔离性(Isolation)和持久性(Durability)。
【1】原子性(Atomicity)
- 事务被视为一个不可分割的原子操作单元。
- 这意味着要么全部操作成功并永久保存,要么全部操作失败并回滚到事务开始前的状态,不存在部分成功或部分失败的情况。
【2】一致性(Consistency)
- 事务在执行前后,数据库都必须保持一致状态。
- 这意味着事务执行前后,数据库中的数据必须满足所有定义的完整性约束,例如列级别的约束、外键关系等。
【3】隔离性(Isolation)
- 事务之间应该相互隔离,每个事务的执行应该与其他事务的执行相互独立,互不干扰。
- 隔离性确保了多个事务可以并发执行,而不会产生不一致的结果。
【4】持久性(Durability)
- 一旦事务成功提交后,其所做的修改将永久保存在数据库中,即使发生系统故障或重启,数据也能够恢复到提交后的状态。
- 持久性通过将事务日志写入非易失性存储介质来实现,如硬盘驱动器或固态硬盘。
【二】事务名词
- 开启事务:Start Transaction
- 事务结束:End Transaction
- 提交事务:Commit Transaction
- 回滚事务:Rollback Transaction
【三】默认事务行为
- Django是支持事务操作的,它的默认事务行为是自动提交
- 具体表现形式为:每次数据库操作(比如调用save()方法)会立即被提交到数据库中。
- 但是如果你希望把连续的SQL操作包裹在一个事务里,就需要手动开启事务。
【四】开启事务
【1】全局开启事务
(1)配置
- 在Web应用中,常用的事务处理方式是将每次请求都包裹在一个事务中。
- 全局开启事务只需要将数据库的配置项ATOMIC_REQUESTS设置为True,如下所示:
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': "six",
"HOST": "127.0.0.1",
"PORT": 3306,
"USER": "root",
"PASSWORD": "123456",
"CHARSET": "utf8mb4",
# 配置这个参数以后每一次的请求进来 都会在视图上开启事务
# 如果你的请求顺利 正常响应 你的事务就会提交
# 如果遇到报错程序崩溃 ,事务就被取消了
"ATOMIC_REQUESTS": True,
}
}
(2)原理
- 每当有请求过来时,Django会在调用视图方法前开启一个事务。
- 如果完成了请求处理并正确返回了结果,Django就会提交该事务。
- 否则,Django会回滚该事务。
(3)局部取消事务
- 如果你全局开启了事务,你仍然可以使用non_atomic_requests装饰器让某些视图方法不受事务控制
# 想要取消局部的 事务验证
from django.db import transaction
# 在局部的函数上面加上装饰器 non_atomic_requests
@transaction.non_atomic_requests
def index(request):
# 如有多个数据库,让使用otherdb的视图不受事务控制
@transaction.non_atomic_requests(using='otherdb')
def my_other_view(request):
do_stuff_on_the_other_database()
- 虽然全局开启事务很简单,但Django并不推荐开启全局事务。
- 因为一旦将事务跟 HTTP 请求绑定到一起时,每一个请求都会开启事务,当访问量增长到一定的时候会造成很大的性能损耗。
- 在实际开发过程中,很多GET请求根本不涉及到事务操作,一个更好的方式是局部开启事务按需使用。
【2】局部开启事务
- Django项目中局部开启事务,可以借助于transaction.atomic方法。
- 使用它我们就可以创建一个具备原子性的代码块,一旦代码块正常运行完毕,所有的修改会被提交到数据库。
- 反之,如果有异常,更改会被回滚。
(1)装饰器使用
- atomic经常被当做装饰器来使用,如下所示:
# 第一步 引入 Django内置的事务模块
from django.db import transaction
# 第二步 在视图函数上面增加装饰器
@transaction.atomic
def index(request):
# 第一步 引入 Django内置的事务模块
from django.db import transaction
from django.views import View
class LoginView(View):
# 第二步 在视图函数上面增加装饰器
@transaction.atomic
def get(self, request):
(2)自定义事务点
- 在事务操作中,我们还会经常显式地设置保存点(savepoint)。
- 一旦发生异常或错误,我们使用savepoint_rollback方法让程序回滚到指定的保存点。
- 如果没有问题,就使用savepoint_commit方法提交事务。
def login(request):
# 开启事务
with transaction.atomic():
# (1)记录事务起点
sid = transaction.savepoint()
try:
# (2)执行你的代码
print("执行代码 ....")
# (3)确认没问题就会自动提交事务
except Exception as e:
# 进行事务的回滚
transaction.savepoint_rollback(sid)
Ⅵ ORM中常用的字段及参数
【1】AutoField
- int自增列,必须填入参数 primary_key=True。
- 当model中如果没有自增列,则自动会创建一个列名为id的列。
【2】IntegerField
- 一个整数类型
- 范围在 -2147483648 to 2147483647。(一般不用它来存手机号(位数也不够),直接用字符串存,)
【3】BigIntegerField(IntegerField)
- 长整型(有符号的)
- 范围在 -9223372036854775808 ~ 9223372036854775807
【4】CharField
- 字符类型,必须提供max_length参数, max_length表示字符长度。
- verbox_name 标识字段的注释
【5】EmailField(CharField)
- varchar(254)
【6】DecimalField(Field)
- max_digits,小数总长度
- decimal_places,小数位长度
【7】TextField(Field)
- 文本类型
- 支持大段内容,无字数限制
【8】FileField(Field)
- 字符串,路径保存在数据库,文件上传到指定目录
- 参数:
- upload_to = "/data"
- 给该字段传一个文件对象,会自动将文件保存到 /data 目录下,然后将文件路径保存到数据库中
- upload_to = "/data"
【9】BooleanField(Field)
- 字段为布尔值
- 数据库里面可以存 0/1
【10】DateField和DateTimeField
(1)DateField
- 日期字段
- 日期格式 YYYY-MM-DD,相当于Python中的datetime.date()实例。
(2)DateTimeField
- 日期时间字段
- 格式 YYYY-MM-DD HH:MM[:ss[.uuuuuu]][TZ],相当于Python中的datetime.datetime()实例。
(3)重要参数
[1]auto_now_add
- 配置auto_now_add=True
- 创建数据记录的时候会把当前时间添加到数据库。
[2]auto_now
- 配置上auto_now=True
- 每次更新数据记录的时候会更新该字段。
【11】ForeignKey
(1)介绍
- 外键类型在ORM中用来表示外键关联关系,一般把ForeignKey字段设置在 '一对多'中'多'的一方。
- ForeignKey可以和其他表做关联关系同时也可以和自身做关联关系。
(2)重要参数
[1]to
- 设置要关联的表
[2]to_field
- 设置要关联的表的字段
[5]on_delete
- 当删除关联表中的数据时,当前表与其关联的行的行为。
- on_delete=models.CASCADE
- 删除关联数据,与之关联也删除
【12】OneToOneField
(1)介绍
- 一对一字段。
- 通常一对一字段用来扩展已有字段。(通俗的说就是一个人的所有信息不是放在一张表里面的,简单的信息一张表,隐私的信息另一张表,之间通过一对一外键关联)
(2)重要参数
[1]to
- 设置要关联的表。
[2]to_field
- 设置要关联的字段。
[3]on_delete
- 当删除关联表中的数据时,当前表与其关联的行的行为。(参考上面的例子)
【13】字段参数
(1)null
- 用于表示某个字段可以为空。
(2)unique
- 如果设置为unique=True 则该字段在此表中必须是唯一的 。
(3)db_index
- 如果db_index=True 则代表着为此字段设置索引。
(4)default
- 为该字段设置默认值。
【14】字段之间对应关系
'AutoField': 'integer AUTO_INCREMENT',
'BigAutoField': 'bigint AUTO_INCREMENT',
'BinaryField': 'longblob',
'BooleanField': 'bool',
'CharField': 'varchar(%(max_length)s)',
'CommaSeparatedIntegerField': 'varchar(%(max_length)s)',
'DateField': 'date',
'DateTimeField': 'datetime',
'DecimalField': 'numeric(%(max_digits)s, %(decimal_places)s)',
'DurationField': 'bigint',
'FileField': 'varchar(%(max_length)s)',
'FilePathField': 'varchar(%(max_length)s)',
'FloatField': 'double precision',
'IntegerField': 'integer',
'BigIntegerField': 'bigint',
'IPAddressField': 'char(15)',
'GenericIPAddressField': 'char(39)',
'NullBooleanField': 'bool',
'OneToOneField': 'integer',
'PositiveIntegerField': 'integer UNSIGNED',
'PositiveSmallIntegerField': 'smallint UNSIGNED',
'SlugField': 'varchar(%(max_length)s)',
'SmallIntegerField': 'smallint',
'TextField': 'longtext',
'TimeField': 'time',
'UUIDField': 'char(32)',
【15】支持自定义字段
from django.db import models
# Create your models here.
#Django中没有对应的char类型字段,但是我们可以自己创建
class FixCharField(models.Field):
'''
自定义的char类型的字段类
'''
def __init__(self,max_length,*args,**kwargs):
self.max_length=max_length
super().__init__(max_length=max_length,*args,**kwargs)
def db_type(self, connection):
'''
限定生成的数据库表字段类型char,长度为max_length指定的值
:param connection:
:return:
'''
return 'char(%s)'%self.max_length
#应用上面自定义的char类型
class Class(models.Model):
id=models.AutoField(primary_key=True)
title=models.CharField(max_length=32)
class_name=FixCharField(max_length=16)
gender_choice=((1,'男'),(2,'女'),(3,'保密'))
gender=models.SmallIntegerField(choices=gender_choice,default=3)
Ⅶ 数据库查询优化
【1】ORM语句的特点
- 惰性查询:如果仅仅是书写了ORM语句,在后面没有使用到的话就不会对数据库进行查询,当我们需要用到查询的数据时,ORM会从数据库查询数据并返回数据
【2】only/defer
- 运行这句话的时候没有SQL语句执行
models.Book.objects.all()
- 这样运行的时候就会返回相应的数据
res = models.Book.objects.all()
print(res) # 只有需要用到真正的数据时,才会走数据库查询数据
(1)获取所有书籍表中书的名字
res = models.Book.objects.all()
for i in res:
print(res.get('title'))
(2)only
- 实现获取到一个数据对象,通过 .属性 拿到值并且无其他字段
res = models.Book.objects.only('title')
print(res)
for k in res:
print(k.title) # .only括号内的字段不会走数据库
print(k.price) # only中没有的字段,会重新走数据库并逐一从数据库中查找
(3)defer
- defer 和 only 相反
- defer 括号内放的字段不在查询的对象里面 ,查询该字段需要重新走数据库
- 而如果查询的是非括号内的字段 则不需要走数据库
res = models.Book.objects.defer('title')
print(res)
for s in res:
print(res.price)
(4)小结
- 在数据库查询中,only和defer是两个常用的方法
- 用于优化查询性能和减少数据传输量。
Ⅷ choice参数(数据库字段设计常见)
【1】引入
- 以一张信息表为例
性别
学历
工作经验
是否婚配
是否生子
客户来源
...
- 针对某个可以列举完全的可能性字段,我们应该如何存储?
- 只要某个字段的可能性是列举完全的,那么一般情况下都会采用choice参数
【2】数据准备
from random import choices
from django.db import models
# Create your models here.
class User(models.Model):
username = models.CharField(max_length=32)
age = models.IntegerField()
# 性别
gender_choices = (
(1, 'male'),
(2, 'female'),
(3, 'other'),
)
score = (
('1', 'male'),
('2', 'female'),
('3', 'other'),
)
# 保证字段类型跟列举出来的元祖第一个数据类型一致即可
gender = models.IntegerField(choices=gender_choices)
'''
该gender字段存的还是数字 但是如果存的数据在上面元祖列举的范围之内
那么可以非常轻松的获取到数字对应的真正内容
'''
【3】问题解决
(1)gender字段存的数字在上述元祖列举的范围内
from django.test import TestCase
# !/usr/bin/env python
import os
import sys
if __name__ == "__main__":
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "day08.settings")
import django
django.setup()
from app01 import models
models.User.objects.create(username="dream", age=18, gender=1)
models.User.objects.create(username="mengmeng", age=28, gender=2)
models.User.objects.create(username="chimeng", age=39, gender=3)
# 存的时候,没有列举出来的数字也能被存进去
models.User.objects.create(username="hope", age=44, gender=4)
- 没有报错,且第四条已经插入到数据库中
(2)gender字段存的数字在上述元祖列举的范围内并获取
# 取 - 如果有对应关系
user_obj = models.User.objects.filter(pk=1).first()
print(user_obj.gender) # 1
# 只要是 choice字段的注释,如果想要获取到注释的信息,固定写法 get_字段名_display()
print(user_obj.get_gender_display()) # male
(3)gender字段存的数字不在上述元祖列举的范围内
# 取 - 如果没有对应关系
user_obj = models.User.objects.filter(pk=4).first()
# 如果没有对应关系 字段是什么 返回的就是什么
print(user_obj.get_gender_display()) # 4
Ⅸ 多对多三种创建方式
【1】全自动
- 利用ORM自动帮我们创建第三张表关系
class Book(models.Model):
name = models.CharField(max_length=32)
# 全自动
authors = models.ManyToManyField(to='Author')
class Author(models.Model):
name = models.CharField(max_length=32)
优点
代码不需要自己写,非常方便,还支持ORM提供操作第三张表的方法
缺点
第三张关系表的扩展性极差(没办法添加额外字段)
【2】纯手动(不建议使用)
class Book(models.Model):
name = models.CharField(max_length=32)
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')
- 优点
- 第三张表完全取决于自己进行额外的拓展
- 缺点
- 需要写代码较多
- 不能使用ORM提供的相关方法
【3】半自动
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')
- 这样虽然可以使用ORM的正反向查询,但是没法使用add,set,remove,clear这四个方法
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY