• 141.内置上下文处理器debug、request、auth、messages、media、static、csrf


    上下文处理器

    上下文处理器可以返回一些数据,在全局模板中都可以使用,比如登录后的用户数据,在很多页面中都需要使用,那么我们就可以方在上下文处理器中,就没有必要在每个视图中返回这个对象了。
    在settings.py.TEMPLATES.OPTIONS.context_processors中,有许多内置的上下文处理器,这些上下文处理器的作用如下:

    (1)django.template.context_processors.debug:增加一个debug和sql_queries变量,在模板中可以通过他来查看到一些数据库查询。

    查看一下debug函数的定义,示例代码如下:

    def debug(request):
        """
        Return context variables helpful for debugging.
        """
        context_extras = {}
        if settings.DEBUG and request.META.get('REMOTE_ADDR') in settings.INTERNAL_IPS:
            context_extras['debug'] = True
            from django.db import connections
            # Return a lazy reference that computes connection.queries on access,
            # to ensure it contains queries triggered after this function runs.
            context_extras['sql_queries'] = lazy(
                lambda: list(itertools.chain.from_iterable(connections[x].queries for x in connections)),
                list
            )
        return context_extras
    
    分析:首先会先判断debug是否为True,并且判断request.META.get('REMOTE_ADDR')是否在 settings.INTERNAL_IPS,因此,我们可以在settings.py中定义:INTERNAL_IPS = ['127.0.0.1'],如果两个都为True,就将定义的context_extras中的debug置为True,也对sql_queries做相应的操作。
    因此,我们可以在index视图函数中,执行一些sql语句,然后在模板中查看是否内置的django.template.context_processors.debug是否为模板添加了debug和sql_queries变量。
    def index(request):
    <!--index视图函数执行相关sql语句-->
        users = User.objects.all()
        # 使用all()方法得到QuerySet对象,并没有执行sql语句
        # 如果想要执行sql语句的话,可以通过遍历
        for user in users:
            print(user)
        return render(request,'static/index.html')
    
    在index.html模板中查看debug和sql_queries变量。
    {{ debug }}/{{ sql_queries }}
    
    之后在浏览器中,输入url就会显示出debug为True,并且也会显示出当前执行sql语句。

    (2)django.template.context_processors.request:增加一个request变量,这个request变量也就是在视图函数中传入的第一个参数。

    这个request对象就是之前我们说过的WSGIRequest对象,这个对象常用的属性都是只读的,我们可以根据request对象上的一些属性从客户端获取一些数据,示例代码如下:
    <!--在index.html模板中-->
    <!--比如我们可以使用request对象的path属性,获取服务器的完整“路径”,-->
    {{ request.path }}
    
    <!--获取浏览器中的所有cookie-->
    <p>{{ request.COOKIES }}</p>
    

    (3)django.contrib.auth.context_processors.auth:Django内置的用户系统,这个上下文处理器会增加一个auth对象。所以,我们在使用自定义的处理器的时候,一定不要为context[]中的key设置为user,否者的话,Django就不知道到底是哪个user了。查看auth函数的定义,示例代码如下:

    def auth(request):
        if hasattr(request, 'user'):
            user = request.user
        else:
            from django.contrib.auth.models import AnonymousUser
            user = AnonymousUser()
    
        return {
            'user': user,
            'perms': PermWrapper(user),
        }
    
    分析:如果用户在request中没有传递user,就从django.contrib.auth.models中导入AnonymousUser,实例化一个user对象。

    (4)django.contrib.messages.context_processors.messages:增加一个message变量。查看messages()函数的定义,示例代码如下:

    def messages(request):
        """
        Return a lazy 'messages' context variable as well as
        'DEFAULT_MESSAGE_LEVELS'.
        """
        return {
            'messages': get_messages(request),
            'DEFAULT_MESSAGE_LEVELS': DEFAULT_LEVELS,
        }
    
    (1).通过messages变量,我们可以返回给用户一些错误消息message和错误级别message.tags,可以通过from django.contrib import messages模块,可以利用messages模块上的add_messages()方法,为messages添加信息(包括提示、警告等)。而info()方法,可以为messages添加提示信息。示例代码如下:
     messages.add_message(request, messages.INFO, '用户名或密码输入有误')
     等同于:
     messages.info(request, '用户名或密码输入有误')
    
    (2). 在模板中就可以遍历错误信息,进行显示。
    <tr>
        <td></td>
        <td>
            <ul>
                {% for message in messages %}
                    <li>{{ message.tags }}{{ message }}</li>
                {% endfor %}
            </ul>
        </td>
    </tr>
    
    (3). 可以对错误信息进行简单的提取,在forms.py文件中,为表单类定义一个函数,示例代码如下:
        def get_errors(self):
            errors = super(SigninForm, self).errors.get_json_data()
            new_errors = []
            for messages in errors.values():
                    for message_dict in messages:
                        for key,value in message_dict.items():
                            if key == "message":
                                new_errors.append(value)
            return new_errors
    

    (5)django.template.context_processors.media:在模板中读取MEDIA_URL,比如想要在模板中使用上传的文件,那么这时候就需要使用settings.py中设置的MEDIA_URL来拼接url,示例代码如下:

    (1)在settings.py文件中配置:
    TEMPLATES = [
        {
            'BACKEND': 'django.template.backends.django.DjangoTemplates',
            'DIRS': [os.path.join(BASE_DIR, 'templates')]
            ,
            'APP_DIRS': True,
            'OPTIONS': {
                'context_processors': [
                <!--添加media上下文处理器-->
                    'django.template.context_processors.media',
                ],
            },
        },
    ]
    
    MEDIA_ROOT = [
        os.path.join(BASE_DIR, 'media')
    ]
    
    MEDIA_URL = '/media/'
    
    (2)在urls.py文件中,拼接media中上传的文件的url。
    from django.urls import path
    from front import views
    from front.views import Signup, Signin
    from django.conf.urls.static import static
    from django.conf import settings
    
    
    urlpatterns = [
        path('', views.index, name='index'),
        path('signin/', Signin.as_view(), name='signin'),
        path('signup/', Signup.as_view(), name='signup'),
    ] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
    
    (3)在模板中:
        <img src="{{ MEDIA_URL }}time.jpg" />
    

    不知道为什么老是会报错:TypeError: expected str, bytes or os.PathLike object, not list
    [18/Feb/2020 19:38:00] "GET /media/time.jpg HTTP/1.1" 500 83742,可是在media中有time.jpg啊? 怎么回事呢?

    (6)django.template.context_processors.static:在模板中使用STATIC_URL。

    django.template.context_processors.static和django.template.context_processors.media的用法相同。

    (7)django.template.context_processors.csrf:生成一个可以在模板中使用的csrf_token变量。示例代码如下:

    <form action="" method="post">
    <!--value可以使用中间件中提供的一个变量csrf_token-->
        <input type="hidden" name="csrfmiddlewaretoken" value="{{ csrf_token }}">
        <table>
            <tr>
                <td>用户名:</td>
                <td><input type="text" name="username"></td>
            </tr>
            <tr>
                <td>密码:</td>
                <td><input type="password" name="password"></td>
            </tr>
            <tr>
                <td>确认密码:</td>
                <td><input type="password" name="password_repeat"></td>
            </tr>
            <tr>
                <td>手机号:</td>
                <td><input type="text" name="telephone"></td>
            </tr>
            <tr>
                <td></td>
                <td><input type="submit" value="提交"></td>
            </tr>
        </table>
    </form>
    
    并且需要在settings.py文件中的TEMPLATES->OPTIONS->context_processors中添加“django.template.context_processors.csrf”,此时在向网站中提交数据时,就不会出现csrf禁止了。

    如果是在模板中需要使用csrf_token变量,我们可以使用{% csrf_token %}标签来生成一个csrf_token的input标签(可以通过查看网页源代码查看),这样同样可以达到相同的效果。而不需要再配置settings.py文件中的csrf的上下文处理器,并且在form表单提交表单内容之前,手动添加一个csrf的input标签。

    始于才华,忠于颜值;每件事情在成功之前,看起来都是天方夜谭。一无所有,就是无所不能。
  • 相关阅读:
    java selenium (九) 常见web UI 元素操作 及API使用
    java selenium (六) XPath 定位
    java selenium (八) Selenium IDE 用法
    java selenium (五) 元素定位大全
    一个使用CSocket类的网络通信实例
    揭开链接器的面纱(中)
    揭开连接器的面纱(上)
    深入理解程序的结构
    调试利器GDB(下)
    调试利器GDB(上)
  • 原文地址:https://www.cnblogs.com/guyan-2020/p/12354700.html
Copyright © 2020-2023  润新知