Django上下文处理器详解

什么是上下文处理器

上下文处理器是可以返回一些数据,在全局模板中都可以使用。比如登录后的用户信息,在很多页面中都需要使用,那么我们可以放在上下文处理器中,就没有必要在每个视图函数中都返回这个对象。

自定义上下文处理器

1. 上下文处理器的存放位置:

你可以根据这个上下文处理器是属于哪个app,然后在这个app中创建一个文件专门用来存储上下文处理器。比如context_processors.py。或者是你也可以专门创建一个Python包,用来存储所有的上下文处理器。

2. 编写上下文处理器:

在你定义的上下文处理器文件中,定义一个函数,这个函数只有一个request参数。这个函数中处理完自己的逻辑后,把需要返回给模板的数据,通过字典的形式返回。如果不需要返回任何数据,那么也 必须返回一个空的字典。

案例:在一个网站中,用户登录了之后需要我们需要在session中设置设置一个user_id的值为当前登录用户的id。然后每次用户访问一个页面时,我们就去获取一下user_id的值,如果获取到了,就认为是登录了,否则没有登录。

为什么要使用上下文处理器:

如果我们不使用上下文处理器的话,那么我们需要在每一个视图函数中都去获取一下session中的user_id,这就是一件很不爽的事情了,而如果我们定义了上下文处理器,那么我们就不需要每一个视图函数中都去获取session中user_id的值了,只需要在上下文处理器中去获取就是了。

在你的app目录下新建一个context_processors.py的文件,然后在里面编写我们的上下文处理器,也就是一个函数。

# 这个User是我自己的一个模型,这里可以改成你自己需要在前端获取的数据的模型
from .models import User

# 因为登录成功之后设置了session的user_id的值
# 所以我们直接获取sessionde中user_id的值来判断用户是否登录了
def front_user(request):
    user_id = request.session.get('user_id')
    context = {}
    if user_id:
        try:
            user = User.objects.get(pk=user_id)
            context['front_user'] = user  # 使用front_user是因为Django内置的会返回一个user,这样才不会产生混淆
        except:
            pass
    # 最后必须返回一个字典
    return context

编写好这个函数之后,我们还需要在settings.py中去将我们的上下文处理器添加进去。

在settings.py中找到TEMPLATES这个列表,然后添加我们自定义的上下文处理器。
Django上下文处理器详解

这样,我们就定义好了我们自己的上下文处理器。

定义好了我们的上下文处理器之后,我们就可以直接在前端使用了,在views中也不用编写相关的代码了。

Django内置的上下文处理器

settings.TEMPLATES.OPTIONS.context_processors中(也就是我们刚才添加上下文处理器的位置),有许多内置的上下文处理器。这些上下文处理器的作用如下:

  1. django.template.context_processors.debug:增加一个debug和sql_queries变量。在模板中可以通过他来查看到一些数据库查询。
  2. django.template.context_processors.request:增加一个request变量。这个request变量也就是在视图函数的第一个参数。正是因为有了这个上下文处理器,我们才能从request中获取数据。
  3. django.contrib.auth.context_processors.auth:Django有内置的用户系统,这个上下文处理器会增加一个user对象。所以刚才我们在自定义上下文处理器的时候,返回的对象我们取名为front_user而不是user
  4. django.contrib.messages.context_processors.messages:增加一个messages变量。可以通过它来存放一些我们需要返回的错误信息。
  5. django.template.context_processors.media:在模板中可以读取MEDIA_URL。比如想要在模板中使用上传的文件,那么这时候就需要使用settings.py中设置的MEDIA_URL来拼接url。首先在settings.py中添加两个参数
MEDIA_ROOT = os.path.join(BASE_DIR,'media')
MEDIA_URL = '/media/'

然后在app的同级目录下新建一个media的文件夹,我们在里面随便存放一张图片。

在主urls.py中添加映射

from django.urls import path,include

from django.conf.urls.static import static
from django.conf import settings

urlpatterns = [
    path('front/', include('front.urls')),
] + static(settings.MEDIA_URL,document_root=settings.MEDIA_ROOT)

那么接下来我们怎样才能在模板中获取我们存放的图片的完整路径呢?

这个时候我们就需要使用到media这个上下文处理器了。

首先我们在settings中将这个上下文处理器添加进去。

TEMPLATES = [
    {
        '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',

                # app名.上下文处理器的文件名.上下文处理器的函数名
                'front.context_processors.front_user',
                'django.template.context_processors.media',
            ],
            'builtins': [
                'django.templatetags.static',
            ]
        },
    },
]

然后我们在模板中添加一个img标签,来显示我们的图片。

<img src="{{ MEDIA_URL }}abc.jpg">

abc.jpg为我的复制过去的图片。
这样就能获取到我们的图片了,不清楚文件或图片上传的方法可以看一下我的这篇博客Django文件上传和图片上传

  1. django.template.context_processors.static:在模板中可以使用STATIC_URL。也就是css,js,images那些静态文件的使用。
  2. django.template.context_processors.csrf:在模板中可以使用csrf_token变量来生成一个csrf_token。因为django中默认是开启了csrf这个中间件,所以我们在前端写表单的时候都需要将{{ csrf_token }}添加进去。

想深入学习django的可以看一下这个视频:超详细讲解Django打造大型企业官网