Django请求生命周期

首先:对于所有的web框架来说本质就是一个socket服务端,浏览器是socket客户端

Python之路【第十六篇续】Django进阶篇

路由系统

在Django的urls中我们可以根据一个URL对应一个函数名来定义路由规则如下:

from cmdb import views
urlpatterns = [
    url(r'^login/$', views.login),
    url(r'^index/$', views.index),
    url(r'^lists/$', views.lists),
    url(r'^add/$', views.add),
]

2、默认URL

上面一个URL对应一个函数!我们可以在整个的url最下面里设置一个默认的URL,当用户访问我们的网站的时候没有指定详细的URL的时候我们默认让他们跳转到一个URL。

urlpatterns = [
    url(r'^login/$', views.login),
    url(r'^index/$', views.index),
    url(r'^lists/$', views.lists),
    url(r'^add/$', views.add),
    url(r'^$', views.login),
]

这里需要注意下:当客户访问过来请求的时候,到达路由系统后是根据正则来匹配的,如果上面的匹配成功了,后面的路由规则将不会继续匹配,需要注意!!!!所以我们在后面都加一个$来做结尾

3、动态URL

3.1、动态URL传参

咱们看下园的分页连接如下图:

Python之路【第十六篇续】Django进阶篇

问:如果有这么多的RUL难道我们都要给他写一个路由规则吗?当然不是,会累死的,那他是怎么实现的呢?在上面的默认的URL中我们就说过他的路由功能是支持“正则表达式”的!

所以我们可以这么写:

    url(r'^user_list/(\d+)$', views.user_list),

views.user_list

def user_list(request,chose_id):
    return HttpResponse(chose_id)

这里当用户点击的时候login后的数字,会自动的传给views.user_list作为参数,因为这个是Django调用的,不是咱们调用的。

他这里会做两步操作:

1、获取user_list后面的这个值

2、运行views.user_list这个函数,并把获取的值自动传给views.user_list作为参数他的参数

3.2、动态URL传多个参数

问:我是否可以传多个参数?

可以传多个参数它是已/来分割的。

    url(r'^user_list/(\d+)/(\d+)$', views.user_list),

views.user_list

def user_list(request,chose_id,chose_id2):
    return HttpResponse(chose_id+chose_id2)

输入:http://127.0.0.1:8000/user_list/8/10  效果就是:810

他的顺序是:正序的,你先给他传那个值,第一个参数就是那个

3.3、动态URL传参数以Key:value的形式

通过正则表达式的分组来做!

    url(r'^user_list/(?P<v1>\d+)/(?P<V2>\d+)$', views.user_list),

这里?p<v1>这里的v1就是key,vlaue就是传进去的值,

def user_list(request,v2,v1):
    print v2 , v1
    return HttpResponse(v1+v2)

这样我们就不必按照顺序去取了,可以通过key,value的方式来取传进来的值

4、URL中专(分级匹配)

在实际的生产环境中有这么一种情况:在一个project下面有很多APP,那么我们的路由规则只能写在一个文件里吗?

Python之路【第十六篇续】Django进阶篇

当然不是,我们可以通过下面的方式来把他分开:

    url(r'^app01/', include("app01.urls")),

然后在app01内创建一个文件urls,不要忘记注册app。然后在访问app01里的url的时候通过:hostip:port/app01/index  or  hostip:port/app01/login

5、基于反射实现动态路由设计

有很多的WEB框架,他和Django不太一样。比如mvc他会将所有的URL做成一个分类的形式。在Django中咱们一般是一个url对应一个函数。

但是在其他的WEB框架中他们也把url也进行用正则处理了。比如下面:

    url(r'^(?P<controller>\w+)/(?P<action>\w+)', mp),
    #咱们给他做个定义mp中第一个是文件比如
    #home.py   第二个参数是文件中的函数 def index
    #
    #/home/index/
    #/login/index/
    #/update/index/

但是上面的方法仅仅是通过反射来实现的,通过文件找到里面的函数然后执行!

但是在Django中不建议使用此方法。因为不同的WEB框架建议你使用不同的方式,Django就不建议使用反射

中间件

中间件定义:

  中间件是一个、一个的管道,如果相对任何所有的通过Django的请求进行管理都需要自定义中间件

  中间件可以对进来的请求和出去的请求进行控制

  中间件是一类。

Python之路【第十六篇续】Django进阶篇

看下面的代码在settings里中间件的类:

MIDDLEWARE_CLASSES = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    # 'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.auth.middleware.SessionAuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
]

当有请求过来的时候,默认从上倒下执行!然后在返回的时候从下面在返回回去,如下图:

Python之路【第十六篇续】Django进阶篇

2、自定义中间件

中间件中可以定义四个方法,分别是:

  • process_request(self,request)
  • process_view(self, request, callback, callback_args, callback_kwargs)
  • process_exception(self, request, exception)
  • process_response(self, request, response)

process_exception 这个方法只有在出现错误的时候才会触发

先写一个自定义中间件,然后在看他的原理和源码:

2.1、自定义中间件

Python之路【第十六篇续】Django进阶篇\

class Testmiddle(object):
    def process_request(self,request):
        print 'Testmiddle process_request'
    def process_view(self, request, callback, callback_args, callback_kwargs):
        print 'Testmiddle process_view'
    def process_exception(self, request, exception):
        pass
    def process_response(self, request, response):
        print 'Testmiddle process_response'
        return response
    
class Nextmiddle(object):
    def process_request(self,request):
        print 'Nextmiddle process_request'
    def process_view(self, request, callback, callback_args, callback_kwargs):
        print 'Nextmiddle process_view'
    def process_exception(self, request, exception):
        pass
    def process_response(self, request, response):
        print 'Nextmiddle process_response'
        return response

2.2、注册中间件

MIDDLEWARE_CLASSES = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
   # 'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.auth.middleware.SessionAuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
    'middleware.middle.Testmiddle',
    'middleware.middle.Nextmiddle',
]

2.3、测试使用url和views

from app01 import views
urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^index/$', views.index),

]
def index(request):
    print 'This app01 Views.index'
    return HttpResponse('OK')

2.4、查看输出结果:

'''
Testmiddle process_request
Nextmiddle process_request
Testmiddle process_view
Nextmiddle process_view
This app01 Views.index
Nextmiddle process_response
Testmiddle process_response
'''

从输出结果可以看出:

他是先执行Testmiddle 的request 方法又执行了Nextmiddle的 process_request方法。。。。

2.5、原理:

当请求进来了到达中间件

去settings里面找到MIDDLEWARE_CLASSES,MIDDLEWARE_CLASSES是一个元组

有4个列表:

process_request_lsit = []
process_view_list = []
process_response_list = []
然后他循环MIDDLEWARE_CLASSES这个类:
forin MIDDLEWARE_CLASSES:
  obj = 类()
  if obj里有process_request方法:
    process_request_lsit.append(obj.process_request)

然后循环后后执行:

for i in process_request_list:
  i() #加括号执行方法

for i in process_view_list:
    i() 
    ............

源码:

def load_middleware(self):
        """
        Populate middleware lists from settings.MIDDLEWARE_CLASSES.

        Must be called after the environment is fixed (see __call__ in subclasses).
        """
        self._view_middleware = []
        self._template_response_middleware = []
        self._response_middleware = []
        self._exception_middleware = []

        request_middleware = []
        for middleware_path in settings.MIDDLEWARE_CLASSES:
            mw_class = import_string(middleware_path)
            try:
                mw_instance = mw_class()
            except MiddlewareNotUsed as exc:
                if settings.DEBUG:
                    if six.text_type(exc):
                        logger.debug('MiddlewareNotUsed(%r): %s', middleware_path, exc)
                    else:
                        logger.debug('MiddlewareNotUsed: %r', middleware_path)
                continue

            if hasattr(mw_instance, 'process_request'):
                request_middleware.append(mw_instance.process_request)
            if hasattr(mw_instance, 'process_view'):
                self._view_middleware.append(mw_instance.process_view)
            if hasattr(mw_instance, 'process_template_response'):
                self._template_response_middleware.insert(0, mw_instance.process_template_response)
            if hasattr(mw_instance, 'process_response'):
                self._response_middleware.insert(0, mw_instance.process_response)
            if hasattr(mw_instance, 'process_exception'):
                self._exception_middleware.insert(0, mw_instance.process_exception)

        # We only assign to this when initialization is complete as it is used
        # as a flag for initialization being complete.
        self._request_middleware = request_middleware
middleware

相关文章: