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

  1. process_request默认返回None,返回None,则继续执行下一个中间件的process_request;一旦返回响应体对象,则会拦截返回。
  2. process_response必须有一个形参response,并return response;这是view函数返回的响应体,像接力棒一样传承给最后的客户端。

image


2.注册中间件

MIDDLEWARE = [
    ...
    'app01.mdws.Md1',
    'app01.mdws.Md2'
]

3.构建index路由

# path('index/', views.index),


def index(request):
    print("index 视图函数执行...")
    return HttpResponse("hello yuan")

启动项目,访问index路径:

image

后台打印结果:

Md1请求
Md2请求
index 视图函数执行...
Md2返回
Md1返回

所以,通过结果我们看出中间件的执行顺序:

image


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 其它

image

image

疑问:prcess_request的执行时,是否已执行了路由匹配?

request.resolver_match
没有执行,只有在中间价全部通过后,进行路由匹配--->在经过 process_view

注意:process_view是在django中源码中写死了。

image


小结

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

image


我们知道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流程图

image


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流程图

image


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"

image

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/')
  1. session 在服务器端,cookie 在客户端(浏览器)
  2. session 默认被存在在服务器的一个文件里(不是内存)
  3. session 的运行依赖 session id,而 session id 是存在 cookie 中的.
  4. session 可以放在 文件、数据库、或内存中都可以。
  5. 用户验证这种场合一般会用 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

image


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.优化分页

image

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 }}&nbsp;价格:{{ 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>
posted @ 2022-08-11 10:52  角角边  Views(90)  Comments(0)    收藏  举报