聚合查询
# 聚合查询
'''聚合查询通常情况下都是配合分组一起使用的
只要是跟数据库相关的模块
基本上都在django.db.models里面
如果上述没有那么应该在django.db里面'''
from django.db.models import Max,Min,Sum,Count,Avg # 模块的导入
# 1. 所有书的平均价格
# res = models.Book.objects.aggregate(Avg('price'))
# print(res)
# 2.上述方法一次性使用
res = models.Book.objects.aggregate(Max('price'), Min('price'), Sum('price'), Count('price'), Avg('price'))
print(res)
分组查询
# 分组查询 annotate
'''
MySQL分组查询都有哪些特点
分组之后默认只能获取到分组的依据 组内其它字段都无法直接获取了
严格模式
ONLY_FULL_GROUP_BY
'''
from django.db.models import Max, Min, Sum, Count, Avg
1.统计每一本书的作者个数
res = models.Book.objects.annotate() # models后面.什么就是按什么分组 这句话意思就是按照书分组
res = models.Book.objects.annotate(author_num=Count('authors')).values('title', 'author_num')
print(res)
2.统计每个出版社卖的最便宜的书的价格
res = models.Publish.objects.annotate(min_book=Min('book__price')).values('name', 'min_book', 'book__title')
print(res)
3.统计不止一个作者的图书
res = models.Book.objects.annotate(author__num=Count('authors')).filter(author__num__gt=1).values('title','author__num')
print(res)
'''
只要你orm语句得出的结果还是一个 queryset对象
那么它就能无限制的点 queryset对象封装的方法
'''
4.查询每个作者出的书的总价格
res = models.Author.objects.annotate(sum_price=Sum('book__price')).values('name', 'sum_price')
print(res)
'''
如果你想按照指定的字段进行分组
models.Book.objects.values('price').annotate()
你们的机器上
'''
F与Q查询
# F与Q查询
# 1. 查询卖出数大于库存数的书籍
# F查询
'''
能够直接帮你获取到表中某个字段对应的数据
'''
from django.db.models import F
# res = models.Book.objects.filter(maichu__gt=F('kucun'))
# print(res)
# 2.将所有的书籍的价格提升50块
# models.Book.objects.update(price=F('price')-50)
# 3.将所有的书的名称后面加上爆款两字
'''
在操作字符类型的数据的时候 F不能够直接做到字符串的拼接
'''
from django.db.models.functions import Concat
from django.db.models import Value
models.Book.objects.update(title=Concat(F('title'),Value('(爆款)')))
'''
models.Book.objects.update(title=F('title')+'(爆款)')) 这样会直接让你的所有名称变空白(django1.x版本会 2.x及以上不会)
'''
# Q查询
# 1. 查询卖出数大于100 或者 价格小于600 的书籍
res = models.Book.objects.filter(maichu__gt=950,price__lt=180).values('title')
'''
filter括号内 多个参数默认的是 and 关系
'''
from django.db.models import Q
res = models.Book.objects.filter(Q(maichu__gt=950) | Q(price__lt=180)).values('title') # 导入Q模块后 用Q()包裹起来 就可以用关系符了 | 或
res = models.Book.objects.filter(Q(maichu__gt=950) , Q(price__lt=180)).values('title') # , 还是and关系
res = models.Book.objects.filter(~Q(maichu__gt=950) | Q(price__lt=180)).values('title') # ~ not关系
print(res)
# Q的高阶用法 能够将查询条件的左边也变成可以改变的字符串的形式 不局限于字段
q = Q()
q.connector = 'or' # 默认关系是 and 可以这样修改成 or
q.children.append(('maichu__gt', 950))
q.children.append(('price__lt', 180))
res = models.Book.objects.filter(q)
print(res)
django中如何开启事务
事务
ACID 四个特性
原子性
不可分割的最小的单位
一致性
跟原子性是相辅相成的
隔离性
事务之间互相不干扰
持久性
事物一旦确认永久生效
事务的回滚
rollback
事务的确认
commit
'''
目前你只需要所掌握Django中如何简单的开启事务
orm中常用字段及参数
AutoField
主键字段 primary_key=True
CharField 对应数据库的是varchar
verbose_name 字段的注释
max_length 长度
IntegerField int
BigIntegerField bigint
DecimalField DecimalField(max_digits=8, decimal_places=2) # 小数 一共八位 小数点后面占两位
EmailField varchar(254)
DateField date
DateTimeField datetime
auto_now:每次修改数据的时候都会自动更新当前时间
auto_now_add:只在创建数据的时候记录创建的时间 后续不会自动修改了
BooleanField(Field) -布尔值类型
该字段传布尔值(False/True) 数据库里面存0/1
TextField - 文本类型
该字段可以用来存大段内容(文字、博客..)
后面的bbs作业 文章字段用的就是TextField
FileField
upload_to = '/data' 给该字段传一个文件对象, 会自动将文件保存到/data 目录下
然后将文件路径保存到数据库中
/data/a.txt
后面的bbs作业也会涉及
https://www.cnblogs.com/Dominic-Ji/p/9203990.html
'''django除了给你提供了很多字段类型外 还支持你自定义字段'''
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):
'''
这返回的才是真正的 数据类型及各种约束条件
:param connection:
:return:
'''
return 'char(%s)' % self.max_length
'''自定义字段的使用'''
myfiled = MyCharField(max_length=13, null=True)
数据库查询优化
only与defer
select_related 与 prefetch_related
'''
orm语句的特点:
惰性查询
如果你仅仅只是书写了orm语句 在后面根本没有用到该语句所查询出来的参数
那么orm会自动识别 直接不执行
'''
# only与defer
res = models.Book.objects.all()
print(res)
想要获取书籍表中所有书籍的名字
res = models.Book.objects.values('title')
print(res)
for t in res:
print(t.get('title'))
实现获取到的是一个数据对象 然后点title的方式能够拿到书名 并且没有其它字段
res = models.Book.objects.only('title')
print(res) # <QuerySet [<Book: Book object (1)>, <Book: Book object (2)>, <Book: Book object (3)>, <Book: Book object (4)>, <Book: Book object (5)>]>
for t in res:
print(t.title) # 点击only括号内的字段 不会走数据库
print(t.price) # 点击only括号内没有的字段 会重新走数据库查询
res = models.Book.objects.defer('title') # 对象除了没有title属性外其它都有
# print(res)
for t in res:
print(t.price)
'''
defer 和 only 刚好相反
defer括号内的不在查询出来的对象里面 该字段的查询需要重新走数据库
'''
choices参数(数据库字段设计常见)
'''
用户表
性别
学历
工作经验
是否结合
客户来源
...
针对某个可以列举完全的可能性字段, 我们应该如何存储
只要某个字段的可能性是可以列举完全的,那么一般情况下都会采用choices参数
'''
class User(models.Model):
username = models.CharField(max_length=32)
age = models.IntegerField()
# 性别
gender_choices = (
(1,'男'),
(2,'女'),
(3,'其它'),
)
gender = models.IntegerField(choices=gender_choices) # choices 固定写法
score_choices = (
('A','优秀'),
('B','良好'),
('C','及格'),
('D','不合格'),
)
score = models.CharField(choices=score_choices, null=True)
'''
该gender字段存的还是数字 但是如果存的数字在上面元组列举的范围之内
那么可以非常轻松的获取到数字对应的内容
1.gender字段存的数字不在上述元组列举的范围之内
2.如果在如何获取对应中文信息
'''
from app01 import models
models.User.objects.create(username='jason', age=19, gender=1)
models.User.objects.create(username='egon', age=85, gender=2)
models.User.objects.create(username='tank', age=40, gender=3)
models.User.objects.create(username='tony', age=49, gender=4)
# 取
user_obj = models.User.objects.filter(pk=1).first()
print(user_obj.gender)
# 要获取 choices参数的字段 固定写法
print(user_obj.get_gender_display())
user_obj = models.User.objects.filter(pk=4).first()
# 如果choices里面没有对应关系 那么就是该gender原本的值
print(user_obj.get_gender_display())
MTV与MVC模型
MTV: Django号称是MTV模型
M:models
T:templates
V:views;
MVC: 其实django本质也是MVC
M:models
V:views
C:controller(urls.py)
多对多三种创建方式
全自动:利用orm自动帮我们创建第三张表
class Book(models.Model):
name = models.CharField(max_length=32)
authors = models.ManyToManyField('Author', on_delete=models.CASCADE)
class Author(models.Model):
name = models.CharField(max_length=32)
'''
有点 : 代码不需要你写 非常的方便 还支持orm提供操作的第三张表的方法
不足之处: 第三张关系表的扩展性极差(没有办法额外添加字段)
'''
# 纯手动
class Book(models.Model):
name = models.CharField(max_length=32)
authors = models.ManyToManyField('Author', on_delete=models.CASCADE)
class Author(models.Model):
name = models.CharField(max_length=32)
class Book2Author(models.Model):
book_id = models.ForeignKey('Book', on_delete=models.CASCADE)
author_id = models.ForeignKey('Author', on_delete=models.CASCADE)
'''
优点: 第三张表完全取决于你自己进行额外的扩展
不足之处:需要写的代码较多, 不能够再使用orm提供的方法
'''
# 半自动
class Book(models.Model):
name = models.CharField(max_length=32)
authors = models.ManyToManyField('Author', on_delete=models.CASCADE,
through='Book2',
through_fields=('book', 'author'))
class Author(models.Model):
name = models.CharField(max_length=32)
class Book2(models.Model):
book = models.ForeignKey('Book', on_delete=models.CASCADE)
author = models.ForeignKey('Author', on_delete=models.CASCADE)
'''
through_fields字段先后顺序
判断本质:
通过第三张表查询对应的表 需要用到哪个字段就把哪个字段放前面
半自动:可以使用orm正反向查询 但是没法使用add,set,remove,clear这四个方法
'''
ajax
'''
异步提交
局部刷新
参考案例:github注册实时获取用户名发送给后端确认并动态展示校验结果(页面不刷新)
复习: input框实时监测事件 input事件
'''
# ajax基本语法
$.ajax({
url:'', # 朝后端哪个地址发送 不写就是默认朝当前地址发送 跟action三种书写方式一致
type:'get/post', # 提交方式 默认get 跟form表单提交方式一致
data:{'username':'jason','password':123}, #要发送的参数
success:function(args){
# 异步回调处理机制
}
})
'''
当你在利用ajax进行前后端交互的时候
后端无论返回什么 都只会被回调函数接收 而不再影响这个浏览器页面了
'''
# 扩展 参数
dataType:'JSON'
'''
当后端是以HttpResponse返回的json格式的数据
默认是不会自动反序列化的
1.自己手动 JSON.parse()
2.配置dataType参数
'''