乐趣区

关于后端:三djanjo

Django

提醒:本文依据 b 站黑马 python 课整顿

链接指引 => 黑马程序员 python 企业级开发我的项目 - 手把手从 0 到 1 开发《美多商城》

视图介绍和我的项目筹备

视图介绍

  • 视图就是利用中 views.py 文件中的函数
  • 视图的第一个参数必须为 HttpRequest 对象,还可能蕴含下参数如

    • 通过正则表达式组获取的地位参数
    • 通过正则表达式组取得的关键字参数
  • 视图必须返回一个 HttpResponse 对象或子对象作为响应

    • 子对象:JsonResponse HttpResponseRedirect
  • 视图负责承受 Web 申请 HttpRequest,进行逻辑解决,返回 Web 响应 HttpResponse 给请求者

    • 响应内容能够是 HTML 内容,404 谬误,重定向,json 数据 …
  • 视图处理过程如下图:

    应用视图时须要进行两步操作,两步操作不分先后

    1. 配置 URLconf
    2. 在利用 /views.py 中定义视图

HttpRequest 对象

回忆一下,利用 HTTP 协定向服务器传参有几种路径?

  • 提取 URL 的特定局部,如 /weather/beijing/2018,能够在服务器端的路由中用正则表达式截取;
  • 查问字符串(query string),形如 key1=value1&key2=value2;
  • 申请体(body)中发送的数据,比方表单数据、json、xml;
  • 在 http 报文的头(header)中。

1 URL 门路参数

  • 如果想从 URL 中获取值 http://127.0.0.1:8000/18/188/
  • 利用中 urls.py

    from django.urls import path
    from book.views import goods
    urlpatterns = [path('<cat_id>/<goods_id>/',goods)
    ]
  • 视图中函数: 参数的地位不能错

    from django.http import JsonResponse
    def goods(request,cat_id,id):
    
      return JsonResponse({'cat_id':cat_id,'id':id})

2 Django 中的 QueryDict 对象

HttpRequest 对象的属性 GET、POST 都是 QueryDict 类型的对象

与 python 字典不同,QueryDict 类型的对象用来解决同一个键带有多个值的状况

  • 办法 get():依据键获取值

     如果一个键同时领有多个值将获取最初一个值

    如果键不存在则返回 None 值,能够设置默认值进行后续解决

    get('键', 默认值)
  • 办法 getlist():依据键获取值,值以列表返回,能够获取指定键的所有值
    如果键不存在则返回空列表[],能够设置默认值进行后续解决

    getlist('键', 默认值)

3. 查问字符串 Query String

获取申请门路中的查问字符串参数(形如?k1=v1&k2=v2),能够通过 request.GET 属性获取,返回 QueryDict 对象。

# /get/?a=1&b=2&a=3

def get(request):
    a = request.GET.get('a')
    b = request.GET.get('b')
    alist = request.GET.getlist('a')
    print(a)  # 3
    print(b)  # 2
    print(alist)  # ['1', '3']
    return HttpResponse('OK')

重要:查问字符串不辨别申请形式,即倘若客户端进行 POST 形式的申请,仍然能够通过 request.GET 获取申请中的查问字符串数据。

4 申请体

申请体数据格式不固定,能够是表单类型字符串,能够是 JSON 字符串,能够是 XML 字符串,应区别对待。

能够发送申请体数据的申请形式有POST、PUT、PATCH、DELETE

Django 默认开启了 CSRF 防护,会对上述申请形式进行 CSRF 防护验证,在测试时能够敞开 CSRF 防护机制,办法为在 settings.py 文件中正文掉 CSRF 中间件,如:

4.1 表单类型 Form Data

前端发送的表单类型的申请体数据,能够通过 request.POST 属性获取,返回 QueryDict 对象。

def post(request):
    a = request.POST.get('a')
    b = request.POST.get('b')
    alist = request.POST.getlist('a')
    print(a)
    print(b)
    print(alist)
    return HttpResponse('OK')

4.2 非表单类型 Non-Form Data

非表单类型的申请体数据,Django 无奈主动解析,能够通过 request.body 属性获取最原始的申请体数据,本人依照申请体格式(JSON、XML 等)进行解析。request.body 返回 bytes 类型。

例如要获取申请体中的如下 JSON 数据

{"a": 1, "b": 2}

能够进行如下办法操作:

import json

def post_json(request):
    json_str = request.body
    json_str = json_str.decode()  # python3.6 无需执行此步
    req_data = json.loads(json_str)
    print(req_data['a'])
    print(req_data['b'])
    return HttpResponse('OK')

5. 验证 path 中门路参数

零碎为咱们提供了一些路由转换器地位在django.urls.converters.py

DEFAULT_CONVERTERS = {'int': IntConverter(), # 匹配正整数,蕴含 0
    'path': PathConverter(), # 匹配任何非空字符串,蕴含了门路分隔符
    'slug': SlugConverter(), # 匹配字母、数字以及横杠、下划线组成的字符串
    'str': StringConverter(), # 匹配除了门路分隔符(/)之外的非空字符串,这是默认的模式
    'uuid': UUIDConverter(), # 匹配格式化的 uuid,如 075194d3-6885-417e-a8a8-6c931e272f00}

咱们能够通过以下模式来验证数据的类型

 path('<int:cat_id>/<int:id>/',goods),

自定义转换器
http://127.0.0.1:8000/1850000… 默认的路由转换器中,没有专门用来匹配手机号的路由转换器。所以在应用 path() 实现需求时,就无奈间接应用默认的路由转换器。如果默认的路由转换器无奈满足需要时,咱们就须要自定义路由转换器。在任意能够被导入的 python 文件中,都能够 自定义路由转换器

  • 比方:在工程根目录下,新建 converters.py 文件,用于自定义路由转换器

    class MobileConverter:
    """自定义路由转换器:匹配手机号"""
    # 匹配手机号码的正则
    regex = '1[3-9]\d{9}'
    
    def to_python(self, value):
        # 将匹配后果传递到视图外部时应用
        return int(value)
    
    def to_url(self, value):
        # 将匹配后果用于反向解析传值时应用
        return str(value)
  • 注册自定义路由转换器

    • 在总路由中,注册自定义路由转换器
    from django.urls import register_converter
    
    # 注册自定义路由转换器
    # register_converter(自定义路由转换器, '别名')
    register_converter(MobileConverter, 'mobile')
    
    urlpatterns = []
  • 应用自定义路由转换器

    # 测试 path()中自定义路由转换器提取门路参数:手机号 http://127.0.0.1:8000/18500001111/
    path('<mobile:phone>/',register)

6 申请头

能够通过 request.META 属性获取申请头 headers 中的数据,request.META为字典类型。

常见的申请头如:

  • CONTENT_LENGTH– The length of the request body (as a string).
  • CONTENT_TYPE– The MIME type of the request body.
  • HTTP_ACCEPT– Acceptable content types for the response.
  • HTTP_ACCEPT_ENCODING– Acceptable encodings for the response.
  • HTTP_ACCEPT_LANGUAGE– Acceptable languages for the response.
  • HTTP_HOST– The HTTP Host header sent by the client.
  • HTTP_REFERER– The referring page, if any.
  • HTTP_USER_AGENT– The client’s user-agent string.
  • QUERY_STRING– The query string, as a single (unparsed) string.
  • REMOTE_ADDR– The IP address of the client.
  • REMOTE_HOST– The hostname of the client.
  • REMOTE_USER– The user authenticated by the Web server, if any.
  • REQUEST_METHOD– A string such as”GET”or”POST”.
  • SERVER_NAME– The hostname of the server.
  • SERVER_PORT– The port of the server (as a string).
    具体应用如:

    def get_headers(request):
      print(request.META['CONTENT_TYPE'])
      return HttpResponse('OK')

7 其余罕用 HttpRequest 对象属性

  • method:一个字符串,示意申请应用的 HTTP 办法,罕用值包含:’GET’、’POST’。
  • user:申请的用户对象。
  • path:一个字符串,示意申请的页面的残缺门路,不蕴含域名和参数局部。
  • encoding:一个字符串,示意提交的数据的编码方式。

    • 如果为 None 则示意应用浏览器的默认设置,个别为 utf-8。
    • 这个属性是可写的,能够通过批改它来批改拜访表单数据应用的编码,接下来对属性的任何拜访将应用新的 encoding 值。
  • FILES:一个相似于字典的对象,蕴含所有的上传文件。

HttpResponse 对象

视图在接管申请并解决后,必须返回 HttpResponse 对象或子对象。HttpRequest 对象由 Django 创立,HttpResponse 对象由开发人员创立。

1 HttpResponse

能够应用 django.http.HttpResponse 来结构响应对象。

HttpResponse(content= 响应体, content_type= 响应体数据类型, status= 状态码)

也可通过 HttpResponse 对象属性来设置响应体、响应体数据类型、状态码:

  • content:示意返回的内容。
  • status_code:返回的 HTTP 响应状态码。
    响应头能够间接将 HttpResponse 对象当做字典进行响应头键值对的设置:

    response = HttpResponse()
    response['itcast'] = 'Python'  # 自定义响应头 Itcast, 值为 Python

    示例:

    from django.http import HttpResponse
    
    def response(request):
      return HttpResponse('itcast python', status=400)
      或者
      response = HttpResponse('itcast python')
      response.status_code = 400
      response['itcast'] = 'Python'
      return response

2 HttpResponse 子类

Django 提供了一系列 HttpResponse 的子类,能够疾速设置状态码

  • HttpResponseRedirect 301
  • HttpResponsePermanentRedirect 302
  • HttpResponseNotModified 304
  • HttpResponseBadRequest 400
  • HttpResponseNotFound 404
  • HttpResponseForbidden 403
  • HttpResponseNotAllowed 405
  • HttpResponseGone 410
  • HttpResponseServerError 500

3 JsonResponse

若要返回 json 数据,能够应用 JsonResponse 来结构响应对象,作用:

  • 帮忙咱们将数据转换为 json 字符串
  • 设置响应头 Content-Type 为 application/json

    from django.http import JsonResponse
    
    def response(request):
      return JsonResponse({'city': 'beijing', 'subject': 'python'})

4 redirect 重定向

from django.shortcuts import redirect

def response(request):
    return redirect('/get_header')

状态放弃

  • 浏览器申请服务器是无状态的。
  • 无状态:指一次用户申请时,浏览器、服务器无奈晓得之前这个用户做过什么,每次申请都是一次新的申请。
  • 无状态起因:浏览器与服务器是应用 Socket 套接字进行通信的,服务器将申请后果返回给浏览器之后,会敞开以后的 Socket 连贯,而且服务器也会在解决页面结束之后销毁页面对象。
  • 有时须要放弃下来用户浏览的状态,比方用户是否登录过,浏览过哪些商品等
  • 实现状态放弃次要有两种形式:

    • 在客户端存储信息应用 Cookie
    • 在服务器端存储信息应用 Session

Cookie

Cookie 的特点

  • Cookie 以键值对的格局进行信息的存储。
  • Cookie 基于域名平安,不同域名的 Cookie 是不能相互拜访的,如拜访 itcast.cn 时向浏览器中写了 Cookie 信息,应用同一浏览器拜访 baidu.com 时,无法访问到 itcast.cn 写的 Cookie 信息。
  • 当浏览器申请某网站时,会将浏览器存储的跟网站相干的所有 Cookie 信息提交给网站服务器。

1 设置 Cookie

能够通过 HttpResponse 对象中的 set_cookie 办法来设置 cookie。

HttpResponse.set_cookie(cookie 名, value=cookie 值, max_age=cookie 有效期)
  • max_age 单位为秒,默认为 None。如果是长期 cookie,可将 max_age 设置为 None。
    示例:

    def cookie(request):
      response = HttpResponse('ok')
      response.set_cookie('itcast1', 'python1')  # 长期 cookie
      response.set_cookie('itcast2', 'python2', max_age=3600)  # 有效期一小时
      return response

    2 读取 Cookie

    能够通过 HttpResponse 对象的 COOKIES 属性来读取本次申请携带的 cookie 值。request.COOKIES 为字典类型。

    def cookie(request):
      cookie1 = request.COOKIES.get('itcast1')
      print(cookie1)
      return HttpResponse('OK')

    3 删除 Cookie

    能够通过 HttpResponse 对象中的 delete_cookie 办法来删除。

    response.delete_cookie('itcast2')

Session

1 启用 Session

Django 我的项目默认启用 Session。

能够在 settings.py 文件中查看,如图所示

如需禁用 session,将上图中的 session 中间件正文掉即可。

2 存储形式

在 settings.py 文件中,能够设置 session 数据的存储形式,能够保留在数据库、本地缓存等。

2.1 数据库

存储在数据库中,如下设置能够写,也能够不写,这是默认存储形式。

SESSION_ENGINE='django.contrib.sessions.backends.db'

如果存储在数据库中,须要在项 INSTALLED_APPS 中装置 Session 利用。

数据库中的表如图所示

表构造如下

由表构造可知,操作 Session 包含三个数据:键,值,过期工夫。

2.2 本地缓存

存储在本机内存中,如果失落则不能找回,比数据库的形式读写更快。

SESSION_ENGINE='django.contrib.sessions.backends.cache'
2.3 混合存储

优先从本机内存中存取,如果没有则从数据库中存取。

SESSION_ENGINE='django.contrib.sessions.backends.cached_db'
2.4 Redis

在 redis 中保留 session,须要引入第三方扩大,咱们能够应用 django-redis 来解决。

文档

1)装置扩大

pip install django-redis

2)配置

在 settings.py 文件中做如下设置

CACHES = {
    'default': {
        'BACKEND': 'django_redis.cache.RedisCache',
        'LOCATION': 'redis://127.0.0.1:6379/1',
        'OPTIONS': {'CLIENT_CLASS': 'django_redis.client.DefaultClient',}
    }
}
SESSION_ENGINE = 'django.contrib.sessions.backends.cache'
SESSION_CACHE_ALIAS = 'default'

留神
如果 redis 的 ip 地址不是本地回环 127.0.0.1,而是其余地址,拜访 Django 时,可能呈现 Redis 连贯谬误,如下:

解决办法:

批改 redis 的配置文件,增加特定 ip 地址。

关上 redis 的配置文件

sudo vim /etc/redis/redis.conf

在如下配置项进行批改(如要增加 10.211.55.5 地址)

重新启动 redis 服务

sudo service redis-server restart

3 Session 操作

通过 HttpRequest 对象的 session 属性进行会话的读写操作。

1)以键值对的格局写 session。

request.session['键']= 值

2)依据键读取值。

request.session.get('键', 默认值)

3)革除所有 session,在存储中删除值局部。

request.session.clear()

4)革除 session 数据,在存储中删除 session 的整条数据。

request.session.flush()

5)删除 session 中的指定键及值,在存储中只删除某个键及对应的值。

del request.session['键']

6)设置 session 的有效期

request.session.set_expiry(value)
  • 如果 value 是一个整数,session 将在 value 秒没有流动后过期。
  • 如果 value 为 0,那么用户 session 的 Cookie 将在用户的浏览器敞开时过期。
  • 如果 value 为 None,那么 session 有效期将采纳零碎默认值,默认为两周,能够通过在 settings.py 中设置 SESSION_COOKIE_AGE 来设置全局默认值。

类视图与中间件

类视图

如何在一个视图中解决 get 和 post 申请

注册视图解决 get 和 post 申请

以函数的形式定义的视图称为函数视图,函数视图便于了解。然而遇到一个视图对应的门路提供了多种不同 HTTP 申请形式的反对时,便须要在一个函数中编写不同的业务逻辑,代码可读性与复用性都不佳。

def register(request):
    """解决注册"""

    # 获取申请办法,判断是 GET/POST 申请
    if request.method == 'GET':
        # 解决 GET 申请,返回注册页面
        return render(request, 'register.html')
    else:
        # 解决 POST 申请,实现注册逻辑
        return HttpResponse('这里实现注册逻辑')

类视图应用

在 Django 中也能够应用类来定义一个视图,称为类视图。

应用类视图能够将视图对应的不同申请形式以类中的不同办法来区别定义。如下所示

from django.views.generic import View

class RegisterView(View):
    """类视图:解决注册"""

    def get(self, request):
        """解决 GET 申请,返回注册页面"""
        return render(request, 'register.html')

    def post(self, request):
        """解决 POST 申请,实现注册逻辑"""
        return HttpResponse('这里实现注册逻辑')

类视图的益处:

  • 代码可读性好
  • 类视图绝对于函数视图有更高的复用性,如果其余中央须要用到某个类视图的某个特定逻辑,间接继承该类视图即可

定义类视图须要继承自 Django 提供的父类 View,可应用 from django.views.generic import View 或者 from django.views.generic.base import View 导入,定义形式如上所示。

配置路由时,应用类视图的 as_view()办法来增加。

urlpatterns = [
    # 视图函数:注册
    # path('register/', views.register),
    # 类视图:注册
    path('register/', views.RegisterView.as_view()),
]
类视图原理(理解)
@classonlymethod
    def as_view(cls, **initkwargs):
        """Main entry point for a request-response process."""
        ... 省略代码...

        def view(request, *args, **kwargs):
            self = cls(**initkwargs)
            if hasattr(self, 'get') and not hasattr(self, 'head'):
                self.head = self.get
            self.request = request
            self.args = args
            self.kwargs = kwargs
            # 调用 dispatch 办法,依照不同申请形式调用不同申请办法
            return self.dispatch(request, *args, **kwargs)

        ... 省略代码...

        # 返回真正的函数视图
        return view


    def dispatch(self, request, *args, **kwargs):
        # Try to dispatch to the right method; if a method doesn't exist,
        # defer to the error handler. Also defer to the error handler if the
        # request method isn't on the approved list.
        if request.method.lower() in self.http_method_names:
            handler = getattr(self, request.method.lower(), self.http_method_not_allowed)
        else:
            handler = self.http_method_not_allowed
        return handler(request, *args, **kwargs)

类视图的多继承重写 dispatch

class CenterView(View):

    def get(self,request):
        return HttpResponse("OK")

    def post(self,request):
        return HttpResponse("OK")

应用面向对象多继承的个性。

class CenterView(LoginRequireMixin,View):

    def get(self,request):
        return HttpResponse("OK")

    def post(self,request):
        return HttpResponse("OK")

中间件

1 中间件的定义方法

Django 在中间件中预置了六个办法,这六个办法会在不同的阶段主动执行,对输出或输入进行干涉。

  • 1.1 初始化办法:

    • 启动 Django 程序,初始化中间件时,主动调用一次,用于确定是否启用以后中间件
    def __init__(self, get_response=None):
    pass
  • 1.2 解决申请前的办法:(重要)

    • 在解决每个申请前,主动调用,返回 None 或 HttpResponse 对象
    def process_request(self, request):
    pass
  • 1.3 解决视图前的办法:(重要)

    • 在解决每个视图前,主动调用,返回 None 或 HttpResponse 对象
    def process_view(self, request, view_func, view_args, view_kwargs):
    pass
  • 1.4 解决模板响应前的办法:

    • 在解决每个模板响应前,主动调用,返回实现了 render 办法的响应对象
    def process_template_response(self, request, response):
    pass
  • 1.5 解决响应后的办法:(重要)

    • 在每个响应返回给客户端之前,主动调用,返回 HttpResponse 对象
    def process_response(self, request, response):
    pass
  • 1.6 异样解决:

    • 当视图抛出异样时,主动调用,返回一个 HttpResponse 对象
    def process_exception(self, request,exception):
    pass

定义中间件

# 导入中间件的父类
from django.utils.deprecation import MiddlewareMixin


class TestMiddleware1(MiddlewareMixin):
    """自定义中间件"""
    def process_request(self, request):
        """解决申请前主动调用"""
        print('process_request1 被调用')

    def process_view(self, request, view_func, view_args, view_kwargs):
        # 解决视图前主动调用
        print('process_view1 被调用')

    def process_response(self, request, response):
        """在每个响应返回给客户端之前主动调用"""
        print('process_response1 被调用')
        return response

定义好中间件后,须要在 settings.py 文件中增加注册中间件

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',
    'book.middleware.TestMiddleware1',  # 增加中间件
]

定义一个视图进行测试

def middleware(request):
    print('view 视图被调用')
    return HttpResponse('OK')

执行后果

process_request1 被调用
process_view1 被调用
process_response1 被调用

2 多个中间件的执行程序

  • 在申请视图被解决前,中间件由上至下顺次执行
  • 在申请视图被解决后,中间件由下至上顺次执行

示例:

定义两个中间件

from django.utils.deprecation import MiddlewareMixin


class TestMiddleware1(MiddlewareMixin):
    """自定义中间件"""
    def process_request(self, request):
        """解决申请前主动调用"""
        print('process_request1 被调用')

    def process_view(self, request, view_func, view_args, view_kwargs):
        # 解决视图前主动调用
        print('process_view1 被调用')

    def process_response(self, request, response):
        """在每个响应返回给客户端之前主动调用"""
        print('process_response1 被调用')
        return response


class TestMiddleware2(MiddlewareMixin):
    """自定义中间件"""
    def process_request(self, request):
        """解决申请前主动调用"""
        print('process_request2 被调用')

    def process_view(self, request, view_func, view_args, view_kwargs):
        # 解决视图前主动调用
        print('process_view2 被调用')

    def process_response(self, request, response):
        """在每个响应返回给客户端之前主动调用"""
        print('process_response2 被调用')
        return response

注册增加两个中间件

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',
    'book.middleware.TestMiddleware1',  # 增加
    'book.middleware.TestMiddleware2',  # 增加
]

执行后果

process_request1 被调用
process_request2 被调用
process_view1 被调用
process_view2 被调用
process_response2 被调用
process_response1 被调用

总结

以上就是 Django 第三局部,之后会继续更新,欢送大家点赞关注呀~~

退出移动版