上下文处理器主要是处理一些需要统一返回的变量,例如,我们常见的导航栏中用户登录之后,不论是哪个页面都是返回同样的变量用户名
这个功能看着还是很简单的,但是在django项目中,我们传递的变量是通过视图层函数中的context经过render传递到相对应的前端模板html中,假设没有上下文处理器,那么我们的做法是需要在每一个对应的视图函数中都携带上对应的context。
例如上方图片中,当我点击个人简介的页面时,右上角的用户名称就消失了,因为在base.html中定义的my_user.username变量只存在于首页视图函数index中,而在profile视图函数中,我们根本就没有传my_user这个变量,所以肯定是取不到正确的变量名的。
# views.py
def index(req):
context = {}
try:
user_login_id = req.session.get('user_id')
my_user = MyUser.objects.filter(pk = user_login_id).first()
context['my_user'] = my_user
except:
pass
return render(req, 'index.html', context = context)
def profile(req):
return render(req, 'profile.html')
而如果我们每一个视图函数都去重复index函数中的判断,实在过于繁琐,所以django可以定义上下文处理器来帮我们处理统一的变量。
自定义上下文处理器的步骤是首先在app下新建context_processor.py,定义自己的函数(第一个参数必须是request),返回值必须是字典,即使是一个空字典。
# context_processor.py
from .models import MyUser
def getUserInfo(req):
context = {}
try:
user_login_id = req.session.get('user_id')
my_user = MyUser.objects.filter(pk = user_login_id).first()
context['my_user'] = my_user
except:
pass
return context
然后在settings.py中定义上下文处理的位置,这样无论是哪个前端模板,都不需要通过视图函数传递就能够获取到my_user这个变量了
django内置的上下文处理器
debug,按照下面在配置文件中设置INTERNAL_IPS,并在前端模板中测试sql_queries和debug参数
request,和视图层的request一样,只不过前端页面无法使用圆括号来传入参数,例如request.session.get('username')是无效的。
auth,Django内置的用户系统,返回用户和权限。
messages,增加一个messages变量。视图层函数如果想要使用需要从django.contrib导出,它可以在前端页面中直接显示出我们想要传递的信息。例如我在视图函数中利用messages.info将一条消息插入到messages列表中
# views.py
class SignIn(View):
...
def post(self, req):
....
messages.info(req, message='user is not exists!')
return redirect(reverse('front:signin'))
....
关于视图函数中messages的用法,我们可以看看底层源码,主要方法是add_message,类似messages.info这类方法只不过是对add_message的封装。
前端页面中,可以直接利用messages将这个变量值输出,那么当用户输入错误的密码,直接就可以在页面中进行提示
除了OPTIONS中展示的四种上下文处理器,我们也可以进入到context_processors去看下其它内置上下文处理器,例如csrf,static,media等,需要注意的是这几个路径在django.template.context_processors下面。
media,在settings.py中我们设置了MEDIA_ROOT 和MEDIA_URL ,并在urls.py中配置static路径,那么此时我们就可以设定文件的上传路径和访问路径,那么如何通过在前端页面中动态的获取某个文件或者图片的链接呢?只要在前端页面中通过{{MEDIA_URL}}就可以获得配置文件中的路径。
csrf,Cross-site request forgery,为了防止跨站请求伪造,Django中表单的提交必须要携带csrf_token,有两种方法,一种是前端页面中直接使用{% csrf_token %},另外一种是自己建立input标签传递csrf_token,这种主要应用于在非表单中需要提交csrf_token。
<input type="hidden" name='csrfmiddlewaretoken' value='{{csrf_token}}'>
而且,我发现Django3.1无须再在配置文件的OPTIONS中增加csrf上下文处理器也可以在前端页面中取到csrf_token。