昨日内容回顾
多对多三种创建方式
1.全自动
完全依赖于ManyToMany让django orm自动创建第三张表
优势:不需要你创建第三张表 自动创建
不足:第三张表扩展性
2.纯手动
不依赖于ManyToMany,自己创建第三张表,里面是有ForeignKey自己做两张表的关联
优势:第三张可以新增任意字段 扩展性较高
不足:orm查询时较为繁琐
3.半自动(推荐使用 因为可以给你后续的项目迭代提供方便)
依赖于ManyToMany,但是自己创建第三张表
优势:可扩展性高
不足:多对多字段方法不支持了(add,set,remove,clear)
forms组件
forms组件三大功能:
1.渲染前端获取用户输入的标签
2.校验数据
3.展示错误信息
注意:forms组件只能渲染获取用户输入的标签 提交按钮需要用户自己写
1.基本使用
forms组件中所有的字段默认都是必填的(默认就是required=True)
from django import forms
class MyForm(forms.Form):
username = forms.CharField(max_length=8)
email = forms.EmailField()
2.先生成一个对象
form_obj = MyForm({'username':'jason','email':'[email protected]'})
3.判断数据是否合法
form_obj.is_valid()
# 只有数据全部满足条件才会返回True
4.获取符合条件的数据
form_obj.cleaned_data
5.获取不符合条件的数据的报错原因
form_obj.errors
6.渲染前端页面 先生成一个空对象 并将对象传递给前端页面
form_obj = MyForm()
7.前端页面有三种渲染方式
1.{{form_obj.as_p}} # 封装程度太高 可扩展性差
2.{{ form_obj.username.label }}{{form_obj.username}} # 书写的内容太多了
3. {% for form in form_obj %} # 使用频率较高
{% endfor %}
8.其他属性操作
from django.forms import widgets
username = forms.CharField(max_length=8,label='用户名',required=False,
error_message={
'max_length':"用户名最大八位",
'required':'用户名不能为空'
},
widget=widgets.TextInput(attrs={'class':'form-control'},
validators=[RegexValidator(r'^[0-9]+$', '请输入数字'), RegexValidator(r'^159[0-9]+$', '数字必须以159开头')]
)
)
9.钩子函数(Hook)
局部钩子 (针对某一个字段做一些额外的校验)
from app01 import models
def clean_username(self):
# 当前用户名是否已经被注册
username = self.cleaned_data.get('username')
is_user = models.User.objects.filter(username=username)
if is_user:
self.add_error('username','用户名已经存在')
if '西游记' in username:
self.add_error('username','不符合社会主义核心价值观')
return username
全局钩子(针对多个字段的校验)
def clean(self):
password = self.cleaned_data.get('password')
confirm_password = self.cleaned_data.get('confirm_password')
if not password == confirm_password:
self.add_error('confirm_password','两次密码不一致')
return self.cleaned_data
多对多三种创建方式
1.全自动
完全依赖于ManyToMany让django orm自动创建第三张表
优势:不需要你创建第三张表 自动创建
不足:第三张表扩展性
2.纯手动
不依赖于ManyToMany,自己创建第三张表,里面是有ForeignKey自己做两张表的关联
优势:第三张可以新增任意字段 扩展性较高
不足:orm查询时较为繁琐
3.半自动(推荐使用 因为可以给你后续的项目迭代提供方便)
依赖于ManyToMany,但是自己创建第三张表
优势:可扩展性高
不足:多对多字段方法不支持了(add,set,remove,clear)
forms组件
forms组件三大功能:
1.渲染前端获取用户输入的标签
2.校验数据
3.展示错误信息
注意:forms组件只能渲染获取用户输入的标签 提交按钮需要用户自己写
1.基本使用
forms组件中所有的字段默认都是必填的(默认就是required=True)
from django import forms
class MyForm(forms.Form):
username = forms.CharField(max_length=8)
email = forms.EmailField()
2.先生成一个对象
form_obj = MyForm({'username':'jason','email':'[email protected]'})
3.判断数据是否合法
form_obj.is_valid()
# 只有数据全部满足条件才会返回True
4.获取符合条件的数据
form_obj.cleaned_data
5.获取不符合条件的数据的报错原因
form_obj.errors
6.渲染前端页面 先生成一个空对象 并将对象传递给前端页面
form_obj = MyForm()
7.前端页面有三种渲染方式
1.{{form_obj.as_p}} # 封装程度太高 可扩展性差
2.{{ form_obj.username.label }}{{form_obj.username}} # 书写的内容太多了
3. {% for form in form_obj %} # 使用频率较高
{{form.label}}{{ form }}
{% endfor %}
8.其他属性操作
from django.forms import widgets
username = forms.CharField(max_length=8,label='用户名',required=False,
error_message={
'max_length':"用户名最大八位",
'required':'用户名不能为空'
},
widget=widgets.TextInput(attrs={'class':'form-control'},
validators=[RegexValidator(r'^[0-9]+$', '请输入数字'), RegexValidator(r'^159[0-9]+$', '数字必须以159开头')]
)
)
9.钩子函数(Hook)
局部钩子 (针对某一个字段做一些额外的校验)
from app01 import models
def clean_username(self):
# 当前用户名是否已经被注册
username = self.cleaned_data.get('username')
is_user = models.User.objects.filter(username=username)
if is_user:
self.add_error('username','用户名已经存在')
if '西游记' in username:
self.add_error('username','不符合社会主义核心价值观')
return username
全局钩子(针对多个字段的校验)
def clean(self):
password = self.cleaned_data.get('password')
confirm_password = self.cleaned_data.get('confirm_password')
if not password == confirm_password:
self.add_error('confirm_password','两次密码不一致')
return self.cleaned_data
10.其他字段及参数
initial 默认值
如果是单选的话 统一都是forms.ChocieField(
widget=widgets.Select(),
widget=widgets.RadioSelect(),
widget=widgets.CheckboxSelect(),
)
Cookie与Session
由于http协议是无状态
cookie是保存在客户端浏览器上的
session是保存服务端上的
session是依赖于cookie的,所有的保存用户登录状态或者各种校验基本都需要
依赖于cookie
django操作cookie与session
操作的cookie要利用HttpResponse对象
obj = HttpResponse()
obj.set_cookie('k1','v1',max_age=100)
return obj
request.COOKIES.get('k1')
initial 默认值
如果是单选的话 统一都是forms.ChocieField(
widget=widgets.Select(),
widget=widgets.RadioSelect(),
widget=widgets.CheckboxSelect(),
)
Cookie与Session
由于http协议是无状态
cookie是保存在客户端浏览器上的
session是保存服务端上的
session是依赖于cookie的,所有的保存用户登录状态或者各种校验基本都需要
依赖于cookie
django操作cookie与session
操作的cookie要利用HttpResponse对象
obj = HttpResponse()
obj.set_cookie('k1','v1',max_age=100)
return obj
request.COOKIES.get('k1')
request.session['name'] = 'jason' # 三件事
# 1.生成一个随机字符串
# 2.将随机字符串和要保存的数据写入django_session表中(django默认session过期时间14天)
# 3.将随机字符串返回给客户端浏览器
"""
服务端保存用户信息 不一定非要在django_session表中保存
可以利用其他数据库或者换成作为session的暂存地
"""
request.session.get('name') # 三件事
# 删除当前会话的所有Session数据
request.session.delete()
# 删除当前的会话数据并删除会话的Cookie。
request.session.flush()
这用于确保前面的会话数据不可以再次被用户的浏览器访问
例如,django.contrib.auth.logout() 函数中就会调用它。
# 设置会话Session和Cookie的超时时间
request.session.set_expiry(value)
* 如果value是个整数,session会在些秒数后失效。
* 如果value是个datatime或timedelta,session就会在这个时间后失效。
* 如果value是0,用户关闭浏览器session就会失效。
* 如果value是None,session会依赖全局session失效策略。
利用cookie写了装饰器
作业用session
今日内容
django中间件
django中间件是类似于是django的保安
请求的时候需要先经过中间件才能到达django后端(urls,views,templates,models)
响应走的时候也需要经过中间件才能到达web服务网关接口
django默认的七个中间件
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
class SecurityMiddleware(MiddlewareMixin):
def __init__(self, get_response=None):
self.sts_seconds = settings.SECURE_HSTS_SECONDS
self.sts_include_subdomains = settings.SECURE_HSTS_INCLUDE_SUBDOMAINS
self.sts_preload = settings.SECURE_HSTS_PRELOAD
self.content_type_nosniff = settings.SECURE_CONTENT_TYPE_NOSNIFF
self.xss_filter = settings.SECURE_BROWSER_XSS_FILTER
self.redirect = settings.SECURE_SSL_REDIRECT
self.redirect_host = settings.SECURE_SSL_HOST
self.redirect_exempt = [re.compile(r) for r in settings.SECURE_REDIRECT_EXEMPT]
self.get_response = get_response
request.session.set_expiry(value)
* 如果value是个整数,session会在些秒数后失效。
* 如果value是个datatime或timedelta,session就会在这个时间后失效。
* 如果value是0,用户关闭浏览器session就会失效。
* 如果value是None,session会依赖全局session失效策略。
利用cookie写了装饰器
作业用session
今日内容
django中间件
django中间件是类似于是django的保安
请求的时候需要先经过中间件才能到达django后端(urls,views,templates,models)
响应走的时候也需要经过中间件才能到达web服务网关接口
django默认的七个中间件
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
class SecurityMiddleware(MiddlewareMixin):
def __init__(self, get_response=None):
self.sts_seconds = settings.SECURE_HSTS_SECONDS
self.sts_include_subdomains = settings.SECURE_HSTS_INCLUDE_SUBDOMAINS
self.sts_preload = settings.SECURE_HSTS_PRELOAD
self.content_type_nosniff = settings.SECURE_CONTENT_TYPE_NOSNIFF
self.xss_filter = settings.SECURE_BROWSER_XSS_FILTER
self.redirect = settings.SECURE_SSL_REDIRECT
self.redirect_host = settings.SECURE_SSL_HOST
self.redirect_exempt = [re.compile(r) for r in settings.SECURE_REDIRECT_EXEMPT]
self.get_response = get_response
def process_request(self, request):
path = request.path.lstrip("/")
if (self.redirect and not request.is_secure() and
not any(pattern.search(path)
for pattern in self.redirect_exempt)):
host = self.redirect_host or request.get_host()
return HttpResponsePermanentRedirect(
"https://%s%s" % (host, request.get_full_path())
)
path = request.path.lstrip("/")
if (self.redirect and not request.is_secure() and
not any(pattern.search(path)
for pattern in self.redirect_exempt)):
host = self.redirect_host or request.get_host()
return HttpResponsePermanentRedirect(
"https://%s%s" % (host, request.get_full_path())
)
def process_response(self, request, response):
if (self.sts_seconds and request.is_secure() and
'strict-transport-security' not in response):
sts_header = "max-age=%s" % self.sts_seconds
if self.sts_include_subdomains:
sts_header = sts_header + "; includeSubDomains"
if self.sts_preload:
sts_header = sts_header + "; preload"
response["strict-transport-security"] = sts_header
if (self.sts_seconds and request.is_secure() and
'strict-transport-security' not in response):
sts_header = "max-age=%s" % self.sts_seconds
if self.sts_include_subdomains:
sts_header = sts_header + "; includeSubDomains"
if self.sts_preload:
sts_header = sts_header + "; preload"
response["strict-transport-security"] = sts_header
if self.content_type_nosniff and 'x-content-type-options' not in response:
response["x-content-type-options"] = "nosniff"
response["x-content-type-options"] = "nosniff"
if self.xss_filter and 'x-xss-protection' not in response:
response["x-xss-protection"] = "1; mode=block"
response["x-xss-protection"] = "1; mode=block"
return response
class CsrfViewMiddleware(MiddlewareMixin):
if settings.CSRF_USE_SESSIONS:
request.session[CSRF_SESSION_KEY] = request.META['CSRF_COOKIE']
else:
response.set_cookie(
settings.CSRF_COOKIE_NAME,
request.META['CSRF_COOKIE'],
max_age=settings.CSRF_COOKIE_AGE,
domain=settings.CSRF_COOKIE_DOMAIN,
path=settings.CSRF_COOKIE_PATH,
secure=settings.CSRF_COOKIE_SECURE,
httponly=settings.CSRF_COOKIE_HTTPONLY,
)
# Set the Vary header since content varies with the CSRF cookie.
patch_vary_headers(response, ('Cookie',))
def process_request(self, request):
csrf_token = self._get_token(request)
if csrf_token is not None:
# Use same token next time.
request.META['CSRF_COOKIE'] = csrf_token
class CsrfViewMiddleware(MiddlewareMixin):
if settings.CSRF_USE_SESSIONS:
request.session[CSRF_SESSION_KEY] = request.META['CSRF_COOKIE']
else:
response.set_cookie(
settings.CSRF_COOKIE_NAME,
request.META['CSRF_COOKIE'],
max_age=settings.CSRF_COOKIE_AGE,
domain=settings.CSRF_COOKIE_DOMAIN,
path=settings.CSRF_COOKIE_PATH,
secure=settings.CSRF_COOKIE_SECURE,
httponly=settings.CSRF_COOKIE_HTTPONLY,
)
# Set the Vary header since content varies with the CSRF cookie.
patch_vary_headers(response, ('Cookie',))
def process_request(self, request):
csrf_token = self._get_token(request)
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
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
# 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 not in ('GET', 'HEAD', 'OPTIONS', 'TRACE'):
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 reject().
return self._accept(request)
if request.method not in ('GET', 'HEAD', 'OPTIONS', 'TRACE'):
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 reject().
return self._accept(request)
if request.is_secure():
# 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.
referer = force_text(
request.META.get('HTTP_REFERER'),
strings_only=True,
errors='replace'
)
if referer is None:
return self._reject(request, REASON_NO_REFERER)
# 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.
referer = force_text(
request.META.get('HTTP_REFERER'),
strings_only=True,
errors='replace'
)
if referer is None:
return self._reject(request, REASON_NO_REFERER)
referer = urlparse(referer)
# Make sure we have a valid URL for Referer.
if '' in (referer.scheme, referer.netloc):
return self._reject(request, REASON_MALFORMED_REFERER)
if '' in (referer.scheme, referer.netloc):
return self._reject(request, REASON_MALFORMED_REFERER)
# Ensure that our Referer is also secure.
if referer.scheme != 'https':
return self._reject(request, REASON_INSECURE_REFERER)
if referer.scheme != 'https':
return self._reject(request, REASON_INSECURE_REFERER)
# If there isn't a CSRF_COOKIE_DOMAIN, require an exact match
# match on host:port. If not, obey the cookie rules (or those
# for the session cookie, if CSRF_USE_SESSIONS).
good_referer = (
settings.SESSION_COOKIE_DOMAIN
if settings.CSRF_USE_SESSIONS
else settings.CSRF_COOKIE_DOMAIN
)
if good_referer is not None:
server_port = request.get_port()
if server_port not in ('443', '80'):
good_referer = '%s:%s' % (good_referer, server_port)
else:
# request.get_host() includes the port.
good_referer = request.get_host()
# match on host:port. If not, obey the cookie rules (or those
# for the session cookie, if CSRF_USE_SESSIONS).
good_referer = (
settings.SESSION_COOKIE_DOMAIN
if settings.CSRF_USE_SESSIONS
else settings.CSRF_COOKIE_DOMAIN
)
if good_referer is not None:
server_port = request.get_port()
if server_port not in ('443', '80'):
good_referer = '%s:%s' % (good_referer, server_port)
else:
# request.get_host() includes the port.
good_referer = request.get_host()
# Here we generate a list of all acceptable HTTP referers,
# including the current host since that has been validated
# upstream.
good_hosts = list(settings.CSRF_TRUSTED_ORIGINS)
good_hosts.append(good_referer)
# including the current host since that has been validated
# upstream.
good_hosts = list(settings.CSRF_TRUSTED_ORIGINS)
good_hosts.append(good_referer)
if not any(is_same_domain(referer.netloc, host) for host in good_hosts):
reason = REASON_BAD_REFERER % referer.geturl()
return self._reject(request, reason)
reason = REASON_BAD_REFERER % referer.geturl()
return self._reject(request, reason)
csrf_token = request.META.get('CSRF_COOKIE')
if csrf_token is None:
# No CSRF cookie. For POST requests, we insist on a CSRF cookie,
# and in this way we can avoid all CSRF attacks, including login
# CSRF.
return self._reject(request, REASON_NO_CSRF_COOKIE)
if csrf_token is None:
# No CSRF cookie. For POST requests, we insist on a CSRF cookie,
# and in this way we can avoid all CSRF attacks, including login
# CSRF.
return self._reject(request, REASON_NO_CSRF_COOKIE)
# Check non-cookie token for match.
request_csrf_token = ""
if request.method == "POST":
try:
request_csrf_token = request.POST.get('csrfmiddlewaretoken', '')
except IOError:
# Handle a broken connection before we've completed reading
# the POST data. process_view shouldn't raise any
# exceptions, so we'll ignore and serve the user a 403
# (assuming they're still listening, which they probably
# aren't because of the error).
pass
request_csrf_token = ""
if request.method == "POST":
try:
request_csrf_token = request.POST.get('csrfmiddlewaretoken', '')
except IOError:
# Handle a broken connection before we've completed reading
# the POST data. process_view shouldn't raise any
# exceptions, so we'll ignore and serve the user a 403
# (assuming they're still listening, which they probably
# aren't because of the error).
pass
if request_csrf_token == "":
# Fall back to X-CSRFToken, to make things easier for AJAX,
# and possible for PUT/DELETE.
request_csrf_token = request.META.get(settings.CSRF_HEADER_NAME, '')
# Fall back to X-CSRFToken, to make things easier for AJAX,
# and possible for PUT/DELETE.
request_csrf_token = request.META.get(settings.CSRF_HEADER_NAME, '')
request_csrf_token = _sanitize_token(request_csrf_token)
if not _compare_salted_tokens(request_csrf_token, csrf_token):
return self._reject(request, REASON_BAD_TOKEN)
if not _compare_salted_tokens(request_csrf_token, csrf_token):
return self._reject(request, REASON_BAD_TOKEN)
return self._accept(request)
def process_response(self, request, response):
if not getattr(request, 'csrf_cookie_needs_reset', False):
if getattr(response, 'csrf_cookie_set', False):
return response
if not getattr(request, 'csrf_cookie_needs_reset', False):
if getattr(response, 'csrf_cookie_set', False):
return response
if not request.META.get("CSRF_COOKIE_USED", False):
return response
return response
# Set the CSRF cookie even if it's already set, so we renew
# the expiry timer.
self._set_token(request, response)
response.csrf_cookie_set = True
return response
class AuthenticationMiddleware(MiddlewareMixin):
def process_request(self, request):
assert hasattr(request, 'session'), (
"The Django authentication middleware requires session middleware "
"to be installed. Edit your MIDDLEWARE%s setting to insert "
"'django.contrib.sessions.middleware.SessionMiddleware' before "
"'django.contrib.auth.middleware.AuthenticationMiddleware'."
) % ("_CLASSES" if settings.MIDDLEWARE is None else "")
request.user = SimpleLazyObject(lambda: get_user(request))
django中间件中有五个用户可以自定义的方法
django中间件可以用来做什么(***********************)
1.网站全局的身份校验,访问频率限制,权限校验...只要是涉及到全局的校验你都可以在中间件中完成
2.django的中间件是所有web框架中 做的最好的
需要我们掌握的方法有
1.process_request()方法
规律
1.请求来的时候 会经过每个中间件里面的process_request方法(从上往下)
2.如果方法里面直接返回了HttpResponse对象 那么会直接返回 不再往下执行
基于该特点就可以做访问频率限制,身份校验,权限校验
2.process_response()方法
规律
1.必须将response形参返回 因为这个形参指代的就是要返回给前端的数据
2.响应走的时候 会依次经过每一个中间件里面的process_response方法(从下往上)
需要了解的方法
3.process_view()
1.在路由匹配成功执行视图函数之前 触发
走完process_request方法就执行process_view(),然后执行process_response()方法
4.process_exception()
1.当你的视图函数报错时 就会自动执行
5.process_template_response()
1.当你返回的HttpResponse对象中必须包含render属性才会触发
def index(request):
print('我是index视图函数')
def render():
return HttpResponse('什么鬼玩意')
obj = HttpResponse('index')
obj.render = render
return obj
总结:你在书写中间件的时候 只要形参中有repsonse 你就顺手将其返回 这个reponse就是要给前端的消息
如何自定义我们自己的中间件,研究这上面五个方法都有哪些特点********
1.如果你想让你写的中间件生效 就必须要先继承MiddlewareMixin
2.在注册自定义中间件的时候 一定要确保路径不要写错
案例:
from django.shortcuts import HttpResponse
from django.utils.deprecation import MiddlewareMixin
# the expiry timer.
self._set_token(request, response)
response.csrf_cookie_set = True
return response
class AuthenticationMiddleware(MiddlewareMixin):
def process_request(self, request):
assert hasattr(request, 'session'), (
"The Django authentication middleware requires session middleware "
"to be installed. Edit your MIDDLEWARE%s setting to insert "
"'django.contrib.sessions.middleware.SessionMiddleware' before "
"'django.contrib.auth.middleware.AuthenticationMiddleware'."
) % ("_CLASSES" if settings.MIDDLEWARE is None else "")
request.user = SimpleLazyObject(lambda: get_user(request))
django中间件中有五个用户可以自定义的方法
django中间件可以用来做什么(***********************)
1.网站全局的身份校验,访问频率限制,权限校验...只要是涉及到全局的校验你都可以在中间件中完成
2.django的中间件是所有web框架中 做的最好的
需要我们掌握的方法有
1.process_request()方法
规律
1.请求来的时候 会经过每个中间件里面的process_request方法(从上往下)
2.如果方法里面直接返回了HttpResponse对象 那么会直接返回 不再往下执行
基于该特点就可以做访问频率限制,身份校验,权限校验
2.process_response()方法
规律
1.必须将response形参返回 因为这个形参指代的就是要返回给前端的数据
2.响应走的时候 会依次经过每一个中间件里面的process_response方法(从下往上)
需要了解的方法
3.process_view()
1.在路由匹配成功执行视图函数之前 触发
走完process_request方法就执行process_view(),然后执行process_response()方法
4.process_exception()
1.当你的视图函数报错时 就会自动执行
5.process_template_response()
1.当你返回的HttpResponse对象中必须包含render属性才会触发
def index(request):
print('我是index视图函数')
def render():
return HttpResponse('什么鬼玩意')
obj = HttpResponse('index')
obj.render = render
return obj
总结:你在书写中间件的时候 只要形参中有repsonse 你就顺手将其返回 这个reponse就是要给前端的消息
如何自定义我们自己的中间件,研究这上面五个方法都有哪些特点********
1.如果你想让你写的中间件生效 就必须要先继承MiddlewareMixin
2.在注册自定义中间件的时候 一定要确保路径不要写错
案例:
from django.shortcuts import HttpResponse
from django.utils.deprecation import MiddlewareMixin
class MyMdd(MiddlewareMixin):
def process_request(self,request):
print('我是第一个中间件process_request')
def process_response(self,request,response):
print('我是第一个中间件里面的process_response')
return response
def process_view(self,request,view_func,view_args,view_kwargs):
print(view_func)
print(view_args)
print(view_kwargs)
print('我是第一个中间件里的process_view')
def process_request(self,request):
print('我是第一个中间件process_request')
def process_response(self,request,response):
print('我是第一个中间件里面的process_response')
return response
def process_view(self,request,view_func,view_args,view_kwargs):
print(view_func)
print(view_args)
print(view_kwargs)
print('我是第一个中间件里的process_view')
def process_exception(self,request, exception): 当你的视图函数报错时 就会自动执行
print('我是第一个中间件里面的process_exception')
class MyMdd1(MiddlewareMixin):
def process_request(self,request):
print('我是第二个中间件process_request')
#当中间件里面的process_request方法返回了一个HttpResponse对象
# 那么就不会再继续向下执行,而是直接跳到同级别的procsee_response直接往回走
return HttpResponse('嘿嘿嘿')
def process_response(self,request,response):
print('我是第二个中间件里面的process_response')
return response
class MyMdd2(MiddlewareMixin):
def process_request(self,request):
print('我是第三个中间件process_request')
def process_response(self,request, response):# 括号里面别忘记response
print('我是第三个中间件里面的process_response')
return response # 此时的response就是视图函数里返回的Http
csrf跨站请求伪造
钓鱼网站
通过制作一个跟正儿八经的网站一模一样的页面,骗取用户输入信息 转账交易
从而做手脚
转账交易的请求确确实实是发给了中国银行,账户的钱也是确确实实少了
唯一不一样的地方在于收款人账户不对
内部原理
在让用户输入对方账户的那个input上面做手脚
给这个input不设置name属性,在内部隐藏一个实现写好的name和value属性的input框
这个value的值 就是钓鱼网站受益人账号
防止钓鱼网站的思路
网站会给返回给用户的form表单页面 偷偷塞一个随机字符串
请求到来的时候 会先比对随机字符串是否一致 如果不一致 直接拒绝(403)
例如用户在登录中国银行的时候,会产生一个唯一的随机的字符串,在下一次用户登录的时候将携带这个wo
能识别的唯一的字符串与我储存的字符串进行一一比对,比对上说明客户登录的就是我网站的用户,比对不上就是钓鱼网站
该随机字符串有以下特点
1.同一个浏览器每一次访问都不一样
2.不同浏览器绝对不会重复
1.form表单发送post请求的时候 需要你做得仅仅书写一句话
{% csrf_token %}*******
在你返回给用户的form表单中,会偷偷的塞一对键值对,塞一组信息,当用户再次发送请求时,我会偷偷的先
拿到那对键值,进行比对,如果比对上,说明你是我本网站用户,接下来在进行用户操作,然后在进行校验
即比对成功,才会让你输入用户名,每一次的token都不一样,钓鱼网站token和正规网站token不一样,正规的网站它会记录自己的token,
钓鱼网站的token如果和正规网站token一样,但是这个token不是正规网站给你的,所以无法访问
2.ajax发送post请求 如何避免csrf校验
1.现在页面上写{% csrf_token %},利用标签查找 获取到该input键值信息
{'username':'jason','csrfmiddlewaretoken':$('[name=csrfmiddlewaretoken]').val()}
$('[name=csrfmiddlewaretoken]').val() #固定用法
2.直接书写'{{ csrf_token }}'
{'username':'jason','csrfmiddlewaretoken':'{{ csrf_token }}'}
{{ csrf_token }}
3.你可以将该获取随机键值对的方法 写到一个js文件中,之后只需要导入该文件即可
新建一个js文件 存放以下代码 之后导入即可
function getCookie(name) {
var cookieValue = null;
if (document.cookie && document.cookie !== '') {
var cookies = document.cookie.split(';');
for (var i = 0; i < cookies.length; i++) {
var cookie = jQuery.trim(cookies[i]);
// Does this cookie string begin with the name we want?
if (cookie.substring(0, name.length + 1) === (name + '=')) {
cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
break;
}
}
}
return cookieValue;
}
var csrftoken = getCookie('csrftoken');
print('我是第一个中间件里面的process_exception')
class MyMdd1(MiddlewareMixin):
def process_request(self,request):
print('我是第二个中间件process_request')
#当中间件里面的process_request方法返回了一个HttpResponse对象
# 那么就不会再继续向下执行,而是直接跳到同级别的procsee_response直接往回走
return HttpResponse('嘿嘿嘿')
def process_response(self,request,response):
print('我是第二个中间件里面的process_response')
return response
class MyMdd2(MiddlewareMixin):
def process_request(self,request):
print('我是第三个中间件process_request')
def process_response(self,request, response):# 括号里面别忘记response
print('我是第三个中间件里面的process_response')
return response # 此时的response就是视图函数里返回的Http
csrf跨站请求伪造
钓鱼网站
通过制作一个跟正儿八经的网站一模一样的页面,骗取用户输入信息 转账交易
从而做手脚
转账交易的请求确确实实是发给了中国银行,账户的钱也是确确实实少了
唯一不一样的地方在于收款人账户不对
内部原理
在让用户输入对方账户的那个input上面做手脚
给这个input不设置name属性,在内部隐藏一个实现写好的name和value属性的input框
这个value的值 就是钓鱼网站受益人账号
防止钓鱼网站的思路
网站会给返回给用户的form表单页面 偷偷塞一个随机字符串
请求到来的时候 会先比对随机字符串是否一致 如果不一致 直接拒绝(403)
例如用户在登录中国银行的时候,会产生一个唯一的随机的字符串,在下一次用户登录的时候将携带这个wo
能识别的唯一的字符串与我储存的字符串进行一一比对,比对上说明客户登录的就是我网站的用户,比对不上就是钓鱼网站
该随机字符串有以下特点
1.同一个浏览器每一次访问都不一样
2.不同浏览器绝对不会重复
1.form表单发送post请求的时候 需要你做得仅仅书写一句话
{% csrf_token %}*******
在你返回给用户的form表单中,会偷偷的塞一对键值对,塞一组信息,当用户再次发送请求时,我会偷偷的先
拿到那对键值,进行比对,如果比对上,说明你是我本网站用户,接下来在进行用户操作,然后在进行校验
即比对成功,才会让你输入用户名,每一次的token都不一样,钓鱼网站token和正规网站token不一样,正规的网站它会记录自己的token,
钓鱼网站的token如果和正规网站token一样,但是这个token不是正规网站给你的,所以无法访问
2.ajax发送post请求 如何避免csrf校验
1.现在页面上写{% csrf_token %},利用标签查找 获取到该input键值信息
{'username':'jason','csrfmiddlewaretoken':$('[name=csrfmiddlewaretoken]').val()}
$('[name=csrfmiddlewaretoken]').val() #固定用法
2.直接书写'{{ csrf_token }}'
{'username':'jason','csrfmiddlewaretoken':'{{ csrf_token }}'}
{{ csrf_token }}
3.你可以将该获取随机键值对的方法 写到一个js文件中,之后只需要导入该文件即可
新建一个js文件 存放以下代码 之后导入即可
function getCookie(name) {
var cookieValue = null;
if (document.cookie && document.cookie !== '') {
var cookies = document.cookie.split(';');
for (var i = 0; i < cookies.length; i++) {
var cookie = jQuery.trim(cookies[i]);
// Does this cookie string begin with the name we want?
if (cookie.substring(0, name.length + 1) === (name + '=')) {
cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
break;
}
}
}
return cookieValue;
}
var csrftoken = getCookie('csrftoken');
function csrfSafeMethod(method) {
// these HTTP methods do not require CSRF protection
return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
}
$.ajaxSetup({
beforeSend: function (xhr, settings) {
if (!csrfSafeMethod(settings.type) && !this.crossDomain) {
xhr.setRequestHeader("X-CSRFToken", csrftoken);
}
}
});
1.当你网站全局都需要校验csrf的时候 有几个不需要校验该如何处理
2.当你网站全局不校验csrf的时候 有几个需要校验又该如何处理
from django.utils.decorators import method_decorator
from django.views.decorators.csrf import csrf_exempt,csrf_protect
# 这两个装饰器在给CBV装饰的时候 有一定的区别
如果是csrf_protect 那么有三种方式
# 第一种方式
# @method_decorator(csrf_protect,name='post') # 有效的
class MyView(View):
# 第三种方式
# @method_decorator(csrf_protect)
def dispatch(self, request, *args, **kwargs):
res = super().dispatch(request, *args, **kwargs)
return res
beforeSend: function (xhr, settings) {
if (!csrfSafeMethod(settings.type) && !this.crossDomain) {
xhr.setRequestHeader("X-CSRFToken", csrftoken);
}
}
});
1.当你网站全局都需要校验csrf的时候 有几个不需要校验该如何处理
2.当你网站全局不校验csrf的时候 有几个需要校验又该如何处理
from django.utils.decorators import method_decorator
from django.views.decorators.csrf import csrf_exempt,csrf_protect
# 这两个装饰器在给CBV装饰的时候 有一定的区别
如果是csrf_protect 那么有三种方式
# 第一种方式
# @method_decorator(csrf_protect,name='post') # 有效的
class MyView(View):
# 第三种方式
# @method_decorator(csrf_protect)
def dispatch(self, request, *args, **kwargs):
res = super().dispatch(request, *args, **kwargs)
return res
def get(self,request):
return HttpResponse('get')
# 第二种方式
# @method_decorator(csrf_protect) # 有效的
def post(self,request):
return HttpResponse('post')
如果是csrf_exempt 只有两种(只能给dispatch装) 特例
@method_decorator(csrf_exempt,name='dispatch') # 第二种可以不校验的方式
class MyView(View):
# @method_decorator(csrf_exempt) # 第一种可以不校验的方式
def dispatch(self, request, *args, **kwargs):
res = super().dispatch(request, *args, **kwargs)
return res
return HttpResponse('get')
# 第二种方式
# @method_decorator(csrf_protect) # 有效的
def post(self,request):
return HttpResponse('post')
如果是csrf_exempt 只有两种(只能给dispatch装) 特例
@method_decorator(csrf_exempt,name='dispatch') # 第二种可以不校验的方式
class MyView(View):
# @method_decorator(csrf_exempt) # 第一种可以不校验的方式
def dispatch(self, request, *args, **kwargs):
res = super().dispatch(request, *args, **kwargs)
return res
def get(self,request):
return HttpResponse('get')
return HttpResponse('get')
def post(self,request):
return HttpResponse('post')
总结 装饰器中只有csrf_exempt是特例,其他的装饰器在给CBV装饰的时候 都可以有三种方式
课后作业:
将昨天的写的登陆认证装饰器 加载CBV上
auth模块
如果你想用auth模块 那么你就用全套
跟用户相关的功能模块
用户的注册 登陆 验证 修改密码 ...
执行数据库迁移命令之后 会生成很多表 其中的auth_user是一张用户相关的表格
添加数据
createsuperuser 创建超级用户 这个超级用户就可以拥有登陆django admin后台管理的权限
return HttpResponse('post')
总结 装饰器中只有csrf_exempt是特例,其他的装饰器在给CBV装饰的时候 都可以有三种方式
课后作业:
将昨天的写的登陆认证装饰器 加载CBV上
auth模块
如果你想用auth模块 那么你就用全套
跟用户相关的功能模块
用户的注册 登陆 验证 修改密码 ...
执行数据库迁移命令之后 会生成很多表 其中的auth_user是一张用户相关的表格
添加数据
createsuperuser 创建超级用户 这个超级用户就可以拥有登陆django admin后台管理的权限
auth模块的功能
查询用户
from django.contrib import auth
user_obj = auth.authenticate(username=username,password=password) # 必须要用 因为数据库中的密码字段是密文的 而你获取的用户输入的是明文
记录用户状态
auth.login(request,user_obj) # 将用户状态记录到session中
判断用户是否登录
print(request.user.is_authenticated) # 判断用户是否登录 如果是你们用户会返回False
用户登录之后 获取用户对象
print(request.user) # 如果没有执行auth.login那么拿到的是匿名用户
校验用户是否登录
from django.contrib.auth.decorators import login_required
@login_required(login_url='/xxx/') # 局部配置
def index(request):
pass
# 全局配置 settings文件中
LOGIN_URL = '/xxx/'
验证密码是否正确
request.user.check_password(old_password)
修改密码
request.user.set_password(new_password)
request.user.save() # 修改密码的时候 一定要save保存 否则无法生效
退出登陆
auth.logout(request) # request.session.flush()
注册用户
# User.objects.create(username =username,password=password) # 创建用户名的时候 千万不要再使用create 了
# User.objects.create_user(username =username,password=password) # 创建普通用户
User.objects.create_superuser(username =username,password=password,email='[email protected]') # 创建超级用户 邮箱必填
自定义auth_user表
from django.contrib.auth.models import AbstractUser
# Create your models here.
# 第一种 使用一对一关系 不考虑
查询用户
from django.contrib import auth
user_obj = auth.authenticate(username=username,password=password) # 必须要用 因为数据库中的密码字段是密文的 而你获取的用户输入的是明文
记录用户状态
auth.login(request,user_obj) # 将用户状态记录到session中
判断用户是否登录
print(request.user.is_authenticated) # 判断用户是否登录 如果是你们用户会返回False
用户登录之后 获取用户对象
print(request.user) # 如果没有执行auth.login那么拿到的是匿名用户
校验用户是否登录
from django.contrib.auth.decorators import login_required
@login_required(login_url='/xxx/') # 局部配置
def index(request):
pass
# 全局配置 settings文件中
LOGIN_URL = '/xxx/'
验证密码是否正确
request.user.check_password(old_password)
修改密码
request.user.set_password(new_password)
request.user.save() # 修改密码的时候 一定要save保存 否则无法生效
退出登陆
auth.logout(request) # request.session.flush()
注册用户
# User.objects.create(username =username,password=password) # 创建用户名的时候 千万不要再使用create 了
# User.objects.create_user(username =username,password=password) # 创建普通用户
User.objects.create_superuser(username =username,password=password,email='[email protected]') # 创建超级用户 邮箱必填
自定义auth_user表
from django.contrib.auth.models import AbstractUser
# Create your models here.
# 第一种 使用一对一关系 不考虑
# 第二种方式 使用类的继承
class Userinfo(AbstractUser):
# 千万不要跟原来表中的字段重复 只能创新
phone = models.BigIntegerField()
avatar = models.CharField(max_length=32)
# 一定要在配置文件中 告诉django
# 告诉django orm不再使用auth默认的表 而是使用你自定义的表
AUTH_USER_MODEL = 'app01.Userinfo' # '应用名.类名'
1.执行数据库迁移命令
所有的auth模块功能 全部都基于你创建的表
而不再使用auth_user
settings功能插拔式源码
参考django 配置文件中的 中间件等功能模块
class Userinfo(AbstractUser):
# 千万不要跟原来表中的字段重复 只能创新
phone = models.BigIntegerField()
avatar = models.CharField(max_length=32)
# 一定要在配置文件中 告诉django
# 告诉django orm不再使用auth默认的表 而是使用你自定义的表
AUTH_USER_MODEL = 'app01.Userinfo' # '应用名.类名'
1.执行数据库迁移命令
所有的auth模块功能 全部都基于你创建的表
而不再使用auth_user
settings功能插拔式源码
参考django 配置文件中的 中间件等功能模块