zoukankan      html  css  js  c++  java
  • Django笔记 —— 高级视图和URL配置

      最近在学习Django,打算玩玩网页后台方面的东西,因为一直很好奇但却没怎么接触过。Django对我来说是一个全新的内容,思路想来也是全新的,或许并不能写得很明白,所以大家就凑合着看吧~

      本篇笔记(其实我的所有笔记都是),并不会过于详细的讲解。因此如果有大家看不明白的地方,欢迎在我正版博客下留言,有时间的时候我很愿意来这里与大家探讨问题。(当然,不能是简简单单就可以百度到的问题-.-)

      我所选用的教材是《The Django Book 2.0》,本节是第八章,高级视图和URL配置。


      在基础部分的学习中,我体会到了一点经验:傻瓜教程最适合作为本书的笔记了~因为本书对于原理讲得很细,看一遍也就能基本理解,但由于讲得太细,具体操作步骤正是其不足。因此,读这本书,如果配上操作教程式的笔记,那复习起来就很舒服了 ^.^

      因此,高级部分的笔记,将给出很多操作教程,没看过书的同学请先看了书再来看笔记~


    0. 目录

      1. 设置DEBUG参数

      2. URL回顾与初试

      3. URLconf的一些特性

      4. 视图中的调度函数

      4+. 动态参数的传递

      5. 视图中的预处理函数

      6. URL中的include函数

    1. 设置DEBUG参数

      (1) 在settings.py中,将DEBUG参数设置为False

      (2) 在settings.py中,将原本是空的ALLOWED_HOSTS参数中加入'127.0.0.1'。否则,当你尝试运行网站时,会在命令行中报错:

        CommandError: You must set settings.ALLOWED_HOSTS if DEBUG is False.

    2. URL回顾与初试

      关于URLconf,即urls.py中urlpatterns参数中的每一项正则表达式,有些很方便的技巧可以大大简化代码。

      先通过几个例子,来回忆一下URLconf(正则表达式)的写法:

    URL地址 视图函数
    http://127.0.0.1:8000/ def index(request): 
    http://127.0.0.1:8000/hello/ def hello(request): 
    http://127.0.0.1:8000/diary/diary_title/ def diary_title(request, title, count='10'):  
    http://127.0.0.1:8000/admin/ # Django内置 

      就以上面这些视图为例,他们对应的URLconf代码如下:

    from django.conf.urls import include, url
    from django.contrib import admin
    from mysite import views
    
    urlpatterns = [
        url(r'^$', views.index),
        url(r'^hello/$', views.hello),
        url(r'^diary/(w+)/$', views.diary_title),
        url(r'^admin/', include(admin.site.urls)),
    ]

       那么,在此基础上,我们再介绍新的技巧,把上面的例子不断扩展。

      首先,看版本1:

    from django.conf.urls import include, url
    from django.contrib import admin
    from django.conf import settings
    
    urlpatterns = [
        url(r'^$', 'mysite.views.index'),
        url(r'^hello/$', 'mysite.views.hello'),
        url(r'^diary/(?P<title>w+)/$', 'mysite.views.diary_title'),
    ]
    
    if settings.DEBUG:
        urlpatterns += [
            url(r'^admin/', include(admin.site.urls)),
        ]

      这时,仅在DEBUG模式下才能进入admin,而且传入的title变量URLconf可读性更高,且连接URL与视图函数时省去了import的麻烦,改为直接写地址。

      再来看版本2:

    from django.conf.urls import include, url
    from django.contrib import admin
    from django.conf import settings
    
    urlpatterns = [
        url(r'^$', 'mysite.views.index', {'visitor': 'icedream'}),
        url(r'^hello/$', 'mysite.views.hello', {'visitor': 'icedream'}),
        url(r'^diary/(?P<title>w+)/$', 'mysite.views.diary_title', {'visitor': 'icedream'}),
    ]
    
    if settings.DEBUG:
        urlpatterns += [
            url(r'^admin/', include(admin.site.urls)),
        ]

      这次,又在版本1的基础上,向视图函数多传入了一个变量visitor,当然,视图函数也应该多接收一个变量了。

      可能有人已经注意到,我们在 视图函数diary_title 中设置了一个 count='10' 的默认值,那么下面是版本3:

    from django.conf.urls import include, url
    from django.contrib import admin
    from django.conf import settings
    
    urlpatterns = [
        url(r'^$', 'mysite.views.index', {'visitor': 'icedream'}),
        url(r'^hello/$', 'mysite.views.hello', {'visitor': 'icedream'}),
        url(r'^diary/(?P<title>w+)/$', 'mysite.views.diary_title', {'visitor': 'icedream'}),
        url(r'^diary/(?P<title>w+)/(?P<count>d+)$', 'mysite.views.diary_title', {'visitor': 'icedream'}),
    ]
    
    if settings.DEBUG:
        urlpatterns += [
            url(r'^admin/', include(admin.site.urls)),
        ]

      这样一来,便可以在传入count时改变默认值,而不传入时依旧可以匹配默认值下的视图函数。

    3. URLconf的一些特性

      注意,如果URL中接收了一个参数title,同时后面字典中所传参数也有一个title,那么URL中接收的title会被忽略。

      还有,URLconf的匹配是短路逻辑,这点提一下,可以适当使用。

      还有,URLconf中传入视图函数的参数,全都是字符串,这点需要注意(注意count的默认值,为了保持一直,我也设置成了字符串)。

      还有,URLconf匹配时,会忽略请求方法部分(例如GET),这点无需担心。

    4. 视图中的调度函数

      为了视图的结构更好,我们可以写一些函数起到调度的作用,就像这样:

    # views.py
    
    from django.http import Http404, HttpResponseRedirect
    from django.shortcuts import render_to_response
    
    def method_splitter(request, GET=None, POST=None):
        if request.method == 'GET' and GET is not None:
            return GET(request)
        elif request.method == 'POST' and POST is not None:
            return POST(request)
        raise Http404
    
    def some_page_get(request):
        assert request.method == 'GET'
        do_something_for_get()
        return render_to_response('page.html')
    
    def some_page_post(request):
        assert request.method == 'POST'
        do_something_for_post()
        return HttpResponseRedirect('/someurl/')
    
    # urls.py
    
    from django.conf.urls import url
    from mysite import views
    
    urlpatterns = [
        # ...
        url(r'^somepage/$', views.method_splitter, {'GET': views.some_page_get, 'POST': views.some_page_post}),
        # ...
    ]

       在此基础上,我们还可以把 method_splitter 函数做如下改进:

    def method_splitter(request, *args, **kwargs):
        get_view = kwargs.pop('GET', None)
        post_view = kwargs.pop('POST', None)
        if request.method == 'GET' and get_view is not None:
            return get_view(request, *args, **kwargs)
        elif request.method == 'POST' and post_view is not None:
            return post_view(request, *args, **kwargs)
        raise Http404

      这样,便可以把向视图函数中传递的参数也都传递进去了。

    4+. 动态参数的传递

      Python中,支持动态参数的传递。写法如下:

    def foo(*args, **kwargs):
        print "Positional arguments are:"
        print args
        print "Keyword arguments are:"
        print kwargs

      当运行时,效果如下:

    >>> foo(1, 2, 3)
    Positional arguments are:
    (1, 2, 3)
    Keyword arguments are:
    {}
    >>> foo(1, 2, name='Adrian', framework='Django')
    Positional arguments are:
    (1, 2)
    Keyword arguments are:
    {'framework': 'Django', 'name': 'Adrian'}

     5. 视图中的预处理函数

      我们还可以让一些函数在进入之前,先进行预处理,其预处理的视图函数就像这样:

    def requires_login(view):
        def new_view(request, *args, **kwargs):
            if not request.user.is_authenticated():
                return HttpResponseRedirect('/accounts/login/')
            return view(request, *args, **kwargs)
        return new_view

       其对应的URL部分是这样的:

    from django.conf.urls import url
    from mysite.views import requires_login, my_view1, my_view2, my_view3
    
    urlpatterns = [
        url(r'^view1/$', requires_login(my_view1)),
        url(r'^view2/$', requires_login(my_view2)),
        url(r'^view3/$', requires_login(my_view3)),
    ]

       而原来,它原本要实现的视图逻辑则是这样的:

    def my_view1(request):
        if not request.user.is_authenticated():
            return HttpResponseRedirect('/accounts/login/')
        # ...
        return render_to_response('template1.html')
    
    def my_view2(request):
        if not request.user.is_authenticated():
            return HttpResponseRedirect('/accounts/login/')
        # ...
        return render_to_response('template2.html')
    
    def my_view3(request):
        if not request.user.is_authenticated():
            return HttpResponseRedirect('/accounts/login/')
        # ...
        return render_to_response('template3.html')

    6. URL中的include函数

      在admin的URL中,用到了include函数,而且URLconf的末尾不能有$。例如下面这段代码:

    from django.conf.urls import include, url
    
    urlpatterns = [
        (r'^weblog/', include('mysite.blog.urls')),
        (r'^photos/', include('mysite.photos.urls')),
        (r'^about/$', 'mysite.views.about'),
    ]

       如你所见,include函数包含了另一个urls.py,其内容就像这样:

    # mysite.blog.urls
    
    from django.conf.urls import url
    
    urlpatterns = [
        url(r'^(dddd)/$', 'mysite.blog.views.year_detail'),
        url(r'^(dddd)/(dd)/$', 'mysite.blog.views.month_detail'),
    ]

      那么,其对应的网址就像这样:

    URL地址 视图函数
    /weblog/2007/ 'mysite.blog.views.year_detail'
    /weblog/2007/09/ 'mysite.blog.views.month_detail'
    ... ...

      而且,你向视图函数中传的参数(无论是URL中接收的、还是字典中手动传的),都会实际传到每一个匹配的视图中。

      举个例子,下面两段代码的效果是完全相同的 ——

    代码1:

    # urls.py
    
    from django.conf.urls import *
    
    urlpatterns = [
        url(r'^blog/', include('inner'), {'blogid': 3}),
    ]
    
    # inner.py
    
    from django.conf.urls import *
    
    urlpatterns = [
        url(r'^archive/$', 'mysite.views.archive'),
        url(r'^about/$', 'mysite.views.about'),
        url(r'^rss/$', 'mysite.views.rss'),
    ]

    代码2:

    # urls.py
    
    from django.conf.urls import *
    
    urlpatterns = [
        url(r'^blog/', include('inner')),
    ]
    
    # inner.py
    
    from django.conf.urls import *
    
    urlpatterns = [
        url(r'^archive/$', 'mysite.views.archive', {'blogid': 3}),
        url(r'^about/$', 'mysite.views.about', {'blogid': 3}),
        url(r'^rss/$', 'mysite.views.rss', {'blogid': 3}),
    ]

      至此,“高级视图和URL配置”内容完结,下一篇是——“模板高级进阶”。

  • 相关阅读:
    冷门Javascript API——element.insertAdjacentHTML
    一些CKEditor定制问题
    HTML中的base标签
    深入Require.js
    狂神说SpringMVC笔记
    GeoServer之Dispatcher类(Controller控制器)
    java之ThreadLocal<>线程
    java获取当前路径&文件读写
    GeoServer服务扩展
    Spring之getBeanNamesForType
  • 原文地址:https://www.cnblogs.com/icedream61/p/4661314.html
Copyright © 2011-2022 走看看