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令牌,用调试模式就可以轻松看到