比如我想和我的某个同学去吃饭,但是我和他前面隔着好几排人,我要找到她,那我就得穿过这几排人
它叫防跨站请求伪造,之前很多同学刚初学Django,可能会直接把CSRF中间件给去掉,或者在表单上加个{% csrf_token %}
,但是原理是啥?其实我们可以用{ csrf_token }
在前端中显示一下,发现其实它就是一个字符串,当我们以get请求来访问服务器的时候,服务器不仅会返回内容,还会给我们一个加密的字符串,这个加密的字符串只有服务器能反解,客户端提交数据的时候,必须带着这个字符串过来,否则我就不给你提交。
就是防跨站请求伪造喽,用大白话说就是防止黑客往我们的表单上提交数据,加了CSRF后我们的表单上以及ajax方式提交都要做处理。
Django里面内置了paginator分页器,
from django.core.paginator import Paginator
object.all()
查询出一个queryset对象,def index(request):
# 批量导入
# book_list = []
# for i in range(100, 200):
# obj = models.Book(price=i*i, name='这是第'+str(i)+'本书')
# book_list.append(obj)
# models.Book.objects.bulk_create(book_list)
book_list = models.Book.objects.all()
paginator = Paginator(book_list, 10)
print('paginator count:',paginator.count)
print('num_page', paginator.num_pages)
print('page_range', paginator.page_range)
try:
current_page = int(request.GET.get('page', 1))
page = paginator.page(current_page)
# 如果页数十分多时,换另外一种显示方式
if paginator.num_pages > 10:
# 显示前五个页码
if current_page-5 < 1:
page_range = range(1, 11)
elif current_page+5 > paginator.num_pages:
page_range = range(paginator.num_pages-10, paginator.num_pages+1)
else:
page_range = range(current_page-5, current_page+5)
print('object_list:', page.object_list)
for i in page:
print(i)
except EmptyPage as e:
# 也会URL输错了,就回到第一页
page = paginator.page(1)
return render(request, 'index.html', locals())
index.html代码,因为注释很详细,我就不一一说了哈
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Titletitle>
<link rel="stylesheet" href="/static/bootstrap-3.3/css/bootstrap.css"/>
<link rel="stylesheet" href="/static/bootstrap-3.3/css/bootstrap-theme.css"/>
<style>
style>
head>
<body>
{% for item in page %}
{{ item.price }}-{{ item.name }}<br>
{% endfor %}
<nav aria-label="Page navigation">
<ul class="pagination">
{% if page.has_previous %}
<li>
<a href="?page={{ page.previous_page_number }}" aria-label="Previous">
<span aria-hidden="true">上一页span>
a>
li>
{% else %}
<li>
<a href="#" aria-label="Previous" class="disabled">
<span aria-hidden="true">上一页span>
a>
li>
{% endif %}
{% for item in page_range %}
{% if item == current_page %}
<li class="active"><a href="?page={{ item }}">{{ item }}a>li>
{% else %}
<li><a href="?page={{ item }}">{{ item }}a>li>
{% endif %}
{% endfor %}
{% if page.has_next %}
<li>
<a href="?page={{ page.next_page_number }}" aria-label="Next">
<span aria-hidden="true">下一页span>
a>
li>
{% else %}
<li>
<a href="#" aria-label="Next" class="disabled">
<span aria-hidden="true">下一页span>
a>
li>
{% endif %}
ul>
nav>
body>
html>
他是在浏览器和服务器中间的钩子,我们一个请求过来的时候,在到达view层之前,需要先穿过一系列的中间件,比如CSRF防护等等,然后在view层返回请求给浏览器的时候也要经过中间件,在Django1.10后的版本,当某个请求在一个中间件中被阻断的话(比如CSRF防护),它会从这个中间件返回,而不是继续穿过后面的中间件到达view函数,但是在Django早期的版本,请求过不了某个中间件的时候,它会一直走完最后一个中间件再往回走,反正不管怎样,被某个中间件阻断后都不会到达视图层。
中间件可以在请求到达view函数之前先对请求做一些操作,或者做一些安全策略,比如我们想过滤掉某些IP,不给这些IP访问,我们可以自己自定义一个中间件,同时,Django自带了很多的中间件,比如CSRF防护,请求必须先穿过这个保护屏障才能到达我们的view函数。
from django.utils.deprecation import MiddlewareMixin
class One(MiddlewareMixin):
def process_request(self, request):
print('我是第一层process_request')
def process_response(self, request, response):
print('我是第一层process_response')
return response
class Two(MiddlewareMixin):
def process_request(self, request):
print('我是第二层process_request')
def process_response(self, request, response):
print('我是第二层process_response')
return response
class Three(MiddlewareMixin):
def process_request(self, request):
print('我是第三层process_request')
def process_response(self, request, response):
print('我是第三层process_response')
return response
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
'm.diymiddle.One',
'm.diymiddle.Two',
'm.diymiddle.Three',
]
view层
def test(request):
print('i love django')
return HttpResponse('OK')
你用中间件做过什么?
因为我们的网站大部分是动态的 请求都会去数据进行相应的操作,如果程序访问量很大,耗时就会增加,这时候最简单的方法就是使用缓存,将view的返回值保存到内存里边,5分钟内再有人来访问就直接去Redis里面拿,或者去内存里边拿,然后再返回。
在很多的web框架都没有这东西,就Django有,缓存也特别简单,只要配置上就行。
Django里面的6种缓存方式:
@cache_page(10)
10表示超时时间为10秒,在要缓存的函数上用cache_page装饰一下{% load cache %}
Django是一个非常非常牛逼的框架,牛逼在它在很多地方都给我们留了一些钩子,Django中提供了信号调度,用于在框架执行操作时的解耦,通俗来讲,就是一些动作发生的时候,信号允许太特定的发送者去提醒一下接受者
信号的作用就大了
看一个新浪面试题:如果我想在每个数据库操作的时候都给他加一条日志,怎么做?
这时候,可能很多人想到装饰器,…之前…之后嘛,就是用装饰器,但是装饰器它的粒度不够细,所以答案是用Django的内置信号。