一、类视图
1、类视图的定义
以函数的方式定义视图称为函数视图,函数视图便于理解,但是遇到一个视图对应的路径提供了多种不同的Http请求方式的支持时,便需要在一个函数中编写不同的业务逻辑,代码可读性与复用性都不佳。在Django中也可以使用类来定义一个视图,称为类视图,使用类视图可以将视图对应的不同请求方式以类中的不同方法来区别定义。
'''
例如在登录页面既要get请求又要post请求
GET 请求是获取登录的页面
POST 请求是验证登录的用户名和密码是否正确
'''
# GET请求 获取登录的页面
def show_login(request):
return render(request)
# POST请求验证登录的用户名和密码,并跳转至首页
def veri_login(request):
return redirect('首页')
# 以上情况由两个视图变为一个视图:
def login(request):
# 需要区分业务逻辑
if request.method == 'GET':
return render(request)
else:
return redirect('首页')
# 以上两种方式代码可读性与复用性都不佳 需要使用类视图
2、类视图的使用
类视图的好处:
- 代码可读性好
- 类视图相对于函数视图有更高的复用性。如果其他地方需要用到某个类视图的某个特定逻辑,直接继承该类视图即可。
- 定义类视图需要继承自Django提供的父类View,可使用from django.views import View,配置路由时,使用类视图的as_view()方法来添加。
'''
面向对象
类视图:采用的面向对象的思路
1.定义类视图
1) 继承自View(from django.views import View)
2) 不同的请求方式有不同的业务逻辑
类视图的方法就是直接采用http请求方式的名字作为函数名,例如 get post put delete
3) 类视图的方法的第二个参数,必须是请求实例对象
类视图的方法必须有返回值,返回值是HttpResponse及其子类
2.类视图的url引导
'''
# 定义类视图
from django.views import View
class LoginView(View):
def get(self,request):
return HttpResponse('get')
def post(self,request):
return HttpResponse('post')
3、类视图的原理
#LoginView.as_view()是一个视图函数名
path('login/',LoginView.as_view()),
二、MRO的顺序继承
虚线代表MRO执行顺序:
'''
个人中心页面
GET方式展示个人中心
POST实现个人中心信息的修改
定义类视图
'''
from django.views import View
# 需求:个人中心展示时,需要用户先登录才能展示个人中心 需要用到LoginRequiredMixin
from django.contrib.auth.mixins import LoginRequiredMixin
# CenterView.as_view()和LoginRequiredMixin中都有dispatch,
# 路由执行CenterView.as_view()展示个人中心时,按照MRO顺序先调用LoginRequiredMixin中的dispatch 判断是否登录
# 如果判断登录了,再按照MRO顺序调用View,成功展示个人中心
# 如果判断没有登录,则不展示个人中心跳转至登录页面
# (LoginRequiredMixin,View):顺序不能变
class CenterView(LoginRequiredMixin,View):
def get(self,request):
return HttpResponse('个人中心展示')
def post(self,request):
return HttpResponse('个人中心修改')
三、中间件
Django中的中间件是一个轻量级、底层的插件系统,可以介入Django的请求和响应处理过程,修改Django的输入或输出,中间件的涉及为开发者提供了一种无侵入式的开发方式,增强了Django框架的健壮性。我们可以使用中间件,在Django处理视图的不同阶段对输入或输出进行干预。
1、中间件的定义方法
定义一个中间件工厂函数,然后返回一个可以被调用的中间件,中间件工厂函数需要接收一个可以调用的get_response对象,返回的中间件也是一个可以被调用的对象,并且像视图一样需要接收一个request对象参数,返回一个response对象
django中的中间件settings.py中
1)在工程或者子应用中创建middleware.py文件
2)定义中间件
'''
中间件的作用:每次请求和响应的时候都会调用,比如 可以判断每次请求中是否携带了cookie中的某些信息
中间件的定义:
'''
def simple_middleware(get_response):
def middleware(request):
# 请求前
print('before request')
response = get_response(request)
# 请求后/响应后
print('after request/response')
return response
return middleware
中间件的作用:每次请求和响应的时候都会调用:
3)注册中间件
4)中间件应用
判断每次请求中是否携带了cookie中的某些信息
代码如下:
'''
中间件的作用:每次请求和响应的时候都会调用,比如 可以判断每次请求中是否携带了cookie中的某些信息
中间件的定义:
'''
from django.http import HttpRequest, HttpResponse
def simple_middleware(get_response):
def middleware(request):
username = request.COOKIES.get('username')
if username is None:
print('username is None')
return HttpResponse('你没有登录')
# 请求前
print('before request')
response = get_response(request)
# 请求后/响应后
print('after request/response')
return response
return middleware
效果:get请求:
post请求:
4)中间件执行顺序
- 在请求视图被处理前,中间件由上至下执行
- 在请求视图被处理后,中间件由下至上执行
四、模板
1、模板的基本配置
- 在工程中创建模板目录templates
- settings.py配置文件中修改TEMPLATES配置项的DIRS值
- 定义模板,在templates目录下创建模板文件index1.html,动态获取url中的username。
变量名必须由字母、数字、下划线(不能以下划线开头)和点组成。
语法如下:{{变量}}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>hello</title>
</head>
<body>
{#http://127.0.0.1:8000/index1/?username=itheima#}
<a href="#">{{ username }}</a>
</body>
</html>
- 创建类视图,渲染模板
#####################################模板##########################################
class HomeView(View):
def get(self,request):
# 1.获取数据-username
# http://127.0.0.1:8000/index1/?username=itheima
username = request.GET.get('username')
# 2.组织数据
context = {
'username': username
}
# 3.模板动态获取数据
return render(request,'index1.html',context=context)
- 配置路由
- 运行
2、模板的基本语法
django文档中查看更多语法:Django文档
- 比较运算符:
等于:==
不等于:!=
大于:>
小于:<
大于等于:>=
小于等于:<=
- 布尔运算符: and or not
- 注意:运算符左右两侧必须有空格
{% if a == 1%} #正确
{% if a==1%} #错误 - for 循环
{% for item in 列表%}
循环逻辑
{{ forloop.counter }}表示当前第几次循环,从1开始
{% empty %} # 列表为空或不存在时执行此逻辑
{% endfor %}
- if 条件
{% if ... %}
逻辑1
{% elif ... %}
逻辑2
{% else %}
逻辑3
{% endif %}
- 字典和列表的取值方法
class HomeView(View):
def get(self,request):
# 1.获取数据-username
# http://127.0.0.1:8000/index1/?username=itheima
username = request.GET.get('username')
# 2.组织数据
context = {
'username': username,
'age':14,
'birthday':datetime.date,
'friends':['tom','jack','rose'],
'money':{
'2019':12000,
'2020':18000,
'2021':25000,
}
}
# 3.模板动态获取数据
return render(request,'index1.html',context=context)
{#列表取值方式#}
<h3>我的女朋友是{{ friends.2 }}</h3>
{#字典取值方式#}
<h3>我第一年的月薪是{{ money.2019 }}</h3>
3、过滤器
语法如下:
- 使用管道符号|来应用过滤器,用于进行计算、转换操作,可以使用在变量、标签中。
- 如果过滤器需要参数,则使用冒号:传递参数
变量|过滤器:参数
列举几个如下:
- safe,禁用转义,告诉模板这个变量是安全的,可以解释执行
- length,长度,返回字符串包含字符的个数,或列表、元组、字典的元素个数。
- defaault,默认值,如果变量不存在时则返回默认值
data|default:'默认值'
- data,日期,用于对日期类型的值进行字符串格式化,常用的格式化字符串如下:
-
- Y 表示年,格式为四位,y表示两位的年
-
- m 表示月,格式为01、02、12等
-
- d 表示日,格式为01、02等
-
- j 表示日,格式为1、2等
-
- H 表示时,24进制,h表示12进制的时
-
- i 表示分,为0-59
-
- s 表示秒,为0-59
value | date:"Y年m月j日 H时1分s秒"
全部
index1
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>hello</title>
</head>
<body>
{#http://127.0.0.1:8000/index1/?username=itheima#}
<a href="#">{{ username }}</a>
<hr>
<h3>我的年龄是{{ age }}</h3>
<hr>
<h3>我的朋友是{{ friends }}</h3>
<hr>
总共有{{ friends|length }}个朋友
<hr>
{#对列表遍历-----for循环(流程控制的语法)#}
{% for friend in friends %}
{# forloop:对象的属性 #}
<li>{{ forloop.counter }}{{ friend }}</li>
{% endfor %}
<hr>
{#列表取值方式#}
<h3>我的女朋友是{{ friends.2 }}</h3>
{#字典取值方式#}
<h3>我第一年的月薪是{{ money.2019 }}</h3>
<hr>
{#大于号前后要加空格#}
{% if age > 10 %}
大于10岁
{% else %}
不大于10岁
{% endif %}
<hr>
{#过滤器的语法形式:变量|过滤器:参数 #}
我的生日是{{ birthday|date:'Y年 m月 d日 ' }}
<hr>
{#如果不加safe,js会被转义 将代码显示在页面变成:#}
{#我的简介是<script>alter("hot")</script>#}
{#加上safe才可以正常执行alter#}
我的简介是{{ desc|safe }}
<hr>
没有定义的变量{{ abd|default:'默认值' }}
</body>
</html>
#####################################模板##########################################
class HomeView(View):
def get(self,request):
# 1.获取数据-username
# http://127.0.0.1:8000/index1/?username=itheima
username = request.GET.get('username')
# 2.组织数据
context = {
'username': username,
'age':14,
'birthday':datetime.datetime.now(),
'friends':['tom','jack','rose'],
'money':{
'2019':12000,
'2020':18000,
'2021':25000,
},
'desc':'<script>alter("hot")</script>'
}
# 3.模板动态获取数据
return render(request,'index1.html',context=context)
4、模板继承
模板继承和类的继承含义一样,主要是为了提高代码的重用,减轻开发人员的工作量。
- 父模板
1)如果发现在多个模板中某些内容相同,那就应该把这段内容定义到父模板中。
2)标签block:用于在父模板中预留区域,留给子模板填充差异性的内容,名字不能相同,为了更好的可读性,建议给endblock标签写上名 字,这个名字与对应的block名字相同,父模板中也可以使用上下文中传递过来的数据。 - 子模板
1)标签extends:继承,卸载子模板文件的第一行
{% block 名称 %}
预留区域,可以编写默认内容,也可以没有默认内容
{% endblock 名称 %}
2)子模板不用填充父模板中的所有预留区域,如果子模板没有填充,则使用父模板定义的默认值。
{% extends "父模板路径" %}
示例:
base.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
{% block header %}
<h1>顶部</h1>
{% endblock header %}
{% block main %}
<h1>我是主要部分</h1>
{% endblock %}
{% block footer %}
<h1>this is footer</h1>
{% endblock footer %}
</body>
</html>
detail.html
{#把继承的模板写在最上边#}
{% extends 'base.html' %}
{#需要改哪里,直接实现block#}
{% block title %}
详情页面
{% endblock %}
{% block main %}
<a href="#">戳我有惊喜</a>
{% endblock main %}
{#不需要某个block,直接重写#}
{% block footer %}{% endblock %}
运行
五、jinja2模板
1、jinja2介绍
jinja2是Python下一个被广泛应用的模板引擎,是由python实现的模板语言,他的设计思想来源于Django的模板引擎,并扩展了其语法和一系列强大的功能,尤其是Flask框架内置的模板语言。由于django默认的模板引擎功能不齐全,速度慢,所以我们也可以在django中使用jinja2,jinja2宣称比django默认模板引擎快10-20倍。Django主流的第三方App基本上也都同时支持jinja2,所以要用jinja2也不会有多少障碍
2、安装jinja2模块
pip3 install jinja2
3、配置jinja2
1)在项目文件或子应用中创建jinja2_env.py文件 ,此处在book子应用中添加文件jinja2_env.py
让jinja2使用Django中的过滤器,代码如下:
from django.template.defaultfilters import date
from jinja2 import Environment
def environment(**option):
# 1. 创建Environment实例
env = Environment(**option)
# 2. 指定(更新)jinja2的函数指向过滤器
env.globals.update({
'date':date
})
# 返回Environment实例
return env
或者自定义jinja2过滤器:
from jinja2 import Environment
def environment(**option):
# 1. 创建Environment实例
env = Environment(**option)
# 2. 将自定义的过滤器添加到环境中
env.filters['do_listreverse'] = do_listreverse
return env
def do_listreverse(li):
if li == 'B':
return 'haha'
2)默认的django的模板配置保留,不要删除,settings.py文件中将jinja2写在前边:
TEMPLATES = [
{ # 添加jinja2的模板引擎
'BACKEND': 'django.template.backends.jinja2.Jinja2',
# 设置模板的路径
'DIRS': [BASE_DIR / 'templates'],
'APP_DIRS': True,
'OPTIONS': {
# 'environment':'jinja2.Environment', # 默认环境
'environment':'book.jinja2_env.environment', # 指定jinja2的环境
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
},
},
{ # 默认的是django的模板引擎
'BACKEND': 'django.template.backends.django.DjangoTemplates',
# 设置模板的路径
'DIRS': [BASE_DIR / 'templates'],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
},
},
]
4、模板语法
jinja2模板的使用绝大多数和Django自带模板一样
jinjia2只有单行注释,没有多行注释
变量 | 描述 |
---|---|
loop.index | 当前循环迭代的次数(从1开始) |
loop.index() | 当前循环迭代的次数(从0开始) |
loop.revindex | 到循环结束需要迭代的次数(从1开始) |
loop.revindex() | 到循环结束需要迭代的次数(从1开始) |
loop.first | 如果是第一次迭代,为True |
loop.last | 如果是最后一次迭代,为Ture |
loop.length | 序列中的项目数 |
loop.cycle | 在一串序列间取值的辅助函数 |
5、jinja2过滤器
六、CSRF
- CSRF 全拼为 Cross Site Request Forgery,译为跨站请求伪造。
- CSRF 指攻击者盗用了你的身份,以你的名义发送恶意请求,包括以你的名义发送邮件、发消息、盗取你的账号。甚至于购买商品,虚拟货币转账……
- 造成 的问题:个人隐私泄露以及财产安全。
CSRF的cookie解决方案