Django 的中间件是一个轻量级、底层的插件系统,可以介入请求和响应处理过程,修改 Django 的输入或输出。
在子应用中定义,对全局视图函数有影响。
在子应用中新建一个 middleware.py 文件
def my_middleware(get_response):
print('init 被调用')
def middleware(request):
print('before request 被调用')
response = get_response(request)
print('after response 被调用')
return response
return middleware
在 settings.py 文件中添加注册中间件
MIDDLEWARE = [
.....................
# 添加中间件
'users.middleware.my_middleware', ]
MIDDLEWARE = [
'classview.middleware.my_middleware1',
'classview.middleware.my_middleware2',]
def my_middleware1(get_response):
print('init 1被调用')
def middleware1(request):
print('before request 1被调用')
response = get_response(request)
print('after response 1被调用')
return response
return middleware1
def my_middleware2(get_response):
print("init 2被调用")
def middleware2(request):
print("before request 2 被调用")
response=get_response(request)
print("after response 2被调用")
return response
return middleware2
多个中间件的执行顺序:
在请求视图被处理前,中间件由上至下依次执行
在请求视图被处理后,中间件由下至上依次执行
init 2被调用
init 1被调用
before request 1被调用
before request 2 被调用
view 视图被调用
after response 2被调用
after response 1被调用
第一步: 需要先创建 templates 模板文件夹,项目下建目录。
第二步: 在 settings.py 文件中配置模板文件夹路径。
第三步: 在模板文件夹中添加模板文件。
第四步: 在视图函数中调用 render( ) 函数, 调用模板, 有需要可以传参数。
settings.py 配置文件中修改 TEMPLATES 配置项的 DIRS 值
TEMPLATES = [
#......................................
'DIRS': [os.path.join(BASE_DIR, 'templates')], # 在此处拼接模板路径]
# os.path.join拼接路径,BASE_DIR项目的绝对路径
定义模板,在 templates 目录中新建一个模板文件,如 index.html
渲染模板,Django 提供了一个实现模板渲染的函数 render( )
使用方式: render( request, ‘模板文件名称’, 添加给模板的数据)
from django.shortcuts import render
def index(request):
# 定义一个变量, 拼接为字典格式:
context={'city': '北京'}
# 返回 render() 函数
return render(request,'index.html',context)
CSRF(Cross Site Request Forgery)跨站请求伪造。
CSRF指攻击者盗用了的身份,以你的名义发送恶意请求。
CSRF攻击图解
CSRF防护图解
在 ORM 框架中,它帮我们把类和数据表进行了一个映射,可以让我们通过类和类对象就能操作它所对应的表格中的数据。
使用 django 进行数据库开发的步骤如下:
#虚拟环境的命令行中执行
pip install PyMySQL
from pymysql import install_as_MySQLdb
install_as_MySQLdb()
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'HOST': '127.0.0.1', # 数据库主机
'PORT': 3306, # 数据库端口
'USER': 'root', # 数据库用户名
'PASSWORD': 'mysql', # 数据库用户密码
'NAME': 'django_demo' # 数据库名字
}
}
create database django_demo default charset=utf8;
注:子应用,需要在setting中注册!INSTALLED_APPS
(1) 创建子应用 booktest,setting注册,在 models.py 文件中定义模型类。
from django.db import models
# 定义图书模型类 BookInfo
class BookInfo(models.Model):
btitle = models.CharField(max_length=20, verbose_name='名称')
bpub_date = models.DateField(verbose_name='发布日期')
bread = models.IntegerField(default=0, verbose_name='阅读量')
bcomment = models.IntegerField(default=0, verbose_name='评论量')
is_delete = models.BooleanField(default=False, verbose_name='逻辑删除')
class Meta:
db_table = 'tb_books' # 指明数据库表名
verbose_name = '图书' # 在admin站点中显示的名称
verbose_name_plural = verbose_name # 显示的复数名称
def __str__(self):
"""定义每个数据对象的显示信息"""
return self.btitle
# 定义英雄模型类 HeroInfo
class HeroInfo(models.Model):
GENDER_CHOICES = (
(0, 'female'),
(1, 'male')
)
hname = models.CharField(max_length=20, verbose_name='名称')
hgender = models.SmallIntegerField(choices=GENDER_CHOICES, default=0, verbose_name='性别')
hcomment = models.CharField(max_length=200, null=True, verbose_name='描述信息')
hbook = models.ForeignKey(BookInfo, on_delete=models.CASCADE, verbose_name='图书') # 外键
is_delete = models.BooleanField(default=False, verbose_name='逻辑删除')
class Meta:
db_table = 'tb_heros'
verbose_name = '英雄'
verbose_name_plural = verbose_name
def __str__(self):
return self.hname
数据库表名::模型类如果未指明表名,Django 默认以 小写 app应用名_小写模型类名 为数据库表名。
定义属性:需要指定字段类型,通过字段类型的参数指定选项,语法如下:属性=models.字段类型(选项)。
(2)迁移
#1)生成迁移文件
python manage.py makemigrations
#2)同步到数据库中
python manage.py migrate
python manage.py shell
#导入两个模型类,以便后续使用
from booktest.models import BookInfo, HeroInfo
from booktest.models import BookInfo, HeroInfo提前导入
外键定义补充说明:
hbook(对象)——>hbook_id(id)(表中存储的为id)
hbook_id=3 (id赋给id)
hbook_id=book.id (id赋给id)
hbook=book (对象赋给对象)
>>> from datetime import date
>>> book = BookInfo(
btitle='西游记',
bpub_date=date(1988,1,1),
bread=10,
bcomment=10
)
>>> book.save()
>>> hero = HeroInfo(
hname='孙悟空',
hgender=0,
hbook=book
)
>>> hero.save()
>>> hero.save()
>>> hero2 = HeroInfo(
hname='猪八戒',
hgender=0,
hbook_id=book.id
)
>>> hero2.save()
>>> HeroInfo.objects.create(
hname='沙悟净',
hgender=0,
hbook=book
)
<HeroInfo: 沙悟净>
#获取对象:
hero = HeroInfo.objects.get(id=13)
#调用对象的删除方法:
hero.delete()
HeroInfo.objects.filter(id=14).delete()
hero = HeroInfo.objects.get(hname='猪八戒')
hero.hname = '猪悟能'
hero.save()
# 模型类.objects.filter().update(),返回值为受影响的行数。
HeroInfo.objects.filter(hname='沙悟净').update(hname='沙僧')
基本查询
get 查询单一结果,如果不存在会抛出 模型类.DoesNotExist 异常.
all 查询多个结果。
count 查询结果数量。
>>> BookInfo.objects.all()
>>> BookInfo.objects.get(id=3)
>>> BookInfo.objects.get(id=100) #DoesNotExist 异常
>>> BookInfo.objects.count()
过滤条件的表达语法如下:属性名不能包括多个下划线
属性名称__比较运算符 = 值
filter 过滤出多个结果
exclude 排除掉符合条件剩下的结果
get 过滤单一结果
注:
filter查询数据不存在返回
get查询数据不存在会抛出 模型类.DoesNotExist 异常
比较查询
gt 大于 (greater then)
gte 大于等于 (greater then equal)
lt 小于 (less then)
lte 小于等于 (less then equal)
#相等exact:表示判等。
#例:查询编号为1的图书。
BookInfo.objects.filter(id__exact=1)
可简写为:
BookInfo.objects.filter(id=1)
#模糊查询contains:是否包含。说明:如果要包含%无需转义,直接写即可。
#例:查询书名包含'传'的图书。
BookInfo.objects.filter(btitle__contains='传')
#startswith、endswith:以指定值开头或结尾。
#例:查询书名以'部'结尾的图书
BookInfo.objects.filter(btitle__endswith='部')
#以上运算符都区分大小写,在这些运算符前加上i表示不区分大小写,如iexact、icontains、istartswith、iendswith.
#空查询isnull:是否为null
#例:查询书名不为空的图书。
BookInfo.objects.filter(btitle__isnull=False)
#范围查询in:是否包含在范围内
#例:查询编号为1或3或5的图书
BookInfo.objects.filter(id__in=[1, 3, 5])
#比较查询
#gt 大于 (greater then)
#gte 大于等于 (greater then equal)
#lt 小于 (less then)
#lte 小于等于 (less then equal)
#例:查询编号大于3的图书
BookInfo.objects.filter(id__gt=3)
exclude()过滤器,取反。
#例:查询编号不等于3的图书
BookInfo.objects.exclude(id=3)
日期查询
year、month、day、week_day、hour、minute、second:
对日期时间类型的属性进行运算
#例:查询1980年发表的图书。
BookInfo.objects.filter(bpub_date__year=1980)
#例:查询1980年1月1日后发表的图书。
BookInfo.objects.filter(bpub_date__gt=date(1990, 1, 1))
F 对象
两个属性比较使用 F对象,语法如下:F(属性名)
#例:查询阅读量大于等于评论量的图书.
# 导入:
from django.db.models import F
# 查询时使用 F 对象
BookInfo.objects.filter(bread__gte=F('bcomment'))
#可以在 F 对象 上使用算数运算.
#例:查询阅读量大于2倍评论量的图书。
BookInfo.objects.filter(bread__gt=F('bcomment') * 2)
Q 对象
#例:查询阅读量大于20,并且编号小于3的图书。
BookInfo.objects.filter(bread__gt=20,id__lt=3)
#或
BookInfo.objects.filter(bread__gt=20).filter(id__lt=3)
# 导入
from django.db.models import Q
# 获取数据
#例:查询阅读量大于 20的图书,改写为 Q对象.
BookInfo.objects.filter(Q(bread__gt=20))
#Q对象 可以使用 &、|连接,&表示逻辑与,|表示逻辑或.
#例:查询阅读量大于20,或编号小于3的图书,只能使用Q对象实现
BookInfo.objects.filter(Q(bread__gt=20) | Q(pk__lt=3))
#Q对象 前可以使用~操作符,表示非not.
#例:查询编号不等于3的图书。
BookInfo.objects.filter(~Q(pk=3))
聚合函数在 django.db.models 中,使用前需导入。
聚合函数包括:Avg 平均,Max 最大,Min 最小,Sum 求和(需要首字母大写,结合aggregate( ) 过滤器使用)。注意 aggregate 的返回值是一个字典类型。
count 数量,可直接用,首字母小写。
#例:查询图书的总阅读量.
from django.db.models import Sum
BookInfo.objects.aggregate(Sum('bread'))
#注意 aggregate 的返回值是一个字典类型:{'bread__sum':3}
#例:查询图书总数。
BookInfo.objects.count()
#注意 count 函数的返回值是一个数字
排序,使用 order_by 对结果进行排序。
BookInfo.objects.all().order_by('bread') # 升序
BookInfo.objects.all().order_by('-bread') # 降序
book = BookInfo.objects.get(id=1)
book.heroinfo_set.all()
hero = HeroInfo.objects.get(id=1)
hero.hbook
hero = HeroInfo.objects.get(id=1)
hero.hbook_id
(1)由多模型类条件查询一模型类数据
格式:关联模型类名小写__属性名__条件运算符=值
注意:如果没有"__运算符"部分,表示等于。
#查询图书,要求图书英雄为"孙悟空"
BookInfo.objects.filter(heroinfo__hname='孙悟空')
#查询图书,要求图书中英雄的描述包含"八"
BookInfo.objects.filter(heroinfo__hcomment__contains='八')
(2)由一模型类条件查询多模型类数据:
格式:一模型类关联属性名__一模型类属性名__条件运算符=值
#查询书名为“天龙八部”的所有英雄。
HeroInfo.objects.filter(hbook__btitle='天龙八部')
#查询图书阅读量大于30的所有英雄
HeroInfo.objects.filter(hbook__bread__gt=30)
查询集,也称查询结果集、QuerySet,表示从数据库中获取的对象集合。当调用过滤器方法时,Django 会返回查询集(而不是简单的列表): all, filter, exclude, order_by 获取的是查询集。
BookInfo.objects.filter(bread__gt=30).order_by('bpub_date')
惰性执行
创建查询集不会访问数据库,
直到调用数据时,才会访问数据库。
作用:减少对数据库的访问
qs = BookInfo.objects.all()
#执行遍历迭代操作后,才真正的进行了数据库的查询
for book in qs:
print(book.btitle)
缓存
再次使用查询集时会使用缓存的数据,
减少了数据库的查询次数。
#情况一:两个相同的查询集,无法重用缓存,每次查询都会与数据库进行一次交互,增加了数据库的负载。
from booktest.models import BookInfo
[book.id for book in BookInfo.objects.all()]
[book.id for book in BookInfo.objects.all()]
#情况二:经过存储后,可以重用查询集,第二次使用缓存中的数据。
qs=BookInfo.objects.all()
[book.id for book in qs]
[book.id for book in qs]
限制查询集
注意:不支持负数索引。
#获取第1、2项,运行查看。
qs = BookInfo.objects.all()[0:2]
部分数据
insert into tb_book(btitle,bpub_date,bread,bcomment,is_delete) values
('射雕英雄传','1980-5-1',12,34,0),
('天龙八部','1986-7-24',36,40,0);
insert into tb_hero(hname,hgender,hbook_id,hcomment,is_delete) values
('郭靖',1,1,'降龙十八掌',0),
('黄蓉',0,1,'打狗棍法',0),
('黄药师',1,1,'弹指神通',0);
类型 | 说明 |
---|---|
AutoField | 自动增长的IntegerField |
BooleanField | 布尔字段,值为True或False |
NullBooleanField | 支持Null、True、False三种值 |
CharField | 字符串,参数max_length表示最大字符个数 |
TextField | 大文本字段,一般超过4000个字符时使用 |
IntegerField | 整数 |
DecimalField | 十进制浮点数,max_digits总位数,decimal_places小数位数 |
FloatField | 浮点数 |
DateField | 日期, 参数auto_now表示每次保存对象时,自动设置该字段为当前时间,用于"最后一次修改"的时间戳,它总是使用当前日期,默认为False; 参数auto_now_add表示当对象第一次被创建时自动设置当前时间,用于创建的时间戳,它总是使用当前日期,默认为False; 参数auto_now_add和auto_now是相互排斥的,组合将会发生错误。 |
TimeField | 时间,参数同DateField |
DateTimeField | 日期时间,参数同DateField |
FileField | 上传文件字段 |
ImageField | 继承于FileField,对上传的内容进行校验,确保是有效的图片 |
选项 | 说明 |
---|---|
null | 如果为True,表示允许为空,默认值是False |
blank | 如果为True,则该字段允许为空白,默认值是False |
db_column | 字段的名称,如果未指定,则使用属性的名称 |
db_index | 若值为True, 则在表中会为此字段创建索引,默认值是False |
default | 默认 |
primary_key | 若为True,则该字段会成为模型的主键字段,默认值是False,一般作为AutoField的选项使用 |
unique | 如果为True, 这个字段在表中必须有唯一值,默认值是False |
related_name | 在关联查询中,代替单一对象查找多对象 对象名小写_set(book.heroinfo_set.all() 的写法 |
auto_now_add | 只在数据添加的时候,记录时间 |
auto_now | 数据添加和更新的时候,记录时间 |
类型 | 作用 |
---|---|
CASCADE 级联 | 删除主表数据时连通一起删除外键表中数据 |
PROTECT 保护 | 通过抛出ProtectedError异常,来阻止删除主表中被外键应用的数据。 |
SET_NULL | 设置为NULL,仅在该字段null=True允许为null时可用。 |
SET_DEFAULT | 设置为默认值,仅在该字段设置了默认值时可用。 |
SET() | 设置为特定值或者调用特定方法。 |