# django 10
- 上下文处理器
- debug
- message
- 缓存
- django操作缓存 memcached
- session 放入memcached
上下文处理器
- 重点
- debug 后期开发 查看 代码 数据库查询是否有问题
- message 前端用户输入内容的错误信息 直接在页面上显示
上下文处理器是可以返回一些数据,在全局模板中都可以使用。比如登录后的用户信息,在很多页面中都需要使用,那么我们可以放在上下文处理器中,就没有必要在每个视图函数中都返回这个对象。
在settings.TEMPLATES.OPTIONS.context_processors中,有许多内置的上下文处理器。这些上下文处理器的作用如下:
-
django.template.context_processors.debug:增加一个debug和sql_queries变量。在模板中可以通过他来查看到一些数据库查询。现在 settings.py中设置 INTERNAL_IPS = ['127.0.0.1'] 在页面 上 {{debug}} 或者 {{sql_queries}} 首页 True ::::[{'sql': 'SELECT "front_user"."id", "front_user"."username", "front_user"."password", "front_user"."telephone" FROM "front_user"', 'time': '0.001'}] -
django.template.context_processors.request:增加一个request变量。这个request变量也就是在视图函数的第一个参数。 -
django.contrib.auth.context_processors.auth:Django有内置的用户系统,这个上下文处理器会增加一个user对象。 -
django.contrib.messages.context_processors.messages:增加一个messages变量。
level的四个级别 info debug Warnning erro如果想让 错误信息直接呈现在页面上 views.py from django.contrib import messages #先引入 class LoginView(View): def get(self,request): return render(request,'login.html') def post(self,request): form = LoginForm(request.POST) if form.is_valid(): username = form.cleaned_data.get('username') password = form.cleaned_data.get('password') user = User.objects.filter(username=username,password=password).first() if user: request.session['user_id'] = user.id #登录成功以后 将这个用户的id存到session return redirect(reverse('index')) else: print("用户名或者密码错误") # messages.add_message(request,messages.INFO,"用户名或者密码错误") messages.info(request, "用户名或者密码错误") #因为内置上下文处理器 上面方式效果一样 这是 用户名或者密码错误级别 return redirect(reverse('login')) 外边是 用户名 密码 不能少于6位 错误级别 这个最开始是交给 forms.py来做的 所以需要在里边 写一个 方法 else: # errors = form.errors.get_json_data() # #'username': [{'message': '用户名不能少于6位', 'code': 'min_length'}], 'password': [{'message': '密码不能少于6位', 'code': 'min_length'}]} # for messages1 in errors.values(): # #print(messages1) # #[{'message': '用户名不能少于6位', 'code': 'min_length'}] # #[{'message': '密码不能少于6位', 'code': 'min_length'}] # for messages_dict in messages1: # for key,value in messages_dict.items(): # if key == "message": # print(value) erros = form.get_errors() #这里调用的是 下面forms.py中的方法 for erro in erros: messages.info(request,erro) return redirect(reverse('login')) forms.py 最终我们只想输出 用户名不能少于 6位用户名不能少于6位 def get_errors(self): new_error = [] errors = self.errors.get_json_data() # 'username': [{'message': '用户名不能少于6位', 'code': 'min_length'}], 'password': [{'message': '密码不能少于6位', 'code': 'min_length'}]} for messages1 in errors.values(): # print(messages1) # [{'message': '用户名不能少于6位', 'code': 'min_length'}] # [{'message': '用户名不能少于6位', 'code': 'min_length'}] for messages_dict in messages1: for key, value in messages_dict.items(): if key == "message": new_error.append(value) return new_error 在 login.html 上 <ul> {% for message in messages %} <li>{{ message }}</li> {% endfor %} </ul> -
django.template.context_processors.media:在模板中可以读取 MEDIA_URL。比如想要在模板中使用上传的文件,那么这时候就需要使用settings.py中设置的MEDIA_URL来拼接url。示例代码如下:
1.在 settings.py OPTIONS 中 写入 'django.template.context_processors.media', 然后制定 MEDIA_ROOT = os.path.join(BASE_DIR,'medias') MEDIA_URL = '/medias/' urls.py 映射 from django.conf.urls.static import static from django.conf import settings urlpatterns = [ path('', views.index,name='index'), ]+ static(settings.MEDIA_URL,document_root=settings.MEDIA_ROOT) <img src="{{MEDIA_URL}}aa.png" /> -
django.template.context_processors.static:在模板中可以使用STATIC_URL。1.在 settings.py OPTIONS 中 写入 'django.template.context_processors.static', 然后制定 urls.py 映射 <img src="{{STATIC}}aa.png" /> -
django.template.context_processors.csrf:在模板中可以使用csrf_token变量来生成一个csrf token。如果表单 post请求 在 form标签里边 加入下面两个 两个效果都可以 {# <input type="hidden" name="csrfmiddlewaretoken" value="{{ csrf_token }}">#} {% csrf_token %} 如果 不是 表单 可以在 head 上面 加一个 {% block head %} <meta name="csrf-coken" content="{{ csrf_token }}"> {% endblock %} base页面上 得有 {% block head %} {% endblock %}
自定义上下文处理器:
有时候我们想要返回自己的数据。那么这时候我们可以自定义上下文处理器。自定义上下文处理器的步骤如下:
-
你可以根据这个上下文处理器是属于哪个
app,然后在这个app中创建一个文件专门用来存储上下文处理器。比如context_processors.py。或者是你也可以专门创建一个Python包,用来存储所有的上下文处理器。 -
在你定义的上下文处理器文件中,定义一个函数,这个函数只有一个request参数。这个函数中处理完自己的逻辑后,把需要返回给模板的数据,通过字典的形式返回。如果不需要返回任何数据,那么也必须返回一个空的字典。示例代码如下:
-
在settings.py下 让 系统识别你写的
context_processors.pyTEMPLATES = [ { 'BACKEND': 'django.template.backends.django.DjangoTemplates', 'DIRS': [os.path.join(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', 'front.context_processors.front_user' #这一步就是让context_processors 生效 ], }, }, ]from .models import User def frontuser(request): userid = request.session.get("userid") #从session中读取 userModel = models.FrontendUser.objects.filter(pk=userid).first()#根据 useid 从User表中查详细信息 if userModel: return {'frontuser':userModel} else: return {} ------------------------- from .models import User def front_user(request): userid = request.session.get('user_id') #从session中读取user_id context = {} if userid: try: user = User.objects.get(pk=userid) context['front_user'] = user except: pass return context 在 页面上 {% if front_user %} <li><a href="#">欢迎你,{{ front_user.username }}</a></li> <li><a href="#">注销</a></li> {% else %} <li><a href="{% url 'login' %}">登录</a></li> <li><a href="{% url 'register' %}">注册</a></li> {% endif %}
memcached
什么是memcached:
-
memcached之前是danga的一个项目,最早是为LiveJournal服务的,当初设计师为了加速LiveJournal访问速度而开发的,后来被很多大型项目采用。官网是www.danga.com或者是memcached.org。 -
Memcached是一个高性能的分布式的内存对象缓存系统,全世界有不少公司采用这个缓存项目来构建大负载的网站,来分担数据库的压力。Memcached是通过在内存里维护一个统一的巨大的hash表,memcached能存储各种各样的数据,包括图像、视频、文件、以及数据库检索的结果等。简单的说就是将数据调用到内存中,然后从内存中读取,从而大大提高读取速度。 - 哪些情况下适合使用
Memcached:存储验证码(图形验证码、短信验证码)、登录session等所有不是至关重要的数据。
安装和启动memcached:
-
windows:
- 安装:
memcached.exe -d install。 - 启动:
memcached.exe -d start。
- 安装:
-
linux(ubuntu):
-
安装:
sudo apt install memcached -
启动:
cd /usr/local/memcached/bin ./memcached -d start
-
-
可能出现的问题:
- 提示你没有权限:在打开cmd的时候,右键使用管理员身份运行。
- 提示缺少
pthreadGC2.dll文件:将pthreadGC2.dll文件拷贝到windows/System32. - 不要放在含有中文的路径下面。
-
启动
memcached:-
-d:这个参数是让memcached在后台运行。 & -
-m:指定占用多少内存。以M为单位,默认为64M。 -
-p:指定占用的端口。默认端口是11211。 -
-l:别的机器可以通过哪个ip地址连接到我这台服务器。如果是通过service memcached start的方式,那么只能通过本机连接。如果想要让别的机器连接,就必须设置-l 0.0.0.0。
如果想要使用以上参数来指定一些配置信息,那么不能使用
service memcached start,而应该使用/usr/bin/memcached的方式来运行。比如/usr/bin/memcached -u memcache -m 1024 -p 11222 start。 -
telnet操作memcached:
telnet ip地址 [11211]
-
添加数据:
-
set:-
语法:
set key flas(是否压缩) timeout value_length value -
示例:
set name 0 120 5 120秒为单位 5表示长度 hello STORED 存储成功 set kangbazi 0 60 7 asdfghjk CLIENT_ERROR bad data chunk #表示超出最大长度 ERROR 7 长度 7 要求只能输入7个字节 多 少 都出错
-
-
add:-
语法:
add key flas(0) timeout value_length value -
示例:
add python 0 60 7 如果 key python 不存在 那么 存入成功 qweasdz STORED add python 0 120 5 如果已经存在 key python 那么 存入失败 hello NOT_STOREDset和add的区别:add是只负责添加数据,不会去修改数据。如果添加的数据的key已经存在了,则添加失败,如果添加的key不存在,则添加成功。而set不同,如果memcached中不存在相同的key,则进行添加,如果存在,则替换。
-
-
-
获取数据:
-
语法:
get key -
示例:
get username get name python #也支持批量获取 VALUE name 0 5 hello VALUE python 0 6 qweasd END
-
-
删除数据:
-
语法:
delete key -
示例:
delete python DELETED 表示删除成功 -
flush_all:删除memcached中的所有数据。flush_all OK
-
-
查看
memcached的当前状态:- 语法:
stats。
- 语法:
-
memcached 自增 自减 指定的值
set num 0 120 2 10 保证key对应的value值 是int 类型 incr num 10 自增 20 decr num 1 自减 19
通过python操作memcached:
-
安装:
python-memcached:pip install python-memcached。 -
建立连接:
import memcache mc = memcache.Client(['127.0.0.1:11211','192.168.174.130:11211'],debug=True) -
设置数据:
mc.set('username','hello world',time=60*5) mc.set_multi({'email':'[email protected]','telphone':'111111'},time=60*5) -
获取数据:
mc.get('telphone') -
删除数据:
mc.delete('email') -
自增长:
mc.incr('read_count') -
自减少:
mc.decr('read_count')
memcached的安全性:
memcached的操作不需要任何用户名和密码,只需要知道memcached服务器的ip地址和端口号即可。因此memcached使用的时候尤其要注意他的安全性。这里提供两种安全的解决方案。分别来进行讲解:
-
使用
-l参数设置为只有本地可以连接:这种方式,就只能通过本机才能连接,别的机器都不能访问,可以达到最好的安全性。/usr/bin/memcached -l 127.0.0.1
-
使用防火墙,关闭
11211端口,外面也不能访问。
ufw enable # 开启防火墙
ufw disable # 关闭防火墙
ufw default deny # 防火墙以禁止的方式打开,默认是关闭那些没有开启的端口
ufw deny 端口号 # 关闭某个端口
ufw allow 端口号 # 开启某个端口
在Django中使用memcached:
首先需要在settings.py中配置好缓存:
CACHES = {
'default': {
'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache',
'LOCATION': '127.0.0.1:11211',
}
}
如果想要使用多台机器,那么可以在LOCATION指定多个连接,示例代码如下:
CACHES = {
'default': {
'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache',
'LOCATION': [
'172.19.26.240:11211',
'172.19.26.242:11211',
]
}
}
配置好memcached的缓存后,以后在代码中就可以使用以下代码来操作memcached了:
stats items 查看 memcached中所有的key
stats cachedump 1 0
stats cachedump item的id 0 表示所有的内容
from django.core.cache import cache
def index(request):
cache.set("username","kangbazi",180)
username = cache.get("username")
print(username)
return HttpResponse("index")
stats items
stats cachedump 1 0
ITEM :1:username [8 b; 297086766 s]
END
get :1:username
VALUE :1:username 16 8
kangbazi
END
需要注意的是,django在存储数据到memcached中的时候,不会将指定的key存储进去,而是会对key进行一些处理。比如会加一个前缀,会加一个版本号。如果想要自己加前缀,那么可以在settings.CACHES中添加KEY_FUNCTION参数:
CACHES = {
'default': {
'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache',
'LOCATION': '127.0.0.1:11211',
'KEY_FUNCTION': lambda key,prefix_key,version:"django:%s"%key
}
}
stats items
STAT items:1:number 2
STAT items:1:age 3054595952
STAT items:1:evicted 0
STAT items:1:evicted_nonzero 0
STAT items:1:evicted_time 0
STAT items:1:outofmemory 0
STAT items:1:tailrepairs 0
END
stats cachedump 1 0
ITEM shanghai:python1806 [6 b; 297086910 s]
ITEM :1:username [8 b; 297086766 s]
END
get shanghai:python1806
VALUE shanghai:python1806 16 6
zelinx
END
修改session的存储机制:下面这些 在 settings.py 中进行设置 session存储方式 很多 不止一种
最后一行 加入 SESSION_ENGINE = "django.contrib.sessions.backends.cached_db "
默认情况下,session数据是存储到数据库中的。当然也可以将session数据存储到其他地方。可以通过设置SESSION_ENGINE来更改session的存储位置,这个可以配置为以下几种方案:
-
django.contrib.sessions.backends.cached_db:在存储数据的时候,会将数据先存到缓存中,再存到数据库中。这样就可以保证万一缓存系统出现问题,session数据也不会丢失。在获取数据的时候,会先从缓存中获取,如果缓存中没有,那么就会从数据库中获取。在 settings.py中 写入下面两段内容 SESSION_ENGINE = "django.contrib.sessions.backends.cached_db " CACHES = { 'default': { 'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache', 'LOCATION': '127.0.0.1:11211', 'KEY_FUNCTION': lambda key,prefix_key,version:"django:%s"%key } } view.py def session_view(request): request.session['shanghai'] = "python" request.session['classid'] = '1806' # username = request.session.pop("username") # userid = request.session.pop("userid") # request.session.clear() # request.session.flush() username = request.session.get("shanghai") print(username) telnet 127.0.0.1 11211 先回车 stats items stats cachedump 5 0 get django:django.contrib.sessions.cached_dbeczyh9yvf9l89x4h71xrd9meyh155z00 获取session信息 -
django.contrib.sessions.backends.signed_cookies:将session信息加密后存储到浏览器的cookie中。这种方式要注意安全,建议设置SESSION_COOKIE_HTTPONLY=True,那么在浏览器中不能通过js来操作session数据,并且还需要对settings.py中的SECRET_KEY进行保密,因为一旦别人知道这个SECRET_KEY,那么就可以进行解密。另外还有就是在cookie中,存储的数据不能超过4k。