BV与CBV:
视图函数既可以是def也可以是class
当我们的视图函数是类的时候路由应该这样写url(r'^login/',views.MyLogin.as_view())
CBV特点:能够直接根据请求方式的不同直接匹配到对应的方法执行,我们通过url中的as_view()来查看CBV源码。
通过对CBV源码的分析我们发现其实内部原理就是通过一系列的函数调用最终通过反射机制完成对类内函数的一个匹配。
有内部函数as_view->view->dispatch(内部有一个字符集,规定了8个方法)当方法在8个之中的时候->通过反射找到类的对应方法
模板层:
模板语法的传值:{{变量}} {%逻辑%}
模板语法可以传递的后端python数据类型:
n = 123 int
f = 11.11 float
s = '我也想奔现' str
b = True bool
l = ['小红','姗姗','花花','茹茹'] list
t = (111,222,333,444) tuple
d = {'username':'jason','age':18,'info':'这个人有点意思'} dict
se = {'晶晶','洋洋','嘤嘤'} set
传递函数名会自动加括号调用,但是不支持给函数传额外的参数
传递类名的时候会自动实例化
传递对象时相当于打印对象也就是触发__str__方法
在取值的时候是固定用法“.” 可以与索引混用
过滤器:类似于一些模板语语法的内置方法,我们在这里学习一部分常用的方法。
基本语法 {{数据|过滤器:参数}}
统计长度 {{数据|length}}
默认值 {{数据|default:""}} 能拿到值就输出值 拿不到返回默认值
文件大小 {{file_size|filesizeformat}}
日期格式化 {{ time|date:'Y-m-d H:i:s' }}
切片操作(支持步长):{{ l|slice:'0:4:2' }}
切取字符(包含三个点) {{ 文本|truncatechars:9 }}
切取单词(不包含三个点 按照空格切) {{ 文本|truncatewords:9 }}
移除特定的字符 {{ 数据|cut:' ' }}
拼接操作 {{ 数据|join:'字符' }}
拼接操作(加法) {{ int|add:10 }}
拼接操作(加法) {{ str|add:str }}
在后端书写HTML代码的时候我们传输到前端是没有进行编译的,所以需要我们自行添加设置转义
转义:{{数据|safe}}
后端写法:
from django.utils.safestring import mark_safe
res = mark_safe('<h1>新新</h1>')
标签:
python中的for循环
{%for i in range%} {% endfor %}
python中的if判断
{% if 条件 %} {%else%} {% endif %}
with起别名
{% with d.hobby.3.info as nb %} {% endwith %}
除了django为我们提供的过滤器之外也允许我们自定义过滤器和标签。
首先先三步走:1.在应用下创建一个templateags文件夹
2.在该文件夹下创建任意名称py文件
3.在py文件中书写 from django import template
register = template.Library()
# 自定义过滤器 过滤器只能有两个参数
@register.filter(name='baby')
def my_sum(v1, v2):
return v1 + v2
# 使用
{% load mytag %}
<p>{{ n|baby:666 }}</p>
# 自定义标签(参数可以有多个) 类似于自定义函数
@register.simple_tag(name='plus')
def index(a,b,c,d):
return '%s-%s-%s-%s'%(a,b,c,d)
# 使用
标签多个参数彼此之间空格隔开
<p>{% plus 'jason' 123 123 123 %}</p>
自定义inclusion_tag
内部原理
先定义一个方法
在页面上调用该方法 并且可以传值
该方法会生成一些数据然后传递给一个html页面
之后将渲染好的结果放到调用的位置
@register.inclusion_tag('left_menu.html')
def left(n):
data = ['第{}项'.format(i) for i in range(n)]
# 第一种
# return {'data':data} # 将data传递给left_menu.html
# 第二种
return locals() # 将data传递给left_menu.html
在我们需要动态的传参去渲染一个页面同时这个页面被多个页面同时使用,这时应该设置为inclusion_tag形式
模板继承:当我们设计的网页有一些差不多的布局内容时,我们可以用模板的继承来完成重复动作。
自己先选好一个你要想继承的模版页面
{% extends 'home.html' %}
# 继承了之后子页面跟模版页面长的是一模一样的 你需要在模版页面上提前划定可以被修改的区域
{% block content %}
模版内容
{% endblock %}
# 子页面就可以声明想要修改哪块划定了的区域
{% block content %}
子页面内容
{% endblock %}
模板的导入:
将页面的某一个局部作为模板,哪里需要就在哪里导入
{% include 'wasai.html' %}
模型层(models):
补充字段属性(DateFiled auto_now:每次数据修改都会更新时间 auto_now_add:只保存当前创建时间)
ps:当我们只需要测试某一个py文件的时候不必与前端进行交互,而是直接写一个测试脚本即可。
测试脚本:所有代码都需要等待环境准备完毕之后才能书写
import os
if __name__ == "__main__":
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "项目名.settings")
import django
django.setup()
ps:可以用pk代替主键使用,方便我们去查找主键是什么。
必知必会13条:
1.all() 查询所有数据
2.filter() 条件筛选
3.get() 条件筛选 不推荐使用因为常常报错
4.first() 拿到返回的数据对象列表中的第一个对象
5.last() 与上一个功能类似但是是最后一个
6.values()获取数据对象的指定字段 返回结果像是列表套字典
7.values_list() 获取数据对象的指定字段 返回结果像是列表套元组
ps:我们可以通过.query方法(queryset对象的方法)来查看sql语句,这个方法具有一定的局限性,所以我们有了第二种方式写日志。
以下代码放入settings配置文件中:
LOGGING = {
'version': 1,
'disable_existing_loggers': False,
'handlers': {
'console':{
'level':'DEBUG',
'class':'logging.StreamHandler',
},
},
'loggers': {
'django.db.backends': {
'handlers': ['console'],
'propagate': True,
'level':'DEBUG',
},
}
}
8.distance()去重 包括主键的话没法做到你想要的样式,别问我怎么知道的
9.oder_by() 排序默认是升序排序 可以使用字段带符号来完成降序排序
10.reverse()反转前提是已经进行过排序了
11.count() 计数
12.exclude() 排除在外
13.exists()判存
双下划线查询:
大于 字段__gt = 条件
小于 字段__lt = 条件
大于等于 字段__gte = 条件
小于等于 字段__lte = 条件
条件查询 字段__in = [条件1,条件2,...]
包含查询 字段__range = [条件1,条件2] 包含首尾
模糊查询 字段__contains = "条件" 区分大小写
模糊查询 字段__icontains = "条件" 不区分大小写
开头 字段__startwith = "条件"
结尾 字段__endwith = "条件"
时间查询 字段__month(可以替换其他时间) = "条件" 只查询月份满足条件的数据
一对多外键增删改查:
在增加和修改数据的时候,外键参数既可以是明确的键值也可以是一个对象,这取决于你的赋值给实际的还是虚拟的字段
删除的时候是级联删除
多对多外键增删改查:他的增删改查就是在操作第三张表
先获取一个对象,然后调用对象下的外建名的方法
book_obj = models.Book.objects.filter(pk=2).first()
book_obj.autor_id.add(1,3) add给第三张关系表添加数据 remove删除数据
括号内除了可以放数字之外亦可以放一个或多个对象。
修改的时候调用set方法,set方法括号内必须是可迭代对象
clear方法清空 不传任何参数
正反向的概念:外键字段的位置决定了正向反向。由外键字段所在的一端发起查询就是正向,反之则是反向。
多表查询:
子查询(基于对象的跨表查询):
正向查询按字段
book_obj = models.Book.objects.filter(pk = 2).first()
res = book_obj.publish_id.name
print(res)
反向查询按表名小写
publish_obj = models.Publish.objects.filter(name="东方出版社").first()
res = publish_obj.book_set.all()
print(res)
联表查询(基于双下划线的跨表查询):
通过双下划线加上小写的表名能够跳转到指定表的位置
你只要掌握了正反向的概念
以及双下划线
那么你就可以无限制的跨表
聚合查询:也就是max、min等聚合函数的查询,通常与分组一起使用,只要是和数据库相关的模块基本上都在django.db.models
或者在django.db中,使用aggregate方法
from django.db.models import Max,Min,Sum,Count,Avg
res = models.Book.objects.aggregate(Avg("price"),Max("price"),Sum("price"))
print(res)
分组查询:分组之后默认只能获取到分组的依据 组内其他字段都无法直接获取了,必须取消严格模式ONLY_FULL_GROUP_BY
使用annotate方法
res = models.Autor.objects.annotate(pri_sum = Sum("book__price")).values("name","pri_sum")
print(res)
也可以按照指定字段进行分组,只需要加上.value()
F查询与Q查询:
F查询:
当我们的筛选条件是表中其他字段的数据的时候,我们无法直接赋值,所以我们需要F查询。F查询会寻找指定的字段的数据,会做一个类似于for循环的操作会一个一个拿出数据。
models.Book.objects.update(price = F("price")+500)
当F查询进行字符操作的时候不能直接拼接,需要其他模块
from django.db.models import F,Value
from django.db.models.functions import Concat
models.Book.objects.update(title = Concat(F("title"),Value("爆款")))
Q查询:Q查询为我们提供了and or not等方法。
from django.db.models import Q
res= models.Book.objects.filter(Q(pk__gt=2),Q(price__gt = 500)) and
res = models.Book.objects.filter(Q(pk= 2)|Q(price__lt = 800)) or
res = models.Book.objects.filter(~Q(pk = 2)) not
print(res)
Q的高阶用法 能够将查询条件的左边也变成字符串的形式
q = Q()
q.connector = 'or' 修改关系
q.children.append(('maichu__gt',100))
q.children.append(('price__lt',600))
res = models.Book.objects.filter(q) # 默认还是and关系
print(res)
django中如何开启事务:
ACID:原子性 要么全部完成,要么全部不完成
一致性 必须和数据库中规定的类型一致
隔离性 多个事务同时操作互不影响
持久性 一旦完成永久保存
回滚 rollback
确认 commit
from django.db import transaction
try:
with transaction.atomic():
# sql1
# sql2
...
# 在with代码快内书写的所有orm操作都是属于同一个事务
except Exception as e:
print(e)
print('执行其他操作')
orm中常用字段:
AutoField
主键字段 primary_key=True
CharField varchar
verbose_name 字段的注释
max_length 长度
IntegerField int
BigIntegerField bigint
DecimalField
max_digits=8
decimal_places=2
EmailFiled varchar(254)
DateField date
DateTimeField datetime
auto_now:每次修改数据的时候都会自动更新当前时间
auto_now_add:只在创建数据的时候记录创建时间后续不会自动修改了
BooleanField(Field) - 布尔值类型
该字段传布尔值(False/True) 数据库里面存0/1
TextField(Field) - 文本类型
该字段可以用来存大段内容(文章、博客...) 没有字数限制
后面的bbs作业 文章字段用的就是TextField
FileField(Field) - 字符类型
upload_to = "/data"
给该字段传一个文件对象,会自动将文件保存到/data目录下然后将文件路径保存到数据库中
数据库查询优化:
orm语句是惰性查询的,当你没有发生调用或者使用到仅是书写的时候是不会执行的。
only与defer
only获取数据对象,并且对象的属性只有指定字段,当你要获取其他字段的时候会重新到数据库中寻找
defer与only刚好相反defer括号内放的字段不在查询出来的对象里面 查询该字段需要重新走数据而如果查询的是非括号内的字段 则不需要走数据库了。
select_related与prefetch_related 跟跨表操作有关
select_related内部直接先将book与publish连起来 然后一次性将大表里面的所有数据
全部封装给查询出来的对象
这个时候对象无论是点击book表的数据还是publish的数据都无需再走数据库查询了
select_related括号内只能放外键字段 一对多 一对一
多对多不行
prefetch_related该方法内部其实就是子查询
将子查询查询出来的所有结果也给你封装到对象中
给你的感觉好像也是一次性搞定的
choice选择字段:
当你的字段中的数据可能性是可以被列举完毕的,我们推荐你使用choice来设置,这样在一定程度上来说加快了数据库搜索的速度(因为是数字么而不是复杂的字符匹配)
在这里我们举一个例子来介绍choice 比如我们的数据库涉及到性别的字段 那么男 女 其他就可以用数字替代
gender_choice= ((1,“男”),(2,“女”),(3,“其他”))
gender = models.IntegerFiled(choice = gender_choice) 用什么形式的数据来代替就声明为设么格式
我们在取得时候如果输入了超出元组范围的数字,那么我们得到的就是一个数字,如果我们输入了范围内的也会得到数字,那是我们可以根据这个数字来取相应数据
固定写法get_字段名_display()
user_obj = models.User.object.filter(pk=5).first()
print(user_obj.get_gender_display())
MTV与MVC模型:
django对外宣称他们是一种新兴的也就是MTV模型但实际上他还是一种MVC模型
MTV:
M:models
T:templates
V:views
MVC:
M:models
V:views
C:controller
还有一种MVVM模型例如vue框架,我们之后在介绍
再来介绍一下多对多创建方式:
全自动:
利用orm提供的manytomany方法关联两个表,第三张表会为你自动创建,不需要手动,但是缺点就是我们对第三张表的控制比较差,可扩展性差。
半自动:
仍然由我们来创建第三张表,但是要声明一下
class Book(models.Model):
name = models.CharFiled(max_length = 32)
authors = models.MangyToManyFiled(to = "Author",though = "Book2Author",though_filed = ("book"."author"))
class Book2Author(models.Model):
book = models.ForeignKey(to='Book')
author = models.ForeignKey(to='Author')
through_fields字段先后顺序:
判断的本质:通过第三张表查询对应的表 需要用到哪个字段就把哪个字段放前面
你也可以简化判断当前表是谁 就把对应的关联字段放前面
可以使用orm的正反向查询 但是没法使用add,set,remove,clear这四个方法
纯手动:
我们自己创建第三张表,这样我们对其的控制就大大增加了,但是代码太多,而且不能在使用orm提供的方法操作就很麻烦了