8 Django组件
1 中间件
中间件顾名思义,是介于request与response处理之间的一道处理过程,相对比较轻量级,并且在全局上改变django的输入与输出。因为改变的是全局,所以需要谨慎实用,用不好会影响到性能。
Django的中间件的定义:
Middleware is a framework of hooks into Django’s request/response processing.
It’s a light, low-level “plugin” system for globally altering Django’s input or output.
MiddleWare,是 Django 请求/响应处理的钩子框架。
它是一个轻量级的、低级的“插件”系统,用于全局改变 Django 的输入或输出。【输入指代的就是客户端像服务端django发送数据,输出指代django根据客户端要求处理数据的结果返回给客户端】
如果你想修改请求,例如被传送到view中的HttpRequest对象。 或者你想修改view返回的HttpResponse对象,这些都可以通过中间件来实现。
django框架内部声明了很多的中间件,这些中间件有着各种各种的用途,有些没有被使用,有些被默认开启使用了。而被开启使用的中间件,都是在settngs.py的MIDDLEWARE中注册使用的。
Django默认的Middleware:
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',
]
1-1 自定义中间件
中间件的执行流程:
当浏览器进来时,经过第一层
wsgi.py文件--在经过第二层MIDDLEWARE中间件--在经过路由层--在经过视图层--在依次往上推返回数据
1.定义中间件
创建存放自定义中间件的文件这里选择在app01里创建mdws.py文件:
from django.utils.deprecation import MiddlewareMixin
class Md1(MiddlewareMixin):
def process_request(self, request):
print("Md1请求")
# return HttpResponse("Md1中断") # 拦截
def process_response(self, request, response):
print("Md1返回")
return response
class Md2(MiddlewareMixin):
def process_request(self, request):
print("Md2请求")
# return HttpResponse("Md2中断")
def process_response(self, request, response):
print("Md2返回")
return response
- process_request默认返回None,返回None,则继续执行下一个中间件的process_request;一旦返回响应体对象,则会拦截返回。
- process_response必须有一个形参response,并return response;这是view函数返回的响应体,像接力棒一样传承给最后的客户端。

2.注册中间件
MIDDLEWARE = [
...
'app01.mdws.Md1',
'app01.mdws.Md2'
]
3.构建index路由
# path('index/', views.index),
def index(request):
print("index 视图函数执行...")
return HttpResponse("hello yuan")
启动项目,访问index路径:

后台打印结果:
Md1请求
Md2请求
index 视图函数执行...
Md2返回
Md1返回
所以,通过结果我们看出中间件的执行顺序:

1-2 中间件应用
1.做IP访问频率限制(请求做处理)
某些IP访问服务器的频率过高,进行拦截,比如限制每分钟不能超过20次。
from django.utils.deprecation import MiddlewareMixin
from django.shortcuts import HttpResponse
class IPValid(MiddlewareMixin):
def process_request(self, request):
print("IPValid请求")
print(request.META)
visit_ip = request.META.get('REMOTE_ADDR')
if visit_ip in ['127.0.0.1', '']:
return HttpResponse("非法IP!") # 拦截(原路返回)
def process_response(self, request, response):
print("IPValid返回")
return response
2.做响应处理(把返回的数据加上welcome to luffycity),一次添加响应所有请求
from django.utils.deprecation import MiddlewareMixin
class IPValid(MiddlewareMixin):
def process_request(self, request):
print("Md1请求")
def process_response(self, request, response):
print("Md1返回")
print(response.content) # b'<h1>ok</h1>'
response.content = b"<h1>welcome to luffycity</h1>" + response.content
return response
1-3 其它


疑问:prcess_request的执行时,是否已执行了路由匹配?
request.resolver_match
没有执行,只有在中间价全部通过后,进行路由匹配--->在经过 process_view
注意:process_view是在django中源码中写死了。

小结
- 定义中间类
- 类方法
- process_request
- process_view
- process_reponse
- process_exception,视图函数出现异常,自定义异常页面。
- process_template_response,视图函数返回
TemplateResponse对象 or 对象中含有.render方法。

2 cookie
我们知道HTTP协议是无状态协议,也就是说每个请求都是独立的!无法记录前一次请求的状态。但HTTP协议中可以使用Cookie来完成会话跟踪!在Web开发中,使用session来完成会话跟踪,session底层依赖Cookie技术。
Cookie翻译成中文是小甜点,小饼干的意思。在HTTP中它表示服务器送给客户端浏览器的小甜点。其实Cookie是key-value结构,类似于一个python中的字典。随着服务器端的响应发送给客户端浏览器。然后客户端浏览器会把Cookie保存起来,当下一次再访问服务器时把Cookie再发送给服务器。 Cookie是由服务器创建,然后通过响应发送给客户端的一个键值对。客户端会保存Cookie,并会标注出Cookie的来源(哪个服务器的Cookie)。当客户端向服务器发出请求时会把所有这个服务器Cookie包含在请求中发送给服务器,这样服务器就可以识别客户端了!
cookie可以理解为每一个浏览器针对每一个服务器创建的key-value结构的本地存储文件
1.cookie流程图

2.cookie语法
# (1) 设置cookie:
res = HttpResponse(...) 或 rep = render(request, ...) 或 rep = redirect()
res.set_cookie(key,value,max_age...)
res.set_signed_cookie(key,value,salt='加密盐',...) # 推荐
# (2) 获取cookie:
request.COOKIES
# (3) 删除cookie
response.delete_cookie("cookie_key",path="/",domain=name)
3.其他方法
rep.set_cookie(key,value,...)
rep.set_signed_cookie(key,value,salt='加密盐',...)
| 字段名 | 字段描述 |
|---|---|
key |
键 |
value |
值 |
max_age |
超长时间,cookie需要延续的时间(以秒为单位) 如果参数是 None ,这个cookie会延续到浏览器关闭为止。 |
expires |
超长时间 expires默认None ,cookie失效的实际日期/时间。 |
path |
Cookie生效的路径,浏览器只会把cookie回传给带有该路径的页面,这样可以避免将cookie传给站点中的其他的应用。 值为/ 表示根路径,特殊的:根路径的cookie可以被任何url的页面访问 |
domain |
Cookie生效的域名,你可用这个参数来构造一个跨站cookie。如, domain=".example.com"所构造的cookie对下面这些站点都是可读的:www.example.com 、 www2.example.com和an.other.sub.domain.example.com 。如果该参数设置为 None ,cookie只能由设置它的站点读取。 |
secure |
如果设置为 True ,浏览器将通过HTTPS来回传cookie。 |
httponly |
只能http协议传输,无法被JavaScript获取(不是绝对,底层抓包可以获取到也可以被覆盖) |
4.应用案例
全局urls.py
from django.contrib import admin
from django.urls import path
from cookie import views
urlpatterns = [
path('admin/', admin.site.urls),
path('index/', views.index),
path('login/', views.login),
]
models.py
from django.db import models
class User(models.Model):
user = models.CharField(max_length=32)
pwd = models.CharField(max_length=32)
class Meta:
db_table = "db_user"
模板文件:
<!--login文件-->
<form action="" method="post">
<label for="use">用户名:</label>
<input type="text" id="use" name="user">
<label for="pwd">密码:</label>
<input type="password" id="pwd" name="pwd">
<input type="submit">
</form>
<!--index文件-->
<h3>hello {{ user_name }}</h3>
cookie.py下view.py
from django.shortcuts import render, redirect, HttpResponse
from cookie.models import User
def index(request):
# 判断该客户端是否登录,读cookie
is_login = request.get_signed_cookie("is_login", salt='123*123')
if is_login == "true":
user_id = request.get_signed_cookie("user_id", salt='123*123')
user_name = User.objects.get(pk=user_id).user
return render(request, 'index.html', {"user_name": user_name})
else:
return redirect('/login/')
def login(request):
if request.method == "GET":
return render(request, 'login.html')
if request.method == "POST":
user = request.POST.get('user')
pwd = request.POST.get('pwd')
try:
user_pk = User.objects.filter(user=user, pwd=pwd)[0].pk
# 登录成功,写cookie
res = redirect('/index/')
res.set_signed_cookie("is_login", "true", salt='123*123')
res.set_signed_cookie("user_id", user_pk, salt='123*123')
return res
except Exception as e:
return redirect('/login/')
5.显示上次访问时间
import datetime
now = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
urls.py:
from app01 import views
urlpatterns = [
path('admin/', admin.site.urls),
path('login/', views.login),
path('index/', views.index),
path('test/', views.test),
]
views.py:
from django.shortcuts import render, HttpResponse, redirect
# Create your views here.
from app01.models import UserInfo
def login(request):
if request.method=="POST":
user = request.POST.get("user")
pwd = request.POST.get("pwd")
user_obj = UserInfo.objects.filter(user=user, pwd=pwd).first()
if user_obj:
# 登录成功,加入cookie
"""
响应体:
return HttpResponse()
return render()
return redirect()
"""
# 设置cookie
response = HttpResponse("登录成功")
response.set_cookie("is_login", True)
# path="/index/" : 有效路径index,只有index路径可以取到"username":user_obj.user
response.set_cookie("username", user_obj.user, path="/index/")
return response
return render(request, "login.html")
def index(request):
print(request.COOKIES)
# 取cookie值
is_login = request.COOKIES.get("is_login")
if is_login:
username = request.COOKIES.get("username")
# 配置时间
import datetime
now = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
last_time = request.COOKIES.get("last_visit_time", "")
response = render(request, "index.html", {"username": username, "last_time":last_time})
response.set_cookie("last_visit_time",now)
return response
else:
return redirect("/login")
def test(request):
print("test:", request.COOKIES)
return HttpResponse("test")
index.html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<p>上次登录时间:{{ last_time }}</p>
<h3>hi。{{ username }}</h3>
</body>
</html>
3 session
我们知道HTTP协议是无状态协议,也就是说每个请求都是独立的!无法记录前一次请求的状态。但HTTP协议中可以使用Cookie来完成会话跟踪!在Web开发中,使用session来完成会话跟踪,session底层依赖Cookie技术。
Django 提供对匿名会话(session)的完全支持。这个会话框架让你可以存储和取回每个站点访客任意数据。它在服务器端存储数据, 并以cookies的形式进行发送和接受数据。
1.session流程图

2.session语法与案例
1、设置Sessions值
request.session['session_name'] ="admin"
2、获取Sessions值
session_name = request.session["session_name"]
session_name = request.session.get("session_name")
3、删除Sessions值
del request.session["session_name"]
4、flush()
# 删除当前的会话数据并删除会话的Cookie。这用于确保前面的会话数据不可以再次被用户的浏览器访问
5、get(key, default=None)
fav_color = request.session.get('fav_color', 'red')
6、pop(key)
fav_color = request.session.pop('fav_color')
7、keys()
8、items()
9、setdefault()
10 用户session的随机字符串
request.session.session_key
# 将所有Session失效日期小于当前日期的数据删除
request.session.clear_expired()
# 检查 用户session的随机字符串 在数据库中是否
request.session.exists("session_key")
# 删除当前用户的所有Session数据
request.session.delete("session_key")
request.session.set_expiry(value)
* 如果value是个整数,session会在些秒数后失效。
* 如果value是个datatime或timedelta,session就会在这个时间后失效。
* 如果value是0,用户关闭浏览器session就会失效。
* 如果value是None,session会依赖全局session失效策略。
3.session配置
Django默认支持Session,并且默认是将Session数据存储在数据库中,即:django_session 表中。
a. 配置 settings.py
SESSION_ENGINE = 'django.contrib.sessions.backends.db'
# 引擎(默认)
SESSION_COOKIE_NAME = "sessionid"
# Session的cookie保存在浏览器上时的key,即:sessionid=随机字符串(默认)
SESSION_COOKIE_PATH = "/"
# Session的cookie保存的路径(默认)
SESSION_COOKIE_DOMAIN = None
# Session的cookie保存的域名(默认)
SESSION_COOKIE_SECURE = False
# 是否Https传输cookie(默认)
SESSION_COOKIE_HTTPONLY = True
# 是否Session的cookie只支持http传输(默认)
SESSION_COOKIE_AGE = 1209600
# Session的cookie失效日期(2周)(默认)
SESSION_EXPIRE_AT_BROWSER_CLOSE = False
# 是否关闭浏览器使得Session过期(默认)
SESSION_SAVE_EVERY_REQUEST = True
# 是否每次请求都保存Session,默认修改之后才保存
# Django默认支持Session,并且默认是将Session数据存储在数据库中,即:django_session 表中。
# 配置 settings.py
SESSION_ENGINE = 'django.contrib.sessions.backends.db' # 引擎(默认)
SESSION_COOKIE_NAME = "sessionid" # Session的cookie保存在浏览器上时的key,即:sessionid=随机字符串(默认)
SESSION_COOKIE_PATH = "/" # Session的cookie保存的路径(默认)
SESSION_COOKIE_DOMAIN = None # Session的cookie保存的域名(默认)
SESSION_COOKIE_SECURE = False # 是否Https传输cookie(默认)
SESSION_COOKIE_HTTPONLY = True # 是否Session的cookie只支持http传输(默认)
SESSION_COOKIE_AGE = 1209600 # Session的cookie失效日期(2周)(默认)
SESSION_EXPIRE_AT_BROWSER_CLOSE = False # 是否关闭浏览器使得Session过期(默认)
SESSION_SAVE_EVERY_REQUEST = True # 是否每次请求都保存Session,默认修改之后才保存
4.代码示例:
利用session可以判断用户是否访问过该浏览器
urls.py:
from django.urls import path
from session import views
urlpatterns = [
path('index/', views.index),
path('login/', views.login),
]
模板:
<!--index文件-->
<h2>session</h2>
<h3>hello {{ user_name }} <a href="/session/logout/">退出</a></h3>
<!--login文件-->
<h3>session登录</h3>
<form action="" method="post">
<label for="use">用户名:</label>
<input type="text" id="use" name="user">
<label for="pwd">密码:</label>
<input type="password" id="pwd" name="pwd">
<input type="submit">
</form>
<!--shop文件-->
<h3>上一次访问时间:{{ last_visit_time }}</h3>
<h3>shop页面</h3>
数据库:
class User(models.Model):
user = models.CharField(max_length=32)
pwd = models.CharField(max_length=32)
class Meta:
db_table = "session_user"

view.py:
from django.shortcuts import render, redirect, HttpResponse
from .models import User
import datetime
# Create your views here.
def index(request):
# 读session
"""
1.取session-id的钥匙
2.去Django-session表中查询符合条件的记录
3.将取出的session-data.get("xxx")
"""
user_id = request.session.get('user_id')
if user_id:
user_name = User.objects.get(pk=user_id).user
return render(request, 'session/index.html', {'user_name': user_name})
else:
return redirect("/session/login/")
def login(request):
if request.method == "GET":
return render(request, 'session/login.html')
if request.method == "POST":
user = request.POST.get('user')
pwd = request.POST.get('pwd')
try:
user = User.objects.get(user=user, pwd=pwd)
# 写session
"""
1.创建一个随机字符串
2.将随机字符串作为session-key,将session键值对作为session-data,
插入到Django-session表中
3.将session-id和随机字符串组成健值作为cookie返回给客户端
"""
request.session['user_id'] = user.pk
return render(request, 'session/index.html')
except Exception as e:
return redirect('/session/login/')
def shop(request):
# 去最后一次的访问时间
last_visit_time = request.session.get('last_visit_time', '第一次访问')
# 将当前时间设置到session中保存,作为最后一次访问的时间
now = datetime.datetime.now().strftime("%Y/%m/%d %X")
request.session['last_visit_time'] = now
return render(request, 'session/shop.html', {"last_visit_time": last_visit_time})
def logout(request):
# 删除session
# request.session.flush() # 会删除所有记录。
del request.session['user_id']
return redirect('/session/login/')
- session 在服务器端,cookie 在客户端(浏览器)
- session 默认被存在在服务器的一个文件里(不是内存)
- session 的运行依赖 session id,而 session id 是存在 cookie 中的.
- session 可以放在 文件、数据库、或内存中都可以。
- 用户验证这种场合一般会用 session
4 用户认证
4-1 auth模块
引入auth模块:
from django.contrib import auth
创建超级用户:
python manage.py createsuperuser
4-1.1 authenticate()
提供了用户认证,即验证用户名以及密码是否正确,一般需要username password两个关键字参数
如果认证信息有效,会返回一个 User 对象。authenticate()会在User 对象上设置一个属性标识那种认证后端认证了该用户,且该信息在后面的登录过程中是需要的。当我们试图登陆一个从数据库中直接取出来不经过authenticate()的User对象会报错的!!
user = authenticate(username='someone',password='somepassword')
4-1.2 login
login(HttpRequest, user)
该函数接受一个HttpRequest对象,以及一个认证了的User对象
此函数使用django的session框架给某个已认证的用户附加上session id等信息。
from django.contrib.auth import authenticate, login
def my_view(request):
username = request.POST['username']
password = request.POST['password']
user = authenticate(username=username, password=password)
if user is not None:
login(request, user)
# Redirect to a success page.
...
else:
# Return an 'invalid login' error message.
...
4-1.3 logout
logout(request) 注销用户
from django.contrib.auth import logout
def logout_view(request):
logout(request)
# Redirect to a success page.
该函数接受一个HttpRequest对象,无返回值。当调用该函数时,当前请求的session信息会全部清除。该用户即使没有登录,使用该函数也不会报错。
4-2 User
4-2.1 is_authenticated
User 对象属性:username, password(必填项)password用哈希算法保存到数据库
user对象的 is_authenticated()
如果是真正的 User 对象,返回值恒为 True 。 用于检查用户是否已经通过了认证。
通过认证并不意味着用户拥有任何权限,甚至也不检查该用户是否处于激活状态,这只是表明用户成功的通过了认证。 这个方法很重要, 在后台用request.user.is_authenticated()判断用户是否已经登录,如果true则可以向前台展示request.user.name
要求:
1 用户登陆后才能访问某些页面,
2 如果用户没有登录就访问该页面的话直接跳到登录页面
3 用户在跳转的登陆界面中完成登陆后,自动访问跳转到之前访问的地址
方法1:
def my_view(request):
if not request.user.is_authenticated():
return redirect('%s?next=%s' % (settings.LOGIN_URL, request.path))
方法2:
django已经为我们设计好了一个用于此种情况的装饰器:login_requierd()
from django.contrib.auth.decorators import login_required
@login_required
def my_view(request):
...
若用户没有登录,则会跳转到django默认的 登录URL '/accounts/login/ ' (这个值可以在settings文件中通过LOGIN_URL进行修改)。并传递 当前访问url的绝对路径 (登陆成功后,会重定向到该路径)。
4-2.2 创建用户
使用 create_user 辅助函数创建用户:
from django.contrib.auth.models import User
user = User.objects.create_user(username='',password='',email='')
4-2.3 check_password
2.3 、check_password(passwd)
用户需要修改密码的时候 首先要让他输入原来的密码 ,如果给定的字符串通过了密码检查,返回 True
4-2.4 修改密码
使用 set_password() 来修改密码
user = User.objects.get(username='')
user.set_password(password='')
user.save
4-3 匿名补充
匿名用户对象:
匿名用户
class models.AnonymousUser
django.contrib.auth.models.AnonymousUser类实现了django.contrib.auth.models.User
接口,但具有下面几个不同点:
id永远为None.
username永远为空字符串。
get_username()永远返回空字符串。
is_staff和is_superuser永远为False.
is_active永远为False。
groups和user_permissions永远为空。
is_anonymous()返回True而不是False.
is_authenticated()返回False 而不是True。
set_password()、check_ password()、save()和delete()引发NotImplementedError.
New in Django 1.8:
新增AnonymousUser.get_username()以更好地模拟django.contrib.auth.models.User.
4-4 认证装饰器
作用:解决重复的登录验证代码
if not request.user.is_authenticated:
return redirect('/login/')
基于用户认证组件的认证装饰器
settings.py:
LOGIN_URL = "/login/"
# 访问有login_required装饰器的页面,都要先跳转的认证路径,认证通过后才可以访问
login_requierd
from django.contrib.auth.decorators import login_required
@login_required
def my_view(request):
...
示例代码:
from django.shortcuts import render, HttpResponse, redirect
# Create your views here.
from django.contrib import auth
from django.contrib.auth.models import User
from django.contrib.auth.decorators import login_required
def login(request):
if request.method == "POST":
user = request.POST.get("user")
pwd = request.POST.get("pwd")
# 用Django的auth_user表进行判断
# 验证通过返回一个user对象,失败返回None
user_obj = auth.authenticate(username=user, password=pwd)
if user_obj:
# request.user的对象=user_obj当前登录对象
auth.login(request, user_obj)
next_url = request.GET.get("next", "/index/")
return redirect(next_url)
return render(request, "login.html")
@login_required
def index(request):
# if not request.user.is_authenticated:
# return redirect('/login/')
return render(request, "index.html")
def logout(request):
auth.logout(request) # 注销
return redirect("/login")
def reg(request):
if request.method == "POST":
user = request.POST.get("user")
pwd = request.POST.get("pwd")
user_obj = User.objects.create_user(username=user, password=pwd)
return redirect("/login/")
return render(request, "reg.html")
@login_required
def order(request):
# if not request.user.is_authenticated:
# return redirect('/login/')
return render(request, "order.html")
4-5 代码示例
链接数据库创建表格
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME':'authdemo', # 要连接的数据库,连接前需要创建好
'USER':'root',# 连接数据库的用户名
'PASSWORD':'root123',# 连接数据库的密码
'HOST':'127.0.0.1', # 连接主机,默认本级
'PORT':3306 # 端口 默认3306
}
}
urls.py:
from app01 import views
urlpatterns = [
path('admin/', admin.site.urls),
path('login/', views.login),
path('index/', views.index),
]
views.py:
from django.shortcuts import render, HttpResponse, redirect
from django.contrib import auth
from django.contrib.auth.models import User
# Create your views here.
def login(request):
if request.method == "POST":
user = request.POST.get("user")
pwd = request.POST.get("pwd")
# 用Django的auth_user表进行判断
# 验证通过返回一个user对象,失败返回None
user_obj = auth.authenticate(username=user, password=pwd)
if user_obj:
# request.user的对象=user_obj当前登录对象
auth.login(request, user_obj)
return redirect("/index/")
return render(request, "login.html")
def index(request):
print("request.user:", request.user.username) # 查看名称
print("request.user:", request.user.id) # id值
print("request.user:", request.user.is_anonymous) # 是不是匿名用户(返回True/False)
if not request.user.is_authenticated: # 检查用户是否已经通过了认证。
return redirect("/login/")
# 方法一:
# username = request.user.username
# return render(request, "index.html", {"username": username})
# 方法二:可以直接在index.html中直接调用
return render(request, "index.html")
def logout(request):
auth.logout(request) # 注销
return redirect("/login")
def reg(request):
if request.method == "POST":
user = request.POST.get("user")
pwd = request.POST.get("pwd")
user_obj = User.objects.create_user(username=user, password=pwd)
return redirect("/login/")
return render(request, "reg.html")
login.html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h3>登录</h3>
<form action="" method="post">
{% csrf_token %}
用户名:<input type="text" name="user">
密码:<input type="text" name="pwd">
<input type="submit">
</form>
</body>
</html>
index.html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
{#方法一#}
{#<h3>hi,{{ username }}</h3>#}
{#方法二#}
<h3>hi,{{ request.user.username }}</h3>
<h3>hi,{{ request.user.id }}</h3>
<a href="/logout/">注销</a>
</body>
</html>
reg.html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h3>注册</h3>
<form action="" method="post">
{% csrf_token %}
用户名:<input type="text" name="user">
密码:<input type="text" name="pwd">
<input type="submit">
</form>
</body>
</html>
Django默认已经提供了认证系统Auth模块,我们认证的时候,会使用auth模块里面给我们提供的表。认证系统包含:
- 用户管理
- 权限
- 用户组
- 密码哈希系统
- 用户登录或内容显示的表单和视图
- 一个可插拔的后台系统 admin
4-6 补充
1.Django用户模型类
Django认证系统中提供了用户模型类User保存用户的数据,默认的User包含以下常见的基本字段:
| 字段名 | 字段描述 |
|---|---|
username |
必选。150个字符以内。 用户名可能包含字母数字,_,@,+ . 和-个字符。 |
first_name |
可选(blank=True)。 少于等于30个字符。 |
last_name |
可选(blank=True)。 少于等于30个字符。 |
email |
可选(blank=True)。 邮箱地址。 |
password |
必选。 密码的哈希加密串。 (Django 不保存原始密码)。 原始密码可以无限长而且可以包含任意字符。 |
groups |
与Group 之间的多对多关系。 |
user_permissions |
与Permission 之间的多对多关系。 |
is_staff |
布尔值。 设置用户是否可以访问Admin 站点。 |
is_active |
布尔值。 指示用户的账号是否激活。 它不是用来控制用户是否能够登录,而是描述一种帐号的使用状态。 |
is_superuser |
是否是超级用户。超级用户具有所有权限。 |
last_login |
用户最后一次登录的时间。 |
date_joined |
账户创建的时间。 当账号创建时,默认设置为当前的date/time。 |
上面缺少一些字段,所以后面我们会对当前内置的用户模型进行改造,比如说它里面没有手机号字段,后面我们需要加上。
2.request.user
Django有一个默认中间件,叫做AuthenticationMiddleware,每次请求进来都会去session中去一个userid,取不到的话,赋值request.user = AnonymousUser() , 一个匿名用户对象。
当用户组件auth.login一旦执行,将userid到session中后,再有请求进入Django,将注册的userid对应的user对象赋值给request.user,即再后面的任何视图函数中都可以从request.user中取到该客户端的登录对象。
3.自定义用户表
from django.contrib.auth.models import AbstractUser
设置Auth认证模块使用的用户模型为我们自己定义的用户模型
格式:“子应用目录名.模型类名”
AUTH_USER_MODEL = 'users.User'
5 分页器
from django.core.paginator import Paginator

1.批量插入数据
from django.shortcuts import render, HttpResponse
from .models import Book
# Create your views here.
def create(request):
# 方式一:性能最差
"""
相当于执行1千条insert语句插入
for i in range(1,1001):
Book.objects.create(title="book"+str(i), price=i*2)
"""
# 方式二:批量插入
"""
将1千个实例对象放到book_list列表中,使用bulk_create批量插入
一条insert语句插入1千个值
"""
book_list = []
for i in range(1, 1001):
book = Book(title="book"+str(i), price=i*2)
book_list.append(book)
# bulk_create批量插入
Book.objects.bulk_create(book_list)
return HttpResponse('批量插入成功')
2.index视图
def index(request):
'''
批量导入数据:
Booklist=[]
for i in range(100):
Booklist.append(Book(title="book"+str(i),price=30+i*i))
Book.objects.bulk_create(Booklist)
分页器的使用:
book_list=Book.objects.all()
# 1.分页对象
paginator = Paginator(book_list, 10) # 每页10条数据
# 分页信息
print("count:",paginator.count) #数据总数
print("num_pages",paginator.num_pages) #总页数
print("page_range",paginator.page_range) #页码的列表
# 2.获取某页对象
page1=paginator.page(1) # 第1页的page对象
for i in page1: # 遍历第1页的所有数据对象
print(i)
print(page1.object_list) #第1页的所有数据,queryset对象
# 某页对象其他属性
page2=paginator.page(2)
print(page2.has_next()) #是否有下一页 返回布尔值
print(page2.next_page_number()) #下一页的页码
print(page2.has_previous()) #是否有上一页 返回布尔值
print(page2.previous_page_number()) #上一页的页码
# 抛错
#page=paginator.page(12) # error:EmptyPage
#page=paginator.page("z") # error:PageNotAnInteger
'''
from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
book_list = Book.objects.all()
paginator = Paginator(book_list, 10)
page = request.GET.get('page', 1)
current_page = int(page)
try:
print(page)
book_list = paginator.page(page)
except PageNotAnInteger:
book_list = paginator.page(1)
except EmptyPage:
book_list = paginator.page(paginator.num_pages)
return render(request, "index.html", {"book_list": book_list, "paginator": paginator, "currentPage": current_page})
2 index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<link rel="stylesheet" href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css"
integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
</head>
<body>
<div class="container">
<h4>分页器</h4>
<ul>
{% for book in book_list %}
<li>{{ book.title }} -----{{ book.price }}</li>
{% endfor %}
</ul>
<ul class="pagination" id="pager">
{% if book_list.has_previous %}
<li class="previous"><a href="/index/?page={{ book_list.previous_page_number }}">上一页</a></li>
{% else %}
<li class="previous disabled"><a href="#">上一页</a></li>
{% endif %}
{% for num in paginator.page_range %}
{% if num == currentPage %}
<li class="item active"><a href="/index/?page={{ num }}">{{ num }}</a></li>
{% else %}
<li class="item"><a href="/index/?page={{ num }}">{{ num }}</a></li>
{% endif %}
{% endfor %}
{% if book_list.has_next %}
<li class="next"><a href="/index/?page={{ book_list.next_page_number }}">下一页</a></li>
{% else %}
<li class="next disabled"><a href="#">下一页</a></li>
{% endif %}
</ul>
</div>
</body>
</html>
3.优化分页

from django.shortcuts import render, HttpResponse
from .models import Book
from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
def create(request):
book_list = []
for i in range(1, 101):
book = Book(title="book"+str(i), price=i*2)
book_list.append(book)
# bulk_create批量插入
Book.objects.bulk_create(book_list)
return HttpResponse('批量插入成功')
def books(request):
book_list = Book.objects.all()
# 只拿一部分书籍
page = Paginator(book_list, 4) # 每页100条数据,分10页
visit_page_num = int(request.GET.get('page', 1))
if visit_page_num == 1:
page_range = range(1, 4)
elif visit_page_num == page.num_pages:
page_range = range(page.num_pages - 2, page.num_pages + 1)
else:
page_range = [visit_page_num - 1, visit_page_num, visit_page_num + 1]
# 分页信息
# print(page.count) # 数据总个数
# print(page.num_pages) # 查看多少页数
# print(page.page_range) # 查看多少范围
try:
page_obj = page.page(visit_page_num)
page_obj.previous_page_number()
except EmptyPage:
page_obj = page.page(1)
except PageNotAnInteger:
page_obj = page.page(1)
return render(request, 'index2.html',
dict(book_list=page_obj, page=page, page_range=page_range, visit_page_num=visit_page_num))
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/3.4.1/css/bootstrap.min.css"
integrity="sha384-HSMxcRTRxnN+Bdg0JdbxYKrThecOKuH5zCYotlSAcp1+c8xmyTe9GYg1l9a69psu" crossorigin="anonymous">
</head>
<body>
<ul>
{% for book in book_list %}
<li>书籍:{{ book.title }} 价格:{{ book.price }}</li>
{% endfor %}
</ul>
<nav aria-label="Page navigation">
<ul class="pagination">
<li class="">
<a href="/books/?page=1" aria-label="Next">
<span aria-hidden="true">上一页</span>
</a>
</li>
<li class="disabled">
<a href="#" aria-label="Next">
<span aria-hidden="true">...</span>
</a>
</li>
{% for i in page_range %}
{% if i == visit_page_num %}
<li class="active"><a href="/books/?page={{ i }}">{{ i }}</a></li>
{% else %}
<li><a href="/books/?page={{ i }}">{{ i }}</a></li>
{% endif %}
{% endfor %}
<li class="disabled">
<a href="#" aria-label="Next">
<span aria-hidden="true">...</span>
</a>
</li>
<li>
<a href="/books/?page={{ page.num_pages }}" aria-label="Next">
<span aria-hidden="true">最后一页</span>
</a>
</li>
</ul>
</nav>
</body>
</html>

浙公网安备 33010602011771号