Django 规范编程5

Task12 表和模板入门

我们都知道,Django的数据要渲染到网页中离不开Template模板的使用。Template 呈现给用户的界面, 实现MVT中的MT的解耦:

  • V视图函数可以渲染(使用)多个模板
  • 一个模板 T 可以呗任意的V 视图函数使用

模板处理的过程:

  • 加载指定的html文件

  • 使用django.template.loader 模板加载对象进行html的加载

    template = loader.get_template('index.html')
    
  • 以context设置的数据,处理html文件模板的语句和变量,生成html内容(渲染)

    html = template.render(context) # context是一个dict对象
    
  • 或者用template.reader() 同时加载与渲染

    html = loader.render_to_string('index.html',context)
    

模板的意义:在多次使用莫格Html时可以将其存放在内存中直接用HttpReponse封装而非return render返回加快响应解析速度。

eg.

# views.py
def show_Games(request: HttpRequest):
    games = Gammer.objects.all().values()
    # 加载模板,这一步的数据可以放在缓存/redis中提高效率
    moban = loader.get_template('game_show.html')
    print(games)
    moban_xuanran = moban.render(context=locals())
    return HttpResponse(moban_xuanran)

在这里插入图片描述

(数据瞎写的,轻喷)

当然,模板(语言)本身也是一门学问,首先是官网镇楼:https://docs.djangoproject.com/zh-hans/4.0/ref/templates/language/

例如:点语法:{{a.b}} 解析的时候会按照 字典->类的属性-> 数组/元组/Set等有序集合的索引值一步一步解析查找, 都是很简单的,或多或少接触过的,有需要现查也来得及

Tips: 使用模板的注释({ # 单行注释 #}) ({% comment %}多行注释 {% endcomment %})并不会在渲染前端时被渲染。前端本身的注释用f12是可以查到的而注释器注释没有办法查到。

在这里插入图片描述

Task12.1 js CSS静态文件
#在主项目的settings中加上 staticfiles_Dirs 其中加上static资源目录
STATICFILES_DIRS = [
    os.path.join(BASE_DIR, 'static')
]
Task13 自定义过滤器

Django不想flask一样可以很轻松的在HTML中写Python, (虽然也和类Python没差) 主要要有语法和过滤器两大重点。上面我们已经给了基本的语法截图,接下来介绍一下过滤器

过滤器主要工作就是规范化数据格式或者做一些判断操作,写法一般如下:

{{ 变量 | 过滤器操作 过滤器参数}}

本身都是规则简单明了的东西,到时候现用先找就行,我放一个随随便便的网址https://www.cnblogs.com/Deaseyy/p/10859893.html

众所周知,我们想要自定义过滤器,我们就要去读它的源码去参考着写,我直接放一个add的源码,之后又发现过滤器竟然分String操作和不是String操作的,那再放一个String操作的源码

from .library import Library
# 过滤器声明函数,用的libuary包(django.template.libruary.Libruary)
register = Library()


# 注册是否为过滤器
@register.filter(is_safe=False)
# 参数
def add(value, arg):
    """Add the arg to the value."""
    try:
        return int(value) + int(arg)
    except (ValueError, TypeError):
        try:
            return value + arg
        except Exception:
            return ""

# 首字母大写过滤器
@register.filter(is_safe=True)
# @stringfilter可以将传入的参数先转换成字符串
@stringfilter
def capfirst(value):
    """Capitalize the first character of the value."""
    return value and value[0].upper() + value[1:]

看完了源码,我们知道一个过滤器至少要:

  • 在Libruary注册
  • 有自己的返回值。Ok我们已经可已完成一个过滤器了
# 在app目录下新建templatetags目录,将自定义的filter文件放置到此目录下
# try_filter
from django.template.library import Library

register = Library()


@register.filter(name='numtobin')
# 写一个数据转n进制的过滤器
def numtobin(value):
    m = bin(int(value))
    m = str(m)[2:]
    return m

# html
{%  load try_filter %}
<h1>{{ num | numtobin }}</h1>

# views
def test_filter(request: HttpRequest):
    htmls = loader.render_to_string('test_filter.html', {'num': 20})
    print(htmls)
    return HttpResponse(htmls)

# test结果
<h1>10100</h1>

至于为什么文件需要这么建,我正在翻源码ing…翻到🤮也没翻出来

好吧我们参考官方的文档吧,毕竟写这玩应的人一定知道为什么,我们先放上官网连接

https://docs.djangoproject.com/zh-hans/4.0/howto/custom-template-tags/

Task14 CSRF防御

CSRF(Cross-site request forgery) 熟悉XSS可以直接跳狼了,CSRF主要是防Cookie伪造的,各种高频Ip伪造的啊,都差不多,用token来验证了身份的真实性

Django中间件: 用于封装网络数据流, socket操作与协议栈,模板渲染等等。Django中间件是一很复杂的东西,想要搞懂还是要时间的,比如说运行时候的钩子函数等等(我学到再放上来https://www.cnblogs.com/8080zh/p/11164277.html)

这里我们先描述跟CSRF中间件

在这里插入图片描述

没错,又是源码的show time:

class CsrfViewMiddleware(MiddlewareMixin):
    """
    Require a present and correct csrfmiddlewaretoken for POST requests that
    have a CSRF cookie, and set an outgoing CSRF cookie.

    This middleware should be used in conjunction with the {% csrf_token %}
    template tag.
    """

    @cached_property
    def csrf_trusted_origins_hosts(self):
        return [
            urlparse(origin).netloc.lstrip("*")
            for origin in settings.CSRF_TRUSTED_ORIGINS
        ]

    @cached_property
    def allowed_origins_exact(self):
        return {origin for origin in settings.CSRF_TRUSTED_ORIGINS if "*" not in origin}

    @cached_property
    def allowed_origin_subdomains(self):
        """
        A mapping of allowed schemes to list of allowed netlocs, where all
        subdomains of the netloc are allowed.
        """
        allowed_origin_subdomains = defaultdict(list)
        for parsed in (
            urlparse(origin)
            for origin in settings.CSRF_TRUSTED_ORIGINS
            if "*" in origin
        ):
            allowed_origin_subdomains[parsed.scheme].append(parsed.netloc.lstrip("*"))
        return allowed_origin_subdomains
    
    # 看到这理知道了这玩应用的请求令牌的方式防御的XSS攻击,同时请求令牌还调用了另一个中间件
    def _get_token(self, request):
        if settings.CSRF_USE_SESSIONS:
            try:
                return request.session.get(CSRF_SESSION_KEY)
            except AttributeError:
                raise ImproperlyConfigured(
                    "CSRF_USE_SESSIONS is enabled, but request.session is not "
                    "set. SessionMiddleware must appear before CsrfViewMiddleware "
                    "in MIDDLEWARE."
                )
        else:
            try:
                cookie_token = request.COOKIES[settings.CSRF_COOKIE_NAME]
            except KeyError:
                return None

            # This can raise InvalidTokenFormat.
            csrf_token = _sanitize_token(cookie_token)

            if csrf_token != cookie_token:
                # Then the cookie token had length CSRF_SECRET_LENGTH, so flag
                # to replace it with the masked version.
                request.META["CSRF_COOKIE_NEEDS_UPDATE"] = True
            return csrf_token
    
    # 两个钩子函数,这个是请求来的时候还没分发路由就已经判断是否有token令牌了
    def process_request(self, request):
        try:
            csrf_token = self._get_token(request)
        except InvalidTokenFormat:
            _add_new_csrf_cookie(request)
        else:
            if csrf_token is not None:
                # Use same token next time.
                request.META["CSRF_COOKIE"] = csrf_token

	# 从路由到试图函数的处理
    def process_view(self, request, callback, callback_args, callback_kwargs):
        if getattr(request, "csrf_processing_done", False):
            return None

        # Wait until request.META["CSRF_COOKIE"] has been manipulated before
        # bailing out, so that get_token still works
        if getattr(callback, "csrf_exempt", False):
            return None

        # Assume that anything not defined as 'safe' by RFC7231 needs protection
        if request.method in ("GET", "HEAD", "OPTIONS", "TRACE"):
            return self._accept(request)

        if getattr(request, "_dont_enforce_csrf_checks", False):
            # Mechanism to turn off CSRF checks for test suite. It comes after
            # the creation of CSRF cookies, so that everything else continues
            # to work exactly the same (e.g. cookies are sent, etc.), but
            # before any branches that call the _reject method.
            return self._accept(request)

        # Reject the request if the Origin header doesn't match an allowed
        # value.
        if "HTTP_ORIGIN" in request.META:
            if not self._origin_verified(request):
                return self._reject(
                    request, REASON_BAD_ORIGIN % request.META["HTTP_ORIGIN"]
                )
        elif request.is_secure():
            # If the Origin header wasn't provided, reject HTTPS requests if
            # the Referer header doesn't match an allowed value.
            #
            # Suppose user visits http://example.com/
            # An active network attacker (man-in-the-middle, MITM) sends a
            # POST form that targets https://example.com/detonate-bomb/ and
            # submits it via JavaScript.
            #
            # The attacker will need to provide a CSRF cookie and token, but
            # that's no problem for a MITM and the session-independent secret
            # we're using. So the MITM can circumvent the CSRF protection. This
            # is true for any HTTP connection, but anyone using HTTPS expects
            # better! For this reason, for https://example.com/ we need
            # additional protection that treats http://example.com/ as
            # completely untrusted. Under HTTPS, Barth et al. found that the
            # Referer header is missing for same-domain requests in only about
            # 0.2% of cases or less, so we can use strict Referer checking.
            try:
                self._check_referer(request)
            except RejectRequest as exc:
                return self._reject(request, exc.reason)

        try:
            self._check_token(request)
        except RejectRequest as exc:
            return self._reject(request, exc.reason)

        return self._accept(request)

    # 相应的钩子
    def process_response(self, request, response):
        if request.META.get("CSRF_COOKIE_NEEDS_UPDATE"):
            self._set_csrf_cookie(request, response)
            # Unset the flag to prevent _set_csrf_cookie() from being
            # unnecessarily called again in process_response() by other
            # instances of CsrfViewMiddleware. This can happen e.g. when both a
            # decorator and middleware are used. However,
            # CSRF_COOKIE_NEEDS_UPDATE is still respected in subsequent calls
            # e.g. in case rotate_token() is called in process_response() later
            # by custom middleware but before those subsequent calls.
            request.META["CSRF_COOKIE_NEEDS_UPDATE"] = False

        return response
    # The _accept and _reject methods currently only exist for the sake of the
    # requires_csrf_token decorator.
    def _accept(self, request):
        # Avoid checking the request twice by adding a custom attribute to
        # request.  This will be relevant when both decorator and middleware
        # are used.
        request.csrf_processing_done = True
        return None


class MiddlewareMixin:
    sync_capable = True
    async_capable = True

    def __init__(self, get_response):
        if get_response is None:
            raise ValueError("get_response must be provided.")
        self.get_response = get_response
        self._async_check()
        super().__init__()

首先我们清楚了中间件最基本的写法:是一个MiddlewareMixin的子类。同时根据注释第2, 3行可以看见这个东西他的针对对象是POST请求。剩下的后续再更把(应该)

所以我们一旦使用Django进行一个Post请求,就会返回一个如下的错误:403Forbidden, 原因就是Browser没有CSRF起争端。这个时候需要在模板加上{ % csrf_token %}保证会生成token(当然,好的js还是能绕过的)。之后渲染的模板会生出一个hidden的token令牌,用调试模式就可以轻松看到

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值