django6/正向查询进阶操作/聚合、分组、F、Q查询/ORM优化/模板层常见字段参数/多对多三种创建方式/
正向查询进阶操作
聚合查询
分组查询
F与Q查询
ORM查询优化
模型层常见字段
ORM常见字段参数
多对多三种创建方式
正向查询进阶操作
1.查询主键为1的书籍对应的出版社名称以及书名
res = models.Publish.object.filter(book_pk=1).values('name','book_title')
#print(res)
2.查询主键为3的书籍对应的作者姓名及书名
res = models.Author.objects.filter(book_pk=1).values('name','book_title')
#print(res)
3.查询jason的作者的电话号码和地址
res = models.AuthorDetail.objects.filter(author_name='jason').values('phone','addr')
#print(res)
4.查询南方出版社出版的书籍名称和价格
res = models.Book.object.fileter(publish_name = '南方出版社').values('title','price')
#print(res)
5.查询jason写过的书的名称和日期
res = models.Book.objects.filter(authors_name='jason').values('title','publish_time')
#print(res)
6.查询电话是110的作者姓名和年龄
res = models.Author.objects.filter(author_detail_phone=110).values('name','age')
#print(res)
7.查询主键为1的书籍对应的作者电话号码
res =models.AuthorDetail.objects.filter(author_book_pk = 1).values('phone')
#print(res)
res = models.Author.objects.filter(book_pk=1).values('author_detail_phone')
#print(res)
聚合查询
聚合函数
函数 | |
---|---|
max | 最大值 |
min | 最小值 |
sum | 计算和 |
avg | 平均值 |
count | 统计 |
聚合查询
from django.db.models import Max,Min,Sum,Avg,Count
#没有分组之前如何单纯的时候聚合函数,需要关键字aggregate
res = models.Book.objects.aggregate(Max('price'),Min('price'),Sum('price'),Avg('price'),Count('pk'))
print(res)
分组查询
分组有一个特性,默认只能够直接获取分组的字段,其它字段需要使用方法
我们也可以忽略掉该特性,将sql_mode中only_full_group_by配置移除即可
1.统计每一本书的作者个数
res = models.Book.objects.annotate(author_num=Count('authors_pk')).values('title','author_num')
print(res)
res1 = models.Book.objects.values('publish_id').annotate(book_num=Count('pk')).values('publish_id','book_num')
print(res1)
1.按照整条数据分组
models.Book.objects.annotate() 按照一条条书籍记录分组
2.按照表中的某个字段分组()
models.Book.objects.values('title').annotate() 按照annotate之前values括号中指定的字段分组
2.统计每个出版社卖的最便宜的书的价格
res = models.Publish.object.annotate(min_price=Min('book_price')).values('name','min_price')
#print(res)
3.统计不止一个作者的图书
filter 在annotate前面则是where 在annotate后面则是having
res = models.Book.objects.annotate(author_num=Count('authors_pk')).filter(author_num_gt=1).values('title','author_num')
#print(res)
4.查询各个作者出的书的总价格
res = models.Author.objects.annotate(book_sum_price = Sum('book_price')).values('name','book_sum_price')
print(res)
F与Q查询
F查询:查询条件不是自定义的而是来自于表中其它字段
from django.db.models import F
#1.查询库存数大于卖出数的书籍
res = models.Book.objects.filter(storage_num_gt=F('sale_num'))
#print(res)
2.将所有书籍的价格上涨1000块
models.Book.objects.update(price=F('price') + 1000)
3.将所有书籍名称加上爆款后缀
models.Book.objects.filter(pk=5).update(title=F('title')+'爆款')#针对字符串数据无法直接拼接
#正确写法
from django.db.models.functions import Concat
from django.db.models import Value
ret3 = models.Book.objects.filter(pk=5).update(titile=Concat(F('title'),Value('爆款')))
ORM查询优化
django orm 默认都是惰性查询
当orm的语句在后续的代码中真正需要使用的时候才会执行
django orm 自带limit分页
减轻数据库端以及服务端的压力
1.ORM查询优化之only
only会将括号内填写的字段封装成一个个数据对象,对象在点击的时候不会再走数据库查询
但是对象也可以点击括号内没有的字段,只不过每次都会走数据库查询
res = models.Book.objects.only('title','price')
for obj in res:
print(obj.title)
print(obj.price)
print(obj.publish_time)
2.ORM查询优化之defer
defer与only相反
数据对象点击括号内出现的字段,每次都会走数据库查询
数据对象点击括号内的没有的字典,不会走数据库查询
res = models.Book.objects.defer('title','price')
for obj in res:
#print(obj.title)
#print(obj.price)
print(obj.publiesh_time)
3.ORM查询优化之select_related
select_related括号内只能接受外键字段(一对多,一对一)自动连表,得出的数据对象在点击表中数据的时候不会再走数据库查询
res = models.Book.object.all()
for obj in res:
print(obj.publish.name) #频繁走数据库查询
4.ORM查询优化之prefetch_related
prefetch_related底层其实是子查询,将查询之后的结果也一次性封装到数据对象中,用户在使用的时候感觉不出来
res = models.Book.objects.prefetch_related('publish')
for obj in res:
print(obj.publish.name)
事务操作
from django.db import transaction
try:
with transaction import transaction
pass #多条ORM语句
except Exception as e:
print(e)
模型层 ORM常见字段和重要参数
ORM字段和mysql里字段的对应关系。
ORM | MYSQL |
---|---|
AutoField() | int auto_increment |
CharField() | 必须提供max_length参数,对应的数据库中是varchar类型 |
IntergerField() | int |
DecimalField() | decimal |
DateField() | date |
DateTimeField() | datetime |
BigIntergerField() | bigint |
BooleanField() | 传布尔值 存0和1 |
TextField() | 存储大段文本 |
FileField() | 传文件自动保存到指定位置并存文件路径 |
EmailField() | 本质还是varchar类型 |
自定义字段类型
class MyCharField(models.Field):
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):
return 'char(%s)' % self.max_length
重要参数
参数 | 说明 |
---|---|
primary_key | 主键 |
max_length | 最大字符长度 |
verbose_name | 对应的名字 |
null | 是否可以为空 |
default | 默认值 |
max_digits | 数字允许的最大位数 |
decimal_places | 小数的最大位数 |
unique | 字段的值唯一 |
db_index | 是否为字段设置索引 |
auto_now | 更新修改数据时间 |
auto_now_add | 数据添加的时间 |
to | 设置关联的表 |
to_field | 设置关联的字段 |
db_constraint | 是否创建外键约束,默认True |
choice参数:用于可以被列举完全的数据,eg:性别,学历,工作经验,工作状态。
class User(models.Model):
username = models.CharField(max_length=32)
password = models.IntegerField()
gender_choice = (
(1,'男性'),
(2,'女性'),
(3,'变性')
)
gender = models.IntegerField(choices=gender_choice)
user_obj.get_gender_display() # 有对应关系就拿 没有还是本身
ps:外键字段中可能还会遇到related_name参数,外键字段中使用related_name参数可以修改正向查询的字段名,之后就可以使用修改后的字段名,类似于起别名。
事务操作
MySQL事务:四大特性(ACID),原子性,一致性,独立性,持久性。一个事务是一个整体,要么同时成功要么同时失败。
mysql开启事务:start transcation;
mysql回滚事务:rollback;
mysql停止事务:commit;
django的事务操作:
from django.db import transaction
with transaction.atomic():
pass # 操作
# with一结束事务就结束了,自动提交和回滚
ORM执行原生SQL
方式1
from django.db import connection, connections
cursor = connection.cursor()
cursor = connections['default'].cursor()
cursor.execute("""SELECT * from auth_user where id = %s""", [1])
cursor.fetchone()
方式2
models.UserInfo.objects.extra(
select={'newid':'select count(1) from app01_usertype where id>%s'},
select_params=[1,],
where = ['age>%s'],
params=[18,],
order_by=['-age'],
tables=['app01_usertype']
)
多对多三种创建方式
全自动(常见)
优点:自动创建第三张表
缺点: 第三张表扩展性差
authors = models.ManyToManyField(to='Author')
全手动(使用频率最低)
优点:在于第三张表完全自定义扩展性高,
缺点:在于无法使用外键方法和正反向以及多对多四个方法
3.半自动创建
class Book(models.Model):
title = models.CharField(max_length=32)
class Author(models.Model):
name = models.CharField(max_length=32)
class Book2Author(models.Model):
book_id = models.ForeignKey(to='Book')
author_id = models.ForeignKey(to='Author')
半自动(常见)
优点:正反向还可以使用,并且第三张表扩展性强
唯一的缺陷是不能用add\set\remove\clear四个方法
class Book(models.Model):
title = models.CharField(max_length=32)
authors = models.ManyToManyField(
to='Author',
through='Book2Author', # 指定表
through_fields=('book','author') # 指定字段
)
class Author(models.Model):
name = models.CharField(max_length=32)
'''多对多建在任意一方都可以 如果建在作者表 字段顺序互换即可'''
books = models.ManyToManyField(
to='Author',
through='Book2Author', # 指定表
through_fields=('author','book') # 指定字段
)
class Book2Author(models.Model):
book = models.ForeignKey(to='Book')
author = models.ForeignKey(to='Author')
........