目录
聚合查询
聚合函数
聚合函数一般用在分组之后, 没有分组默认整体就是一组
1.关键字 aggregate, 2.导入模块: from django.models import Max, Min, Sum, Avg, Count
小提示: 与数据库相关的功能, 基本都在django.db.models或django.db中
from django.db.models import Max, Min, Sum, Avg, Count
# 求所有书的最高价格
res = models.Book.objects.aggregate(max_price=Max('price'))
print(res) # {'max_price': Decimal('999.00')}
# 一起使用
res = models.Book.objects.aggregate(Min('price'), Sum('price'), Count('price'), Avg('price'))
print(res)
# {'price__min': Decimal('456.21'), 'price__sum': Decimal('3910.21'), 'price__count': 5, 'price__avg': 782.042}
分组查询
关键字: annotate, 与聚合函数组合使用
按某一个字段分组: models.Publish.objects.values('name')...
from django.db.models import Max, Min, Sum, Avg, Count
# 1. 统计每一本书的作者个数
res1 = models.Book.objects.annotate() # 分组
res2 = models.Book.objects.annotate(authors_amount=Count('authors')).values('authors_amount', 'title') # 分组+聚合函数
print(res1) # <QuerySet [<Book: 红楼梦>, <Book: 西游记>, <Book: jinpingmei>, <Book: 水浒传>, <Book: 安徒生童话>]>
print(res2) # <QuerySet [{'title': '红楼梦', 'authors_amount': 2}, ..., {'title': '安徒生童话', 'authors_amount': 0}]>
# 2. 统计出每个出版社卖的最便宜的书的价格
res = models.Publish.objects.annotate(min_price=Min('book__price')).values('name', 'min_price')
print(res) # <QuerySet [{'name': '北京出版社', 'min_price': Decimal('456.21')}, ...]>
# 严格模式, 只能拿分组依据所在的表中的数据和 聚合函数统计的数据,
# 取消严格模式: 更改MySQL的配置文件, 删除sql_mode=only_full_group_by
# 统计不止一个作者的图书
res = models.Book.objects.annotate(author_amount=Count('authors')).filter(author_amount__gt=1).values('title', 'author_amount')
print(res) # <QuerySet [{'title': '红楼梦', 'author_amount': 2}]>
# 查询各个作者出的书的总价格
res = models.Author.objects.annotate(sum_price=Sum('book__price')).values('name', 'sum_price')
print(res) # <QuerySet [..., {'name': 'oscar', 'sum_price': Decimal('1455.21')}, ...]>
F查询与Q查询
F查询
操作字符串需要导入Concat和Value
F能够获取表中字段所对应的值
from django.db.models import F
# 查询库存数大于卖出数的书籍
res = models.Book.objects.filter(stock__gt=F('sale')).values('title')
print(res) # <QuerySet [{'title': 'jinpingmei'}, {'title': '水浒传'}]>
# 将所有书的价格上涨100块
models.Book.objects.update(price=F('price') + 100)
# 将所有书的名称后面全部加上"爆款"后缀
from django.db.models.functions import Concat
from django.db.models import Value
models.Book.objects.update(title=Concat(F('title'), Value('爆款')))
Q查询
from django.db.models import Q
# 查询书籍名称是三国演义或者价格库存是是500的书籍
res = models.Book.objects.filter(Q(title='西游记') | Q(stock=3000))
print(res) # <QuerySet [<Book: 西游记>, <Book: 水浒传>]>
res = models.Book.objects.filter(~Q(title='西游记')) # ~表示取反
print(res) # <QuerySet [<Book: 红楼梦>, <Book: jinpingmei>, <Book: 水浒传>, <Book: 安徒生童话>]>
# Q对象高级用法:
q = Q()
q.connector = 'or' # 控制多个查询条件之间的关系为or
q.children.append(('title', '三国演义')) # 添加查询条件
q.children.append(('stock__gt', 1000))
res = models.Book.objects.filter(q)
print(res) # <QuerySet [<Book: 三国演义>, <Book: jinpingmei>, <Book: 水浒传>]>
res = models.Book.objects.filter(~q) # 可以使用~取反: WHERE NOT ((... or ...))
print(res) # <QuerySet [<Book: 三国演义>, <Book: jinpingmei>, <Book: 水浒传>]>
常用字段及参数
CharField, 对应MySQL中的varchar, 必须指定max_length参数
IntegerField, 对应MySQL中的int
BigIntegerField, 对应MySQL中的bigint
扫描二维码关注公众号,回复: 8048193 查看本文章EmaiField, 对应MySQL中的varchar(254)
DateField, DateTimeField(***)
auto_now与auto_now_add这两个参数的区别:
- auto_now: 每次修改数据时都会将当前修改时间更新上去, 实时更新
- auto_now_add: 在创建数据的时候, 会将当前时间自动记录, 之后不会自动修改
AutoField, 专门用来创建主键字段的
BooleanField(***), 布尔值, 该字段在存储的时候, 需要传入True或False, 会自动存成1/0
TextField, 专门用来存储大段文本
FileField, 专门用来存文件路径
- 给FileField字段传值的时候, 直接传文件对象,
- 会自动将文件对象保存到upload_to参数后面指定的文件路径中
- 最后将文件路径保存到数据库
- 例如: upload_to = "/mysql/data"
DecimalField:
- max_digits参数: 小数总长度
- decimal_palces, 小数位长度
db_index=True表示为此字段设置索引, 但索引不是越多越好, 索引能提高查询速度但会降低写速度
on_delete=models.CASCADE, 级联删除
自定义Char字段
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,) # 将db_type方法的返回结果当做字段类型
# customize_char = MyCharField(max_length=66, null=True)
图书管理系统
BMS(Book Manage System)首页搭建
'''
url(r'^show_book/', views.show_book, name='list'), # 图书展示页
def show_book(request):
book_queryset = models.Book.objects.all()
return render(request, 'list.html', locals()) # 将函数查询到的所有数据传到到HTML页面
{% extends 'home.html' %} # 继承home模板减少代码量
<a href="{% url 'add' %}">新增</a> # 数据展示表格上面设置新增数据按钮
<tbody>
{% for book_obj in book_queryset %}
<tr>
<td>{{ forloop.counter }}</td> # 优化序号展示格式, 从1开始
<td>{{ book_obj.publish_date|date:'Y-m-d' }}</td> # 优化日期展示格式
<td> # 优化书的作何展示格式
{% for author_boj in book_obj.authors.all %}
{% if forloop.last %}
{{ author_boj.name }}
{% else %}
{{ author_boj.name }}, # 不为最后一个作者时, 以逗号隔开
{% endif %}
{% endfor %}
</td>
</tr>
{% endfor %}
</tbody>
'''
新增图书页面
Forbidden (403), CSRF verification failed. Request aborted.
settings-->MIDDLEWARE-->注释掉'django.middleware.csrf.CsrfViewMiddleware'
'''
def add_book(request):
if request.method == 'POST':
...
author_list = request.POST.getlist('author')
book_obj = models.Book.objects.create(
...
)
book_obj.authors.add(*author_list) # 新增数据时外键的数据的处理方式
# 反向解析, 重定向到展示页
_url = reverse('list')
return redirect(_url)
# 将出版社和作者数据全部查询出来传到html页面供用户选择
publish_queryset = models.Publish.objects.all() # 无重复的出版社
author_queryset = models.Author.objects.all() # 无重复的作者
return render(request, 'add_book.html', locals())
{% block content %}
<h2 class="text-center">新增书籍</h2>
<form action="" method="post">
...
<p>
出版社:
<select name="publish" id="" class="form-control">
{% for publish_obj in publish_queryset %} # 在select标签中循环添加option选项标签
<option value="{{ publish_obj.pk }}">{{ publish_obj.name }}</option> # 展示给用户出版社名,传给后端对应出版社主键值
{% endfor %}
</select>
</p>
<p>
作者:
<select name="author" id="" multiple class="form-control">
{% for author_obj in author_queryset %}
<option value="{{ author_obj.pk }}">{{ author_obj.name }}</option>
{% endfor %}
</select>
</p>
...
</form>
{% endblock %}
'''
图书编辑页面
'''
url(r'^edit_book/(\d+)', views.edit_book, name='edit'), # 图书编辑页
<a href="{% url 'edit' book_obj.pk %}" class="btn btn-primary btn-sm">编辑</a>
def edit_book(request, edit_id):
"""
1. 先获取用户想要编辑的书籍对象,
2. 将该对象的数据展示给用户看,
3. 用户在原有数据的基础上编辑修改
4. 获取用户修改后的数据并同步到数据库
"""
edit_obj = models.Book.objects.filter(pk=edit_id).first() # POST请求和GET请求都要用到edit_obj, 故在最上端获取用户想要编辑的图书对象,
if request.method == 'POST':
...
models.Book.objects.filter(pk=edit_id).update(
title=title,
price=price,
publish_date=publish_date,
publish_id=publish_id,
)
edit_obj.authors.set(author_list) # 修改数据时外键的数据的处理方式
# 反向解析, 重定向到展示页
_url = reverse('list')
return redirect(_url)
publish_queryset = models.Publish.objects.all() # 获取所有的出版社, 无重复
author_queryset = models.Author.objects.all() # 获取所有的作者, 无重复
return render(request, 'edit_book.html', locals())
{% block content %}
...
<form action="" method="post">
...
<p>出版日期: <input type="date" name="publish_date" class="form-control"
value="{{ edit_obj.publish_date|date:'Y-m-d' }}"></p> # 设置默认展示原数据, 优化日期展示格式
<p>
出版社:
<select name="publish" id="" class="form-control">
{% for publish_obj in publish_queryset %} # 遍历每一个无重复的出版社对象
{% if edit_obj.pulish == publish_obj %} # 判断修改的书籍的出版社对象与遍历的出版社对象是否相等
<option value="{{ publish_obj.pk }}" selected>{{ publish_obj.name }}</option> # 相等则增加默认选中
{% else %}
<option value="{{ publish_obj.pk }}">{{ publish_obj.name }}</option> # 不相等则正常新增option标签
{% endif %}
{% endfor %}
</select>
</p>
<p>
作者:
<select name="author" id="" multiple class="form-control">
{% for author_obj in author_queryset %} # 遍历每一个无重复的作者对象
{% if author_obj in edit_obj.authors.all %} # 判断遍历的作者对象是否在修改的书籍的作者对象列表中
<option value="{{ author_obj.pk }}" selected>{{ author_obj.name }}</option> # 在则增加默认选中
{% else %}
<option value="{{ author_obj.pk }}">{{ author_obj.name }}</option> # 不再则正常新增option标签
{% endif %}
{% endfor %}
</select>
</p>
...
</form>
{% endblock %}
'''
删除图书页面
'''
RBAC:
基于角色的权限管理,
在web领域中url就是权限,
提前创建用户能访问的url列表
request.path获取用户想要访问的url路径, 与用户能访问的url列表进行比对实现权限管理
'''
orm中的事务操作
四大特性---ACID
原子性, 一致性, 隔离性, 持久性
数据库三大范式
- 第一范式就是无重复的域, 即数据库表的每一列都是不可分割的原子数据项,而不能是集合,数组,等非原子数据项
- 第二范式就是属性完全依赖于主键, 即数据库表中的每个实例或记录必须可以被唯一地区分
- 第三范式就是一个数据库表中不能包含已在其它表中已包含的非主关键字信息。
- 例如, 如果一个部门信息表中有部门编号和部门名称等信息,
- 那么在员工信息表中列出部门编号后就不能再将部门名称等信息再加入到员工信息表中
作用
保证数据的安全, 实例: 两个人之间进行转账
搜索引擎myisam和innodb的区别
回滚: rollback
django中如何开启事务
from django.db import transaction
with transaction.atomic():
# 在缩进的代码中书写数据库操作
# 在该缩进内的所有代码都是一个事务
pass