17 django框架(中)视图|模板

news2024/11/16 13:50:48

文章目录

  • 框架介绍
    • 模型类
    • 视图
      • 视图的功能
        • 页面重定向
      • 视图函数的使用
      • url匹配过程
      • 错误视图
        • 补充
      • 捕获url参数
        • 类型介绍
      • 普通登录案例(前情准备)
        • HttpReqeust 对象
        • HttpResponse 对象
        • QueryDict 对象(即GET POST )
        • 总结
      • ajax
        • ajax的登录样例
      • 状态保持
        • cookie
        • Session
          • 启用Session
          • 对象以及使用方法
          • 记住登录状态示例
    • 模板
      • 模板的功能
      • 模板文件的使用
      • 模板文件加载顺序
      • 模板语言
        • 变量
        • 标签(模板中使用for和if函数)
        • 过滤器(调用自己使用的函数)
        • 注释
      • 模板继承
      • html转义
      • csrf攻击
      • 反向解析
        • 补充 软件库下 url
        • 前端反向解析(带参数)
        • 后端的反向解析(带参数)
    • 其他技术

框架介绍

模型类

见16 django框架(上)

视图

视图的功能

接收请求,进行处理,与 M 和 T 进行交互,返回应答。

返回 html 内容 HttpResponse,也可能重定向 redirect,还可以返回 json数据

页面重定向

服务器不返回页面,而是告诉浏览器再去请求其他的 url 地址:

将 return HttpResponse(‘ok’)改为 return HttpResponseRedirect(‘/index’),当然在头部需要增加HttpResponseRedirect 的引用包

def delete(request, bid):
	'''删除点击的图书'''
	# 1.通过 bid 获取图书对象
	book = BookInfo.objects.get(id=bid)
	# 2.删除
	book.delete()
	# 3.重定向,让浏览器访问/index
	# return HttpResponseRedirect('/index')
	return redirect('/index')

视图函数的使用

  1. 定义视图函数:request 参数必须有
  2. 配置 url:建立 url 和视图函数之间的对应关系。

url匹配过程

在这里插入图片描述

错误视图

404:找不到页面,关闭调试模式之后(在 setting.py 中修改 DEBUG 开关进行调试模式设置),默认会显示一个标准的错误页面,如果要显示自定义的页面,则需要的 templates 目录下面自定义一个 404.html 文件

404 错误

  1. url 没有配置
  2. url 配置错误

500: 服务器端的错误。

  1. 视图出错

补充

网站开发完成需要关闭调试模式,在 settings.py 文件中:

DEBUG=False
ALLOWED_HOST=[ '*'] #允许绑定的 IP 地址列表

比如在代码中增加 num =‘b’+1 这样的错误代码,就会出现 500 错误,当然我们也可以自己增加一个 500.html 页面,这样就会显示对应的内容,配置 400 和 505 页面需要重启 Django 服务器。

捕获url参数

在这里插入图片描述
关于path的理解,实际上这么一串数据,最后做到的就是将访问的url指向,匹配到对应的函数,并且将year ,month等等传递给相对应的视图函数。

类型介绍

  1. str - 匹配除了 ‘/’ 之外的非空字符串。如果表达式内不包含转换器,则会默认匹配字符串。
  2. int - 匹配 0 或任何正整数。返回一个 int 。
  3. slug - 匹配任意由 ASCII 字母或数字以及连字符和下划线组成的短标签。比如,building-your-1st-django-site 。
  4. uuid - 匹配一个格式化的 UUID 。为了防止多个 URL 映射到同一个页面 ,必 须包含破折号并且字符都为小写 。比如,075194d3-6885-417e-a8a86c931e272f00。返回一个 UUID 实例。
  5. path - 匹配非空字段,包括路径分隔符 ‘/’ 。它允许你匹配完整的 URL 路径而不是像 str 那样只匹配 URL 的一部分。

如果要用正则表达式,要用 re_path

普通登录案例(前情准备)

模板文件(login.html):

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>登录</title>
</head>
<body>
<form method="post" action="/login_check/">
    用户名:<input type="text" name="username" value="{{ username }}"><br/>
    密码:<input type="password" name="password"><br/>
    <input type="checkbox" name="remember">记住用户名<br/>
    <input type="submit" value="登录">
</form>
</body>
</html>

重点关注的对象是action:在模板文件中增加表单 form(注意 2.2 版本 action 必须是/login_check/,3.2版本可以采用/login_check),这边action的意思就是,当点击提交这个form表单的时候,跳转到url为/login_check的地方

还有这边定义的是采用post的方法进行上传信息:
在这里插入图片描述

在这里插入图片描述

HttpReqeust 对象

服务器接收到 http 协议的请求后,会根据报文创建 HttpRequest 对象,这个对
象不需要我们创建,直接使用服务器构造好的对象就可以。视图的第一个参数
必须是 HttpRequest 对象,在 django.http 模块中定义了 HttpRequest 对象的
API,实际上就是右键检查网络当中的-request header那一部分,而这一部分返回的值,会被返回到view视图的
在这里插入图片描述
关于request属性介绍:

  1. path:一个字符串,表示请求的页面的完整路径,不包含域名和参数部分。
  2. method:一个字符串,表示请求使用的 HTTP 方法,常用值包括 : ‘GET’,‘POST’,’PUT’,’DETELE’。
  3. encoding:一个字符串,表示提交的数据的编码方式。如果为 None 则表示使用浏览器的默认设置,一般为 utf-8。
  4. GET:QueryDict 类型对象,类似于字典,包含 get 请求方式的所有参数。
    例:网址如下
    http://www.cskaoyan.com/?a=10&b=20&c=python
    其中的请求参数为:a=10&b=20&c=python
    分析请求参数,键为’a’、‘b’、‘c’,值为’10’、‘20’、‘python’。
    在 Django 中可以使用 HttpRequest 对象的 GET 属性获得 get 方方式请求的参数。GET 属性是一个 QueryDict 类型的对象,键和值都是字符串类型。
  5. POST:QueryDict 类型对象,类似于字典,包含 post 请求方式的所有参数。
    使用 form 表单请求时,method 方式为 post 则会发起 post 方式的请求,需要使用 HttpRequest 对象的 POST 属性接收参数,提取数据和GET的方式一样。
  6. FILES:一个类似于字典的对象,包含所有的上传文件。
  7. COOKIES:一个标准的 Python 字典,包含所有的 cookie,键和值都为字符串。
  8. session:一个既可读又可写的类似于字典的对象,表示当前的会话,只有当 Django 启用会话的支持时才可用,详细内容见"状态保持"。

HttpResponse 对象

实际上就是右键查询网络的第二个 和 上面的进行区分。

视图在接收请求并处理后,必须返回 HttpResponse 对象或子对象。在django.http 模块中定义了 HttpResponse 对象的 API。HttpRequest对象由Django 创建,HttpResponse 对象由开发人员创建。

属性
content:表示返回的内容。
charset:表示 response 采用的编码字符集,默认为 utf-8。
status_code:返回的 HTTP 响应状态码。
content-type:指定返回数据的的 MIME 类型,默认为’text/html

主要是两种方式使用 Response

  1. return HttpResponse(‘hello’)
  2. return render(request, ‘booktest/index.html’, {‘content’: 'hello})

QueryDict 对象(即GET POST )

与 python 字典不同,QueryDict 类型的对象用来处理同一个键带有多个值的情况。

使用方法:

  1. QueryDict.get(键) 得到的是一个值
  2. QueryDict.get(键,默认值) 当这个键不存在,就插入一个默认值键值对,并且返回自己
  3. QueryDict[键] 得到的也是一个值
  4. QueryDict.getlist(键) 由于QueryDict对象可能存在{‘a’:[1,2]},他的值是存储在一个列表当中的,即可以允许重复插入值。这个方法提取的就是全部的值

例子(补充login_check):

def login_check(request):
	'''登录校验视图''' 
	# request.POST 保存的是 post 方式提交的参数 QueryDict
	# request.GET 保存是 get 方式提交的参数 类型也是 QueryDict
	username=request.POST.get('username')
	password=request.POST.get('password')
	print(username+':'+password)
	return HttpResponse('ok')

总结

写的有点乱:整理一下流程

  1. 先写一个前端显示login.html,里面的表单中 关注method 代表以什么方式进行上传数据 和 action 代表当提交表单之后会传送到什么url
  2. 配置login的url,转向view.login函数
  3. 在login函数当中先不进行书写,这里是当我们访问登录页面的时候需要的操作,一般这里用来判断是否已经登陆过了,检查cookie内部是否存在登陆的账号,如果登录,转向别的别的页面,没的话,继续本页面
  4. 然后配置login_check 也就是action中的url
  5. 编写login_check 的函数,这里面访问数据库,检测是否存在用户名以及相对应的密码。

以及上文的三种对象,进行理解

ajax

异步的 javascript。在不全部加载某一个页面部的情况下,对页面进行局部的
刷新,ajax 请求都在后台。
在这里插入图片描述

也就是说,回想一下我们前面的登录试验,我们所作的是先在login页面进行登录,然后点击登陆后,先转到login_check页面,然后在login_check函数的作用下再返回别的页面,但我们不想要这种做法,我们希望没有页面跳转,也就是我们仅仅向在login页面登录,然后页面还是在本页面,或者显示登录成功的页面的异步加载,这就需要用到ajax方法,步骤:

  1. 发起 ajax 请求:jquery 发起
  2. 执行相应的视图函数,返回 json 内容
  3. 执行相应的回调函数。通过判断 json 内容,进行相应处理。

ajax的登录样例

首先就是需要放置对应的文件,比如我们这边需要放置jquery文件(ajax就在里面),放置文件的位置:

  1. 我们需要先在项目目录下放置一个文件夹(一般名为static的文件夹)
  2. 然后到配置下加上:
# 这个是静态文件的位置,这边的static代表的就是根目录下的static
STATICFILES_DIRS = [os.path.join(BASE_DIR, 'static')]
  1. 然后往内部加上文件,比如这里要在static文件夹下创建js文件夹,内部再放入jquery的文件,如此完成配置。

然后就是先编写html文件:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>ajax登录</title>
    <script src="/static/js/jquery-1.12.4.min.js"></script>
    <script>
        $(function () {
            $('#btnLogin').click(function () {
                // 1.获取用户名和密码
                username = $('#username').val()
                password = $('#password').val()
                // 2.发起post ajax请求,/login_ajax_check, 携带用户名和密码
                $.ajax({
                    'url':'/login_ajax_check/', //当是post请求时默认多写一个/让urls匹配保持一致
                    'type': 'post',
                    'data': {'username':username, 'password':password},
                    'dataType': 'json'
                }).success(function (data) {
                    // 登录成功 {'res':1}
                    // 登录失败 {'res':0}
                    if (data.res == 0){
                        $('#errmsg').show().html('用户名或密码错误')
                    }
                    else{
                        // 跳转到首页
                        location.href = '/index'
                    }
                })
            })
        })
    </script>
    <style>
        #errmsg{
            display: none;
            color: red;
        }
    </style>
</head>
<body>
<div>
    用户名:<input type="text" id="username"><br/>
    密码:<input type="password" id="password"><br/>
    <input type="button" id="btnLogin" value="登录">
    <div id="errmsg"></div>
</div>
</body>
</html>

如此之后,当点击登录按钮,将会向url为 /login_ajax_check/的地方发送post的请求,然后数据是json格式的data

					'url':'/login_ajax_check/', 
                    'type': 'post',
                    'data': {'username':username, 'password':password},
                    'dataType': 'json'

此时我们就需要编写对应的后端函数,并且匹配上路由为login_ajax_check。

  1. 匹配路由略
  2. 后端函数(要求需要返回一个json格式的数据,就用于类似上文的判断,当传回的数据的res是0,代表登录失败,我们就在id名为errmsg的组件上加上用户名或密码错误)
.success(function (data) {
                    // 登录成功 {'res':1}
                    // 登录失败 {'res':0}
                    if (data.res == 0){
                        $('#errmsg').show().html('用户名或密码错误')
                    }
                    else{
                        // 跳转到首页
                        location.href = '/index'
                    }

后端代码:(值得关注的是,这边使用的就不是和以前一样,返回一个redirect(‘/login’),或者render(),这边一定需要返回一个JsonResponse({‘res’:1})对象用于判断)

def login_ajax_check(request):
    '''ajax登录校验'''
    # 1.获取用户名和密码 
    username = request.POST.get('username')
    password = request.POST.get('password')

    # 2.进行校验,返回json数据
    if username == 'admin' and password == '123':
        # 用户名密码正确
        return JsonResponse({'res':1})
        # return redirect('/index') ajax请求在后台,不要返回页面或者重定向,这样是不行的,一定要返回Json!
    else:
        # 用户名或密码错误
        return JsonResponse({'res':0})

状态保持

http 协议是无状态的。下一次去访问一个页面时并不知道上一次对这个页面做了什么。具体意思就是类似短连接,我们访问某一个路由,他就把对应的资源传给你,然后断开连接,那么什么是有状态呢?就是游戏,我么需要时刻连接的这种长连接模式。

cookie

cookie 是由服务器生成,存储在浏览器端的一小段文本信息。

cookie 的特点:

  1. 以键值对方式进行存储。
  2. 通过浏览器访问一个网站时,会将浏览器存储的跟网站相关的所有 cookie信息发送给该网站的服务器。request.COOKIES
  3. cookie 是基于域名安全的。www.baidu.com www.iqiyi.com
  4. cookie 是有过期时间的,如果不指定,默认关闭浏览器之后 cookie 就会过期。

样例1:基本使用,使用之后就会在浏览器的

from datetime import datetime,timedelta

# /set_cookie
def set_cookie(request):
	'''设置 cookie 信息''' 
	response = HttpResponse('设置 cookie')
	# 设置一个 cookie 信息,名字为 num, 值为 2
	# response.set_cookie('num', 2)
	# 下面是设置 cookie 在两周之后过期
	# response.set_cookie('num', 2, max_age=14*24*3600)
	response.set_cookie('num',1,expires=datetime.now()+timedelta(days=14))
	# 返回 response
	return respons

在这里插入图片描述

样例2:
cookie的基本使用:还是以登录为例子,实际上就是为了让用户本次输入账号之后,之后再一次进入此页面,达到账号已经填入的效果,只需要输入密码就可以完成登录的效果。

def login(request):
    # 判断用户是否登录
    if request.session.has_key('islogin'):
        # 用户已登录, 跳转到首页
        return redirect('/index')
    if 'username' in request.COOKIES:
        # 获取记住的用户名
        username = request.COOKIES['username']
    else:
        username = ''

    return render(request, 'booktest/login.html', {'username': username})

def login_check(request):
    '''登录校验视图'''
    # request.POST 保存的是post方式提交的参数 QueryDict
    # request.GET 保存是get方式提交的参数  类型也是 QueryDict
    username=request.POST.get('username')
    password=request.POST.get('password')
    remember=request.POST.get('remember')
    if username=='admin' and password=='123':
        reponse=redirect('/index')	
        # 值得关注的是,在前端中的打勾返回的json格式数据,一般都是on
        if remember=='on':
            reponse.set_cookie('username', username, max_age=7*24*3600)
        return reponse
    else:
        return redirect('/login')

Session

现在我们又面临一个问题,就是我们想要记录我们的登录状态,那cookie只能完成服务器上存储我们发送的信息,这没办法完成,甚至还有点不安全,于是我们需要引入Session,这个能在数据库当中存储我们的登录状态,但是也需要搭配cookie进行使用。

在这里插入图片描述
session 存储在服务器端。

在服务器端进行状态保持的方案就是 Session。

session 的特点:

  1. session 是以键值对进行存储的。
  2. session 依赖于 cookie。唯一的标识码 sessionid 保存在 cookie 中,实际上就变成了服务器向浏览器以cookie的方式 传递sessionid码,然后每次浏览器读取这个网页,就通过这个cookie码去服务器的数据库当中查询登录状态
  3. session 也是有过期时间,如果不指定,默认两周就会过期。
  4. session 与 cookie 的差异,cookie 无论保存什么值进去,取出来都是字符串,session 保存进去什么类型,取出来就是什么类型。
启用Session

Django 项目默认启用 Session,在setting.py文件当中:
在这里插入图片描述
值得关注的是我们这边注释了csrf,这个是跨域问题的中间件,注释掉解决跨域问题,但是当上线的时候,需要打开。

存储 Session 时,键与 Cookie 中的 sessionid 相同,值是开发人员设置的键
值对信息,进行了 base64 编码,过期时间由开发人员设置。Base64 是网络上最常见的用于传输 8Bit 字节码的编码方式之一,Base64 就是一种基于 64个可打印字符来表示二进制数据的方法

对象以及使用方法
通过 HttpRequest 对象的 session 属性进行会话的读写操作。
1) 以键值对的格式写 session。
request.session['键']=2)根据键读取值。
request.session.get('键',默认值)
或者 request.session['键']
3)清除所有 session,clear()方法只清除会话中的数据,但会话本身仍然存在。
request.session.clear()
4)清除 session 数据,在存储中删除 session 的整条数据。flush()方法不仅清除会话中的数据,还会删除会话本身,使用户获得一个新的会话。
request.session.flush()
5)删除 session 中的指定键及值,在存储中只删除某个键及对应的值。
del request.session['键']
6)设置会话的超时时间,如果没有指定过期时间则两个星期后过期。
request.session.set_expiry(value)
 如果 value 是一个整数,会话将在 value 秒没有活动后过期。
 如果 value为 0,那么用户会话的 Cookie 将在用户的浏览器关闭时过期。
 如果 value 为 None,那么会话永不过期。
记住登录状态示例
def login(request):
    # 判断用户是否登录
    if request.session.has_key('islogin'):
        # 用户已登录, 跳转到首页
        return redirect('/index')
    if 'username' in request.COOKIES:
        # 获取记住的用户名
        username = request.COOKIES['username']
    else:
        username = ''

    return render(request, 'booktest/login.html', {'username': username})

def login_check(request):
    '''登录校验视图'''
    # request.POST 保存的是post方式提交的参数 QueryDict
    # request.GET 保存是get方式提交的参数  类型也是 QueryDict
    username=request.POST.get('username')
    password=request.POST.get('password')
    remember=request.POST.get('remember')
    if username=='admin' and password=='123':
        reponse=redirect('/index')
        request.session['islogin']=True
        if remember=='on':
            reponse.set_cookie('username', username, max_age=7*24*3600)
        return reponse
    else:
        return redirect('/login')

模板

模板的功能

产生 html,控制页面上展示的内容。模板文件不仅仅是一个 html 文件。模板文件包含两部分内容:

  1. 静态内容:css,js,html。
  2. 动态内容:用于动态去产生一些网页内容。通过模板语言来产生。

模板文件的使用

通常是在视图函数中使用模板产生 html 内容返回给客户端。

  1. 加载模板文件 loader.get_template 获取模板文件的内容,产生一个模板对象。
  2. 定义模板上下文 Context 给模板文件传递数据。
  3. 模板渲染产生 html 页面内容 render(之前已经用过多次)
    用传递的数据替换相应的变量,产生一个替换后的标准的 html 内容。

下面是关于我们经常使用的render的一个解析(示例):

from django.template import loader,RequestContext
from django.http import HttpResponse

def my_render(template_path, context={}):
	# 1.加载模板文件,获取一个模板对象
	temp = loader.get_template(template_path)
	# 2.给模板传参,模板渲染,产生一个替换后的 html 内容
	res_html = temp.render(context)
	# 3.返回应答
	return HttpResponse(res_html)

def index(request):
	return my_render('booktest/index.html')
	#return render(request,'booktest/index.html')

上面是为了让大家理解 render 主要做了哪些事情,但是实际上的 使用直接使用render即可,内部填的参数也直接类似这种:render(request, ‘转达的html文件’,{‘area’:area,‘parent’:parent, ‘children’:children}需要传递的参数)

模板文件加载顺序

  1. 首先去配置的模板目录下面去找模板文件。
  2. 去 INSTALLED_APPS 下面的每个应用的 templates 去找模板文件,前提是应用中必须有 templates 文件夹,加载顺序是 INSTALLED_APPS 中的顺序

模板语言

模板语言简称为 DTL。(Django Template Language)
模板语言包括 4 种类型,分别是:变量 标签 过滤器 注释.

变量

模板变量名是由数字,字母,下划线和点组成的,不能以下划线开头,然后在html上进行使用,在后端render()的第三个参数上传输,以键值对来传输。

使用模板变量:{{模板变量名}}

模板变量的解析顺序:
例如:{{ book.btitle }}

  1. 首先把 book 当成一个字典 ,把 btitle 当成键名,进行取值book[‘btitle’]
  2. 把 book 当作一个列表,但是bititle明显不是一个数字,所以跳过。
  3. 把 book 当成一个对象,把 btitle 当成属性,进行取值 book.btitle。
  4. 把 book 当成一个对象,把 btitle 当成对象的方法,进行取值 book.btitle

标签(模板中使用for和if函数)

for循环使用方法:
{% 代码段 %}
# for循环
{% for x in 列表 %}
# 列表不为空时执行
{% empty %}
# 列表为空时执行
{% endfor %}
# 可以通过{{ forloop.counter }}得到 for 循环遍历到了第几次

if判断使用方法:
{% if 条件 %}
{% elif 条件 %}
{% else %}
{% endif %}
关系比较操作符:> < >= <= == != 注意:进行比较操作时,比较操作符两边必须包含空格
逻辑运算:not and or

示例:
{% for book in books %}
	{% if book.id <= 2 %}
		<li class="red">{{ forloop.counter }}--{{ book.btitle }}</li>
	{% elif book.id <= 5 %}
		<li class="yellow">{{ forloop.counter }}--{{ book.btitle }}</li>
	{% else %}
		<li class="green">{{ forloop.counter }}--{{ book.btitle }}</li>
	{% endif %}

{% endfor %}


过滤器(调用自己使用的函数)

参考链接

这边只点几个个人认为重要的:

格式:模板变量|过滤器:参数
自定义过滤器。(比如不能使用除号)
自定义的过滤器函数,至少有一个参数,最多两个。

自定义过滤标签的时候,需要在 应用文件夹 下新建 templatetags文件夹,注意必须在对应路径,而且必须叫这个名字,在下面新建 filters.py文件。

内部写上相对应的代码:这边以我写的为例子:

from django.template import Library

# 创建一个 Library 类的对象
register = Library()

# 自定义的过滤器函数,至少有一个参数,最多两个

# 自定义过滤器函数一,实际上完成的就是判断是不是偶数
@register.filter
def mod(num):
	'''判断 num 是否为偶数'''
	return num%2 == 0

# 自定义过滤器函数二
@register.filter
def mod_val(num, val):
	'''判断 num 是否能被 val 整除'''
	return num%val == 0

相对应使用模板函数地方,一些比较不重要的去掉了,只保留使用了的地方

{% for book in books %}
	{# {% if book.id|mod %}#}         # 使用一个参数的地方,实际上默认将第一个book.id当作第一个参数进行传入
	{% if book.id|mod_val:3 %}        # 使用俩个参数的地方,第一个是book.id第二个是3,需要用:隔开
		<li class="red">{{ book.id }}--{{ book.btitle|length }}--{{ book.bpub_date|date:'Y/m/d' }}</li>
	{% else %}
		<li class="green">{{ book.btitle }}--{{ book.bpub_date }}</li>
	{% endif %}
{% endfor %}

上文还使用了date这一个内置的模板函数的地方,我们这边简要介绍一下date这种模板函数,实际上就是我们没使用模板函数的时候,显示的是2023年8月28日,但使用了上文类型的模板函数,就会变成我们想要的格式:2023/08/28

具体的内置过滤器函数,见上面的链接即可。

注释

单行注释:
{# 注释内容 #}

多行注释:
{% comment %}
······
注释内容
······
{% endcomment %}

浏览器源代码看不到模板注释的,但是可以看到 html 的注释。

模板继承

模板继承也是为了重用 html 页面内容。比如很多网站的头部导航条和底部版权版权信息不变的,但是如果想要不断重写这一块内容,就很浪费时间,所以对于我们来说就需要一个父亲模板,内部已经编写好了导航条和底部的版权等内容,然后子模板去继承,节省时间。

在这里插入图片描述
例子:父亲模板 base.html 父亲写block的地方实际上就是放着需要替换的位置

<!DOCTYPE html>
<html lang="en">
	<head>
		<meta charset="UTF-8">
		<title>{% block title %}父模板文件{% endblock title %}</title>
	</head>
	<body>
		<h1>导航条</h1>
		{% block b1 %}
			<h1>这是父模板 b1 块中的内容</h1>
		{% endblock b1 %}

		{% block b2 %}
			<h1>这是父模板 b2 块中的内容</h1>
		{% endblock b2 %}
		<h1>版权信息</h1>
	</body>
</html>

子模板 (首先先extends指向要继承的父亲模板 然后下文一个个去替换,{{ block.super }}是使用父亲模板内的内容,如果没有这句,就直接完全替换)

{% extends 'booktest/base.html' %}

{% block title %}子模板文件{% endblock title %}

{% block b1 %}
	{{ block.super }}
	<h1>这是子模板 b1 块中的内容</h1>
{% endblock b1 %}

{% block b2 %}
	{{ block.super }}
	<h1>这是子模板 b2 块中的内容</h1>
{% endblock b2 %}

html转义

在模板上下文中的 html 标记默认是会被转义的。

  1. 小于号< 转换为&lt;
  2. 大于号> 转换为&gt;
  3. 单引号’ 转换为&#39;
  4. 双引号" 转换为 &quot;
  5. 与符号& 转换为 &amp;

什么意思呢?就是说,当我们view函数中render(request, 地址,{‘content’:‘<h1>hello world</h1>’})的时候网页上会直接打印出<h1>\hello world,而不是我们想要的h1标题状的hello world,那我们想要他能直接打印出标题装的,就需要我们让他关闭转义功能

  打印出<h1>hello world</h1>
html 转义:<br/>  
{{ content }}<br/>

  打印出hello world
使用 safe 过滤器关闭转义:<br/>
{{ content|safe }}<br/>

  和上面的safe一样,不过是多行safe
使用 autoescape 关闭转义:<br/>
{% autoescape off %}
{{ content }}
{{ content }}
{% endautoescape %}<br/>

  使用别的模板过滤器
模板硬编码中的字符串默认不会经过转义:<br/>
{{ test|default:'<h1>hello</h1>' }}<br/>
手动进行转义:<br/>
{{ test|default:'&lt;h1&gt;hello&lt;/h1&gt;' }

csrf攻击

CSRF 全拼为 Cross Site Request Forgery,译为跨站请求伪造。CSRF 指攻击者盗用了你的身份,以你的名义发送恶意请求。CSRF 能够做的事情包括:以你名义发送邮件,发消息,盗取你的账号,甚至于购买商品,虚拟货币转账… 造成的问题包括:个人隐私泄露以及财产安全。

举个小例子:我们前面提到了cookie以及session,那么就比如说我们浏览器正常访问一个银行页面,输入了账户密码登录之后,服务器就会使用cookie给我们发送一个sessionid,储存在我们的浏览器中,然后这种攻击就有可能会发生在,当我们访问一个不健康的网站,比如说黄色网站,我们点击其中的美女还是什么的图案,他实际上内置了超链接,超链接的对象是我们上面登录过的银行的网站的修改密码的url(好好理解一下,在引入ajax/axios的异步后,url分为实际上显示网页的 和 只执行相对应函数的),并且模拟发送修改密码的密码,那由于是我们浏览器点击的超链接,就直接进行了修改密码这项操作,这是很不安全的

那我们csrf的解决策略就是使用token,当我们打开一个页面的时候,他会给我们发送一个csrftoken
在这里插入图片描述
这边再重复一遍我们正常修改密码的流程和csrf修改的流程:

  1. 正常:我们先在/xiugai 上填写新密码,点击表单提交后,post提交到/xiugai_mima 进行数据库修改
  2. csrf: 直接利用cookie的性质向/xiugai_mima直接模拟发包,直接发送新的密码。

二者在我们用户的视角上都是不可见的(ajax/axios)

对比一下二者的区别,所以解决策略就是我们会在访问xiugai页面的时候发送一个token,当你修改的时候一样需要检测这个token,如果没有或者不一样,那么就无法进行修改,所以说token的生存周期就是关闭即没有。

使用方式:如下文{% csrf_token %},实际上就是,当我们提交表单到/change_pwd_action/的时候需要验证这个token

<form method="post" action="/change_pwd_action/">
{% csrf_token %}
新密码:<input type="password" name="pwd">
<input type="submit" value="确认修改">
</form>

效果就是:
在这里插入图片描述

防御原理:

  1. 渲染模板文件时在页面生成一个名字叫做 csrfmiddlewaretoken 的隐藏域。
  2. 服务器交给浏览器保存一个名字为 csrftoken 的 cookie 信息。
  3. 提交表单时,两个值都会发给服务器,服务器进行比对,如果一样,则 csrf验证通过,否则失败

反向解析

实际上就是我们在写好项目的时候,产品经理要求我们将一个页面的url进行修改,那我们直接去url视图下直接进行修改,然后把所有用到这一部分的地方都进行修改吗?很明显工程量太大了。

所以这边可以使用反向解析操作进行实现

整个方法的流程

先去url.py处进行起一个别名(假设原本这边是index)
path('index1',view.index,name='ooo')

反向解析
 # 后端反向解析
 	from django.urls import reverse
 	reverse('ooo') 这一个就是我们相对应的url
 # 前端进行反向解析
 	<a href="{% url 'ooo' %}">111</a>

补充 软件库下 url

实际上我们也可以在我们对应的软件库下写一个url.py 然后把url配置写在里面,最后再将这一部分导入到项目url当中,导入的函数:

path('',include(('booktest.urls','booktest'),namespace = 'booktest')

然后之后使用反向解析,就需要我们使用namespace:ooo,如例如{% url ‘booktest:ooo’ %}

所以见下面的例子,希望好好理解一下,这是带参数的反向解析例子:

前端反向解析(带参数)

html的使用

动态产生/show_args/1/2:<br/>
<a href="{% url 'booktest:show_args' 1 2 %}">/show_args/1/2</a><br/>

<a href="{% url 'booktest:show_kwargs' d=4 c=3 %}">/show_kwargs/3/4</a>

同时在 urls.py 中增加

path('show_args/<int:a>/<int:b>',views.show_args,name='show_args'),

path('show_kwargs/<int:c>/<int:d>',views.show_kwargs,name='show_kwargs'),

软件的view下:

def show_args(request, a, b):
	return HttpResponse(str(a) + ':' + str(b))
def show_kwargs(request, c, d):
	return HttpResponse(str(c) + ":" + str(d))

后端的反向解析(带参数)

from django.urls import reverse

# /test_redirect
def test_redirect(request):
	# 重定向到/index
	# return redirect('/index')
	# url = reverse('booktest:index')
	
	# 重定向到/show_args/1/2
	url = reverse('booktest:show_args', args=(1,2))	
	
	# 重定向到/show_kwargs/3/4
	# url = reverse('booktest:show_kwargs', kwargs = {'c': 3, 'd': 4})
	
	return redirect(url)

其他技术

见18 django框架(下)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/963536.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

面试中的商业思维:如何展示你对业务的理解

&#x1f337;&#x1f341; 博主猫头虎&#xff08;&#x1f405;&#x1f43e;&#xff09;带您 Go to New World✨&#x1f341; &#x1f984; 博客首页——&#x1f405;&#x1f43e;猫头虎的博客&#x1f390; &#x1f433; 《面试题大全专栏》 &#x1f995; 文章图文…

华为数通方向HCIP-DataCom H12-821题库(单选题:221-240)

第201题 BGP 协议用​​ beer default-route-advertise​​ 命令来给邻居发布缺省路由,那么以下关于本地 BGP 路由表变化的描述,正确的是哪一项? A、在本地 BGP 路由表中生成一条活跃的缺省路由并下发给路由表 B、在本地 BGP 路由表中生成一条不活跃的缺省路由,但不下发给…

WordPress(4)关于网站的背景图片更换

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 前言一、更改的位置1. 红色区域是要更换的随机的图片二、替换图片位置三.开启随机数量四.结束前言 提示:这里可以添加本文要记录的大概内容: 例如:随着人工智能的不断发展,机器学习这门技术也…

算法通过村第五关-队列和Hash青铜笔记|队列和Hash

文章目录 前言1. Hash基础1.1 Hash的概念和基本特征1.2 碰撞处理方法1.2.1 开放地址法1.1.2 链地址法 2. 队列的基础2.1 队列的概念和基本特征2.2 队列的实现 总结 前言 提示&#xff1a;幸福的秘密是尽量扩大自己的兴趣范围对感兴趣的人和物尽可能的友善 --波特兰罗素 谈完栈&…

【人工智能】—_深度神经网络、卷积神经网络(CNN)、多卷积核、全连接、池化

深度神经网络、卷积神经网络&#xff08;CNN&#xff09;、多卷积核、全连接、池化) 文章目录 深度神经网络、卷积神经网络&#xff08;CNN&#xff09;、多卷积核、全连接、池化)深度神经网络训练训练深度神经网络参数共享 卷积神经网络&#xff08;CNN&#xff09;卷积多卷积…

7.(Python数模)消防站的选址问题

Python解决消防站的选址问题 原文参考该博文 问题描述 源代码 import pulp # 导入 pulp 库# 主程序 def main():# 问题建模&#xff1a;"""决策变量&#xff1a;x(j) 0, 不选择第 j 个消防站x(j) 1, 选择第 j 个消防站, j1,8目标函数&#xff1a;min fx …

【C++心愿便利店】No.4---C++初谈类和对象

文章目录 前言一、面向过程和面向对象初步认识二、类的引用三、类的定义四、类的访问限定符及封装五、类的作用域六、类的实例化七、类对象模型八、this指针 前言 &#x1f467;个人主页&#xff1a;小沈YO. &#x1f61a;小编介绍&#xff1a;欢迎来到我的乱七八糟小星球&…

PVZ紫卡植物排名

前言 此文章为“植物大战僵尸”专栏中的第003刊&#xff08;2023年9月第一刊&#xff09;。 无名版中有很多紫卡植物&#xff0c;分别是忧郁菇、玉米加农炮、猫尾草、机枪射手、地刺王、冰西瓜投手、双子向日葵、吸金菇。 提示&#xff1a;双子向日葵&#xff08;向日葵的升…

300行代码,教你用Python写个飞机大战

闲赋在家&#xff0c;甚是无聊&#xff0c;便萌发了研究经典小游戏&#xff1a;飞机大战的念头&#xff0c;想必大家可能玩过微信的这款小游戏&#xff0c;给我的感觉是这款游戏怎么可以做得这么好呢&#xff0c;操作简单&#xff0c;容易上手&#xff0c;简直是“老少皆宜”啊…

2023-09-02 LeetCode每日一题(最多可以摧毁的敌人城堡数目)

2023-09-02每日一题 一、题目编号 2511. 最多可以摧毁的敌人城堡数目二、题目链接 点击跳转到题目位置 三、题目描述 给你一个长度为 n &#xff0c;下标从 0 开始的整数数组 forts &#xff0c;表示一些城堡。forts[i] 可以是 -1 &#xff0c;0 或者 1 &#xff0c;其中&…

Android 1.1 背景相关与系统架构分析

目录 1.1 背景相关与系统架构分析 分类 Android 基础入门教程 1.Android背景与当前的状况 2.Android系统特性与平台架构 系统特性&#xff1a; 平台架构图&#xff1a; 架构的简单理解&#xff1a; 3.本节小结&#xff1a; 1.1 背景相关与系统架构分析 分类 Android 基础…

C++ 分割字符串数据

使用stringstream流&#xff08;已验证&#xff09; 引入头文件 #include <sstream> 功能实现&#xff1a; string keyValue "WTH01#WTH02#WTH03#WTH04#WTH05" string keys[6] { "" }; stringstream is(keyValue); string temp; int index 0;…

stable diffusion实践操作-采样sample

系列文章目录 stable diffusion实践操作 文章目录 系列文章目录前言一、采样是什么&#xff1f;1.1 SD原理图1.2 SD中采样工作流程1.3 SD重复预测采样结果1.4 SD中采样方法列表1.4 SD中采样方法功能总结1.5 SD中常用采样方法 二、 SD中常用采样方法对比2.1 二次元-第一组2.1.…

YOLOv5训练自己的数据集并测试(以及踩坑记录)

YOLOv5是一个非常流行的图像识别框架&#xff0c;这里介绍一下使用YOLOv5给自己的数据集进行训练和测试 官方介绍文档&#xff1a;YOLOv5官方文档 基本流程&#xff1a; 下载必要的库和包&#xff0c;以及yolov5框架自制数据集&#xff1a;收集图像、视频数据&#xff0c;la…

从零开发JavaWeb入门项目--十天掌握

原文网址&#xff1a;从零开发JavaWeb入门项目--十天掌握_IT利刃出鞘的博客-CSDN博客 简介 这是一个靠谱的JavaWeb入门项目实战&#xff0c;名字叫蚂蚁爱购。从零开发项目&#xff0c;视频加文档&#xff0c;十天就能学会开发JavaWeb项目&#xff0c;教程路线是&#xff1a;搭…

Super Resolve Dynamic Scene from Continuous Spike Streams论文笔记

摘要 近期&#xff0c;脉冲相机在记录高动态场景中展示了其优越的潜力。不像传统相机将一个曝光时间内的视觉信息进行压缩成像&#xff0c;脉冲相机连续地输出二的脉冲流来记录动态场景&#xff0c;因此拥有极高的时间分辨率。而现有的脉冲相机重建方法主要集中在重建和脉冲相…

Windows 重新映射 CapsLock 大写锁定到 Ctrl

Windows 重新映射 CapsLock 大写锁定到 Ctrl 本要点中的这些方法适用于我的美国键盘布局。我不确定其他布局。如果出现问题&#xff0c;请恢复您的更改&#xff1b;删除您创建的注册表项&#xff08;并重新启动&#xff09;。 强烈推荐 方法5 ctrl2cap&#xff0c;因为不会影…

代码随想录第35天|860.柠檬水找零 , 406.根据身高重建队列(很多细节点注意一下),452. 用最少数量的箭引爆气球

860.柠檬水找零 思路比较简单 class Solution {public boolean lemonadeChange(int[] bills) {//然后向你付 5 美元、10 美元或 20 美元//如果收到5&#xff0c;直接收下//如果收到10&#xff0c;需要付回去5//如果收到20&#xff0c;需要付回去105或者555//开始时我手上拥有…

java基础-----第八篇

系列文章目录 文章目录 系列文章目录一、Java类加载器二、双亲委托模型 一、Java类加载器 JDK自带有三个类加载器&#xff1a;bootstrap ClassLoader、ExtClassLoader、AppClassLoader。 BootStrapClassLoader是ExtClassLoader的父类加载器&#xff0c;默认负责加载%JAVA_HOME…

Ops实践 | 国产化KylinOS系统中快速部署企业内部高性能DNS服务器、时间同步服务器 (精选)...

各位看友&#xff0c;由于微信公众号推送机制改变&#xff0c;现在需要设置为星标才能收到的本公众号推送消息哟。关注回复【学习交流群】加入【安全开发运维】答疑交流群 请朋友们【多多点击文中的广告】&#xff0c;支持作者更新更多文章。 目录: 本文为作者原创文章&#xf…