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 pathfrom book.views import goodsurlpatterns = [  path('<cat_id>/<goods_id>/',goods)]
  • 视图中函数: 参数的地位不能错

    from django.http import JsonResponsedef 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=3def 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 jsondef 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 HttpResponsedef 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 JsonResponsedef response(request):  return JsonResponse({'city': 'beijing', 'subject': 'python'})

4 redirect重定向

from django.shortcuts import redirectdef 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 Viewclass 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 MiddlewareMixinclass 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 MiddlewareMixinclass 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 responseclass 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第三局部,之后会继续更新,欢送大家点赞关注呀~~