定义:缓存是一类可以更快的读取数据的介质统称,也指其它可以加快数据读取的存储方式。一般用来存储临时数据,常用介质的是读取速度很快的内存
意义:视图渲染有一定成本,数据库的频繁查询过高,对于低频变得的页面可以考虑使用缓存技术,减少实际渲染次数,用户拿到响应的时间成本会更低
1,博客列表页
2,电商商品详情页
场景特点:缓存的地方,数据变动频率较少
Django中设置缓存–数据库缓存
说明:尽管存储介质没有更换,但当把一次负责查询的结果直接存储到表里,如果多个条件的过滤查询结果,可避免重复进行复杂查询,提升效率;
Django中设置缓存–本地内存缓存
Django中设置缓存–文件系统缓存
Django中使用缓存—视图函数中
样例:
from django.views.decorators.cache import cache_page
@cache_page(30) -->单位s
def my_view(request):
...
Django中使用缓存—路由中
样例:
from django.views.decorators.cache import cache_page
utlpattrens = [
path('foo/',cache_page(60)(my_view)),
]
方式1:使用caches[‘CACHE配置key’]导入具体对象
from django.core.cache import caches #自带
cache1 = caches['myalias']
cache2 = caches['myalias_2']
方式2:from django.core.cache import cache 相当于直接引入CACHES配置项中的’default’项
缓存api的使用
1)cache.set(key,value,timeout) -存储缓存 key:缓存的key,字符串类型 value:Python对象
timeout:缓存存储时间(s),默认为CACHES中的TIMEOUT值 返回值:None
2)cache.get(key) -获取缓存 key:缓存的key 返回值:为key的具体值,如果没有数据,则返回None
3)cache.add(key,value) -存储缓存,只在key不存在时,生效 返回值:True【存储成功】or False【存储失败】
4)cache.get_or_set(key,value,timeout) --如果未获取到数据 则执行set操作 返回值:value
5)cache.set_many(dict,timeout) --批量存储缓存 dict:key 和value的字典 timeout:存储时间(s) 返回值:插入不成功的key的数组
6)cache.get_many(key_list) -批量获取缓存数据 key_list:包含key的数组 返回值:取到的key和value的字典
7)cache.delete(key) -删除key的缓存数据 返回值:None
8)cache.delete_many(key_list) -批量删除 返回值:None
不会项服务器发送请求,直接从缓存中读取资源
1)响应头-Expires 定义:缓存过期时间,用来指定资源到期的时间,是服务器端的具体的时间点
样例:Expires:Thu,02 Apr 2030 05:14:09 GTM
2)响应头 -Cache-Control 在HTTP/1.1中,Cache-Control主要用于控制网页缓存。比如当‘Cache-Control:max-age=120’代表请求创建时间后的120秒,缓存失效。
说明:目前服务器都会带着这两个头,同时响应给浏览器,浏览器有限使用Cache-Control
浏览器缓存–协商缓存
强缓存中的数据一旦过期,还需要跟服务器进行通信,从而获取最新数据
思考:如果强缓存的数据是一些静态文件,大图片等
解答:考虑到大图片这类比较费宽带且不易变化的数据,强缓存时间到期后,浏览器会去跟服务器协商,当前缓存是否可用,如果可用,服务器不必返回数据,浏览器继续使用原来缓存的数据,如果问津不可用,则返回最新数据
1)Last-Modified响应头和If-Modified-Since请求头
说明:
Last-Modified为文件的最近修改时间,浏览器第一次请求静态文件时,服务器如果返回Last-Modified响应头,则代表该资源为需协商的缓存
当缓存到期后,浏览器将获取到的Last-Modified值做为请求头If-Modified-Since的值,与服务器发出请求协商,服务端返回304响应码【响应体为空】,代表缓存继续使用,200响应码代表缓存不可用【响应体为最新资源】
2)ETag响应头和If-None-Match请求头
说明:
Etag是服务器响应请求时,返回当前资源文件的一个唯一标示(由服务器生成),只要资源由变化,Etag就会重新生成
缓存到期后,浏览器将ETag响应头的值作为If-None-Match请求头的值,给服务器发请求协商;服务器接到请求头后,比对文件标示,不一致则认为资源不可用,返回200响应码【响应体为最新资源】;可用则返回304响应码。
定义:中间件是Django请求/响应处理的钩子框架。它是一个轻量级的、低级的“插件”系统,用于全局改变Django的输入或输出。
中间件以类的形式体现
每个中间件组件负责做一些特定的功能。例如,django包含一个中间件组件AuthenticationMiddleware,它使用会话将用户与请求关联起来。
编写中间件
中间件类必须继承自django.utils.deprecation.MiddlewareMixin类
中间件类必须实现下列五个方法中的一个或多个:
process_request(self,request) 执行路由之前被调用,在每个请求上调用,返回None或HttpResponse对象
**process_view(self,request,callback,callback_args,callback_kwargs)**调用视图之前被调用,在每个请求上调用,返回None或HttpResponse对象
process_response(self,request,response) 所有响应返回浏览器,被调用,在每个请求上调用,返回HttpResponse对象
process_exception(self,request,exception) 当处理过程中抛出异常时调用,返回一个HttpResponse对象
process_template_response(self,request,response) 在视图函数执行完毕且返回的对象中包含render方法时被调用,该方法需要返回实现了render方法的响应对象。
注:中间件中的大多数方法在返回None时,表示忽略当前操作进入下一项事件,当返回HttpResponse对象时表示此请求结束,直接返回给客户端
注册中间件
settings.py中需要注册一下自定义的中间件
# file:settings.py
MIDDLEWARE = [
...
]
注意:配置为数组,中间件被调用时,以’先上到下‘再’由下到上‘的顺序调用
#新建middleware包,mymiddleware.py
from django.utils.deprecation import MiddlewareMixin
class MyMW(MiddlewareMixin):
def process_request(self, request):
print('MyMW process_request do ---')
def process_view(self, request, callback, callback_args, callback_kwargs):
print('MyMW process_views do ---')
def process_response(self, request, response):
print('MyMW process_response do ---')
return response
setting.py
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',
'middleware.mymiddleware.MyMW', #添加自定义中间件
]
views.py
from django.http import HttpResponse
def test_mw(request):
print('---test_mw view in ---')
return HttpResponse('--test-mw---')
urls.py
from django.contrib import admin
from django.urls import path
from . import views
urlpatterns = [
path('admin/', admin.site.urls),
path('test_mw', views.test_mw),
]
from django.http import HttpResponse
from django.utils.deprecation import MiddlewareMixin
import re
class MyMW(MiddlewareMixin):
def process_request(self, request):
print('MyMW process_request do ---')
def process_view(self, request, callback, callback_args, callback_kwargs):
print('MyMW process_views do ---')
def process_response(self, request, response):
print('MyMW process_response do ---')
return response
class MyMW2(MiddlewareMixin):
def process_request(self, request):
print('MyMW2 process_request do ---')
def process_view(self, request, callback, callback_args, callback_kwargs):
print('MyMW2 process_views do ---')
def process_response(self, request, response):
print('MyMW2 process_response do ---')
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',
'middleware.mymiddleware.MyMW',
'middleware.mymiddleware.MyMW2',
#'middleware.mymiddleware.VisitLimit',
]
再去执行def test_mw(request):调用(刷新页面)注意:执行顺序
mysite7\middleware\mymiddleware.py
from django.http import HttpResponse
from django.utils.deprecation import MiddlewareMixin
import re
class VisitLimit(MiddlewareMixin):
visit_times = {
}
def process_request(self, request):
ip_address = request.META['REMOTE_ADDR'] # 获取访问者ip
path_url = request.path_info # 获取url
if not re.match('^/test', path_url):
return
times = self.visit_times.get(ip_address, 0) # 如果没get到数据,赋值0
print('ip', ip_address, '已经访问', times)
self.visit_times[ip_address] = times + 1
if times < 5:
return
return HttpResponse('您已经访问过' + str(times) + '次, 访问被禁止')
CSRF-跨站伪造请求攻击:某些恶意网站上包含链接、表单按钮或者JavaScript,它们会利用登录过的用户在浏览器中的认证信息试图在你的网站上完成某些操作,这就是跨站请求伪造(CSRF,即Cross-Site Request Forgey)。
CSRF防范:django采用’对比暗号‘机制,防范攻击。Cookies中存储暗号1,模板中,表单中藏着暗号2,用户只有在本网站下提交数据,暗号2才会随着表单提交给服务器,django对比两个暗号,对比成功,则认为是合法请求,否则是违法请求-403响应码
配置步骤:
1、settings.py中确认MIDDLEWARE中django.middleware.csrf.CsrfViewMiddleware是否打开
2、模板中,form标签下添加如下标签 {% csrf_token %}
views.py
def test_csrf(request):
if request.method == 'GET':
return render(request, 'test_csrf.html')
elif request.method == 'POST':
return HttpResponse('---test post is ok---')
urls.py
path('test_csrf', views.test_csrf),
templates\test_csrf.html
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Titletitle>
head>
<body>
<form action="/test_csrf" method="post">
{% csrf_token %}
<input type="text" name="username">
<input type="submit" value="提交">
form>
body>
html>
特殊说明:
如果某个视图不需要django进行csrf保护,可以用装饰器关闭对此视图的检查。样例:
from django.views.decorators.csrf import csrf_exempt
@csrf_exempt
def my_view(request):
return HttpResponse('Hello world')
csv文件定义:逗号分隔值(Comma-Separated Values,CSV,有时也称为字符分隔值,因为分隔字符也可以不是逗号),其文件以纯文本形式存储表格数据(数字和文本)
说明:可被常见制表工具,如excel等直接进行读取
python中生成csv文件
python提供了内建库-csv;可直接通过该库操作csv文件,案例如下:
import csv
with open('eggs,csv','w',newline='') as csvfile:
writer = csv.writer(csvfile)
writer.writerow(['a','b','c'])
w_csv.py
import csv
with open('test_csv.csv','w', newline='') as csvfile:
writer = csv.writer(csvfile)
writer.writerow(['a', 'b', 'c'])
writer.writerow(['d', 'e'])
在网站中,实现下载csv,注意如下:
响应Content-Type类型需要修改为text/csv。这告诉浏览器该文档是CSV文件,而不是HTML文件
响应会获得一个额外的Content-Disposition标头,其中包含CSV文件的名称。它将被浏览器用于开启“另存为…”对话框
views.py
def test_csv(request):
response = HttpResponse(content_type='text/csv')
response['Content-Disposition'] = 'attachment;filename="test.csv"'
all_data = ['a', 'b', 'c', 'd']
writer = csv.writer(response)
writer.writerow(all_data)
return response
urls.py
path('test_csv', views.test_csv),
views.py
import csv
from django,http import HttpResponse
from .models import Book
def make_csv_view(request):
response = HttpResponse(content_type='text/csv')
response['Content-Disposition'] = 'attachment;filename="mybook.csv"'
all_book = Book.objects.all()
writer = csv.writer(response)
writer.writerow(['id', 'title'])
for b in all_book:
writer.writerow([b.id, b.title])
return response
urls.py
path('make_csv_view', views.make_csv_view),
概念:项目部署是指在软件开发完毕后,将开发机器上运行的软件实际安装到服务器上进行长期运行
1、在安装机器上安装和配置相同版本的环境【py,数据库等】
2、django项目迁移(下面代码,参考)
sudo scp /home/tarena/django/mysitel
root@88.77.66.55:/home/root/xxx
请输入root密码:
3、用uWSGI代替python3 manage.py renserver方法启动服务器
WSGI(Web Server Gateway Interface)Web服务器网关接口,是Python应用程序或框架和Web服务器之间的一种接口,被广泛使用。使用python manage.py runserver通常只在开发和测试环境中使用。当开发结束后,完善的项目代码需要在一个高效稳定的环境中运行,这时候可以使用WSGI
uWSGI是WSGI的一种,它实现了http协议,WSGI协议以及uwsgi协议。uWSGI功能完善,支持协议众多,在pyhton web圈热度极高
uWSGI主要学习配置为主,uWSGI安装:Ubuntu执行
sudo pip3 install uwsgi==2.0.18
检查是否安装成功:
sudo pip3 freeze|grep -i 'uwsgi' # 如果成功安装,会输出uWSGI==2.0.18
配置uWSGI
添加配置文件 项目同名文件夹/uwsgi.ini 如:mysite1/mysite1/uwsgi.ini
文件以[uwsgi]开头,有如下配置项:
套接字方式的IP地址:端口号 【此模式需要有nginx】 socket=127.0.0.1:8000
Http通信方式的IP地址:端口号 http=127.0.0.1:8000
项目当前工作目录:chdir=/home/tarena/tedu/vip/day08/mysite7
项目中wsgi.py文件的目录,相对于当前的工作目录:wsgi-file=mysite7/wsgi.py
进程个数:process=4
每个进程的线程个数:threads=2
服务的pid记录文件 :pidfile=uwsgi.pid
服务的日记文件位置:daemonize=uwsgi.log
开启主进程管理模式:master=True
uwsgi.ini
[uwsgi]
http=192.168.42.128:8000
chdir=/home/pyvip/df17_pro/django_pro
wsgi-file=django_pro/wsgi.py
process=4
threads=2
pidfile=uwsgi.pid
daemonize=uwsgi.log
master=True
# 指定虚拟环境所在目录,不能填相对目录,如果不指定,会找不到django
virtualenv=/home/pyvip/.virtualenvs/df17
特殊说明:Django的settings.py需要做如下配置
。修改settings.py将DEBUG=True改为DEBUG=False
。修改settings.py将ALLOWED_HOSTS=[]改为ALLOWED_HOSTS=[‘网站域名’]或者[‘服务监听的ip地址’]
启动uwsgi :cd 到uWSGI配置文件所在目录 执行:uwsgi --ini uwsgi.ini 停止:uwsgi – stop uwsgi.pid
查看启动状况:
无论是启动还是关闭,都需要执行ps aux|grep 'uwsgi’确认是否符合预期。启动成功后,进程在后台执行,所有日志均输出在配置文件所在目录的uwsgi.log中。Django中任何代码修改,需要重新启动uwsgi
在浏览器端输入 http://127.0.0.1:8000/url进行测试
注意:此时端口8000被uWSGI进程监听,并非runserver,如果当前有预期返回,则uWSGI启动成功
uWSGI常见问题汇总
1)启动失败:端口被占用
原因:有其它进程占用uWSGI启动的端口;解决方案:可执行 sudo lsof -i:端口号 查询出具体进程;杀掉进程后,重启uWSGI即可
2)停止失败:stop无法关闭uWSGI
原因:重复启动uWSGI,导致pid文件中的进程号失准 解决方案:ps出uWSGI进程,手动kill掉
通过 cat Usagi.pid 查看端口号
sudo kill -9 端口号
4、配置nginx反向代理服务器
什么是nginx?是轻量级的高性能web服务器,提供了诸如HTTP代理和反向代理、负载均衡等一系列重要特性。c语言编写,执行效率高。
作用:负载均衡,多台服务器轮流处理请求,反向代理
原理:客户端请求nginx,再由nginx将请求转发uWSGI运行的django
安装:sudo apt install nginx
如果下载速度慢,考虑更换为国内源
vim /etc/apt/sources.list # 更改国内源
sudo apt-get update
安装完毕后,ubuntu终端中 输入nginx -v 显示版本号
修改nginx的配置文件/etc/nginx/sites-enabled/default; sudo vim该文件
#在server节点下添加新的location项,指向uwsgi的ip与端口
server {
...
# 静态文件
location /static {
alias /home/pyvip/projects/aerf_mall/aerf/aerf/static/frontend/;
}
location /{
...
uwsgi_pass 192.168.42.128:8000; # 重定向到192.168.42.128的8000端口
include /etc/nginx/uwsgi_params; # 将所有的参数转到uwsgi下
}
...
}
vim修改后可以使用命令:sudo nginx -t 测试修改后的nginx有没有问题
启动和停止nginx
$sudo /etc/init.d/nginx start|stop|restart|status
#或
$sudo service nginx start|stop|restart|status
(py3env) pyvip@VIP:/etc/nginx/sites-enabled$ sudo service nginx restart
(py3env) pyvip@VIP:/etc/nginx/sites-enabled$ sudo nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
注意:nginx配置只要修改,就需要进行重启,否则配置不生效
修改uWSGI配置:说明nginx负责接受请求,并把请求转发给后面的uWSGI。此模式下,UWSGI需要以socket模式启动。样例:
[uwsgi]
#http=192.168.42.128:8000
socket=192.168.42.128:8000
chdir=/home/pyvip/df17_pro/django_pro
wsgi-file=django_pro/wsgi.py
process=4
threads=2
pidfile=uwsgi.pid
daemonize=uwsgi.log
master=True
# 指定虚拟环境所在目录,不能填相对目录,如果不指定,会找不到django
virtualenv=/home/pyvip/.virtualenvs/df17
修改uWSGI配置后,也需要重启
5、用nginx配置静态文件路径,解决静态路径问题
在Django settings.py 中添加新配置
STATIC_ROOT = os.path.join(BASE_DIR, 'static') #用于网站的静态文件
# 注意 此配置路径为:存放所有正式环境中需要的静态文件