Django-02.url、错误处理以及命名空间

1.Django 如何处理一个请求

  • Django 决定要使用的根URLconf 模块。通常,这个值就是ROOT_URLCONF 的设置,但是如果进来的HttpRequest对象具有一个urlconf 属性(通过中间件request processing 设置),则使用这个值来替换ROOT_URLCONF设置。
  • Django 加载该Python 模块并寻找可用的urlpatterns。它是django.conf.urls.url()
    实例的一个Python 列表。
  • Django 依次匹配每个URL 模式,在与请求的URL 匹配的第一个模式停下来。 一旦其中的一个正则表达式匹配上,Django将导入并调用给出的视图,它是一个简单的Python 函数(或者一个基于类的视图)。视图将获得如下参数: 一个HttpRequest 实例。
  • 如果匹配的正则表达式返回了没有命名的组,那么正则表达式匹配的内容将作为位置参数提供给视图。关键字参数由正则表达式匹配的命名组组成,但是可以被django.conf.urls.url()的可选参数kwargs覆盖。
  • 如果没有匹配到正则表达式,或者如果过程中抛出一个异常,Django 将调用一个适当的错误处理视图。

2.URL解释:

schema://host[:port#]/path/.../?query-string

  • schema:指定使用的协议(例如:http, https, ftp)
  • host:Http服务器的IP地址或者域名
  • port:端口号,默认是80端口
  • path:访问资源的路径
  • query-string:发送给http服务器的数据
  • anchor:锚点

3.URL中的正则

url(r'^test1/9999/$', views.test1.as_view()),                #普通用法
url(r'^test2/([0-9]{4})/$', views.test2.as_view()),        # 单个非命名参数
url(r'^test3/([0-9]{4})/([0-9]{2})/$', views.test3.as_view()),
url(r'^test4/([0-9]{4})/([0-9]{2})/([0-9]+)/$', views.test4.as_view()),

我们先开始建一个django工程 在这里我们给给工程命名为lesson1 放在Django_lesson文件夹下
具体建django工程的细节详情见Django-01、初识Django和搭建Django helloworld

然后新建一个app 名为urltest

在lesson1.url.py 中导入view

from urltest import views

4.非命名参数

在lesson.urls.py中添加以下路由

    url(r'^admin/', admin.site.urls),
    url(r'^test1/9999/$', views.Test1.as_view()),
    url(r'^test2/([0-9]{4})/$', views.Test2.as_view()),
    url(r'^test3/([0-9]{4})/([0-9]{2})/$', views.Test3.as_view()), views.Test4.as_view()),

在urltest.view.py中添加以下视图类

class Test1(View):
    def get(self, request):
        msg = "Test1 sucessful"
        return HttpResponse(msg)


class Test2(View):
    def get(self, request, year):
        msg = "Test2 sucessful  %s 年" % year
        return HttpResponse(msg)


class Test3(View):
    def get(self, request, year, month):
        msg = "Test3 sucessful %s 年 %s 月" % (year, month)
        return HttpResponse(msg)

注:
若要从URL 中捕获一个值,只需要在它周围放置一对圆括号。
不需要添加一个前导的反斜杠,因为每个URL 都有。例如,应该是^articles 而不是 ^/articles。
每个正则表达式前面的'r' 是可选的但是建议加上。它告诉Python 这个字符串是“原始的” —— 字符串中任何字符都不应该转义。参见Dive Into Python 中的解释。

^代表开始匹配,如果只有^符号,则只需要部分匹配成功即可
$代表结束匹配,添加$符号, 一般就代表完整匹配

我们的URL匹配规则一定需要保持唯一

5.命名参数

上面的示例使用简单的、没有命名的正则表达式组(通过圆括号)来捕获URL 中的值并以位置 参数传递给视图。在更高级的用法中,可以使用命名的正则表达式组来捕获URL 中的值并以关键字 参数传递给视图。
在Python 正则表达式中,命名正则表达式组的语法是(?Ppattern),其中name 是组的名称,pattern 是要匹配的模式。

    url(r'^test4/(?P[0-9]{4})/$', views.Test4.as_view()),
    url(r'^test5/(?P[0-9]{4})/(?P[0-9]{2})/$', views.Test5.as_view()),

在urltest.view.py中添加以下视图类

class Test4(View):
    def get(self, request, year):
        msg = "Test3 sucessful %s 年" % year
        return HttpResponse(msg)


class Test5(View):
    def get(self, request, month, year):  # 这里我们交换了year和month的顺序
        msg = "Test3 sucessful %s 年 %s 月" % (year, month)
        return HttpResponse(msg)






如果有命名参数,则使用这些命名参数,忽略非命名参数。
否则,它将以位置参数传递所有的非命名参数。
请求的URL被看做是一个普通的Python 字符串, URLconf在其上查找并匹配。进行匹配时将不包括GET或POST请求方式的参数以及域名。换句话讲,所有的请求方法 —— 即,对同一个URL的无论是POST请求、GET请求、或HEAD请求方法等等 —— 都将路由到相同的函数。
每个捕获的参数都作为一个普通的Python 字符串传递给视图,无论正则表达式使用的是什么匹配方式。

包含其它的URLconfs

在任何时候,你的urlpatterns 都可以包含其它URLconf 模块。这实际上将一部分URL 放置于其它URL 下面。
在lesson1.urls.py中加入以下代码

    from django.conf.urls import include  # 导入 include
    url(r'^test7/', include('urltest.urls')),  # 加入路由

在urltest文件夹下新建urls.py加入以下代码

from django.conf.urls import url
from urltest import views
urlpatterns = [
    url(r'^test7/$', views.Test7.as_view()),
]

在urltest.views.py加入以下视图类

class Test7(View):
    def get(self, request):  # 这里我们交换了year和month的顺序
        msg = "Test7 sucessful"
        return HttpResponse(msg)

传递额外的选项给视图函数

URLconfs 具有一个钩子,让你传递一个Python 字典作为额外的参数传递给视图函数。
django.conf.urls.url() 函数可以接收一个可选的第三个参数,它是一个字典,表示想要传递给视图函数的额外关键字参数。

#lesson1.urls.py中加入这个路由
url(r'^test8/', include('urltest.urls'), {'name': 'lethe', 'date': '2018'}),

#urltest.urls.py中加入这个路由
url(r'^test8/$', views.Test8.as_view()),

#views.py中加入这个视图类
class Test8(View):
    def get(self, request, name, date):  # 这里我们交换了year和month的顺序
        msg = "Test8 sucessful by %s in %s" % (name, date)
        return HttpResponse(msg)

6.错误处理

当Django 找不到一个匹配请求的URL 的正则表达式时,或者当抛出一个异常时,Django 将调用一个错误处理视图。

Http状态码
每一个请求,都会返回一个状态
200 : 请求正常
404:找不到页面
403:是指服务器拒绝
400:request异常
500:服务器异常

在URLconf中指定参数,这些参数分别是

handler404
一个callable或一个字符串,表示如果没有URL模式匹配,应该调用的视图的完整Python导入路径。
默认情况下是'django.views.defaults.page_not_found'。

handler500
一个callable或一个字符串,表示如果没有URL模式匹配,应该调用的视图的完整Python导入路径。
默认情况下,这是'django.views.defaults.page_not_found'。

handler403
一个callable或一个字符串,表示如果用户没有访问资源所需的权限,应调用的视图的完整Python导入路径。
默认情况下,这是'django.views.defaults.permission_denied'。

handler400
如果HTTP客户端已发送导致错误条件的请求和状态代码为400的响应,则应调用的可调用或表示完整的Python视图导入路径的字符串。
默认情况下,这是'django.views.defaults.bad_request'。

在settings.py中将DEBUG值改为True
当找不到页面的时候 页面显示如下图

然后我们再在settings.py中将DEBUG值改为False (我们一般在开发的时候设置DEBUG值为True 在产品上线的时候将DEBUG值改为False)
当找不到页面的时候 页面显示如下图

我们将代码作如下更改

#在views.py中加入以下代码
def Error404(request):
    return HttpResponse("哎呦 404 尴尬了!")

#DEBUG值保持为False
#在lesson1.py中加入
handler404 = 'urltest.views.Error404'   

7.URL 的反向解析

在使用Django 项目时,一个常见的需求是获得URL 的最终形式,以用于嵌入到生成的内容中(视图中和显示给用户的URL等)或者用于处理服务器端的导航(重定向等)。
人们强烈希望不要硬编码这些URL(费力、不可扩展且容易产生错误)或者设计一种与URLconf 毫不相关的专门的URL 生成机制,因为这样容易导致一定程度上产生过期的URL。
换句话讲,需要的是一个DRY 机制。除了其它优点,它还允许设计的URL 可以自动更新而不用遍历项目的源代码来搜索并替换过期的URL。
要获取一个URL,最初拥有的信息是负责处理它的视图的标识(例如名字),与查找正确的URL 的其它必要的信息如视图参数的类型(位置参数、关键字参数)和值。
Django 提供了一个解决方案使得URL 映射是URL 设计唯一的储存库。你用你的URLconf填充它,然后可以双向使用它:
根据用户/浏览器发起的URL 请求,它调用正确的Django 视图,并从URL 中提取它的参数需要的值。
根据Django 视图的标识和将要传递给它的参数的值,获取与之关联的URL。
第一种方式是我们在前面的章节中一直讨论的用法。第二种方式叫做反向解析URL、反向URL匹配、反向URL查询或者简单的URL反查。
在需要URL 的地方,对于不同层级,Django 提供不同的工具用于URL 反查:
在模板中:使用url 模板标签。
在Python 代码中:使用django.core.urlresolvers.reverse() 函数。
在更高层的与处理Django 模型实例相关的代码中:使用get_absolute_url() 方法。

    #在urls.views.py中加入以下代码
    url(r'^articles/$', views.Articles.as_view()),
    #在views.py中加入以下代码
    class Articles(View):
    def get(self, request):
        return redirect('/test1/9999/')

7.URL 命名空间

URL 命名空间允许你反查到唯一的命名URL 模式,即使不同的应用使用相同的URL 名称。第三方应用始终使用带命名空间的URL 是一个很好的实践(我们在教程中也是这么做的)。类似地,它还允许你在一个应用有多个实例部署的情况下反查URL。换句话讲,因为一个应用的多个实例共享相同的命名URL,命名空间提供了一种区分这些命名URL 的方法。

一个URL命名空间有两个部分,它们都是字符串:
应用命名空间
它表示正在部署的应用的名称。一个应用的每个实例具有相同的应用命名空间。例如,可以预见Django 的管理站点的应用命名空间是'admin'。
实例命名空间
它表示应用的一个特定的实例。实例的命名空间在你的全部项目中应该是唯一的。但是,一个实例的命名空间可以和应用的命名空间相同。它用于表示一个应用的默认实例。
URL 的命名空间使用':' 操作符指定。例如,管理站点应用的主页使用'admin:index'。它表示'admin' 的一个命名空间和'index' 的一个命名URL。
命名空间也可以嵌套。命名URL'sports:polls:index' 将在命名空间'polls'中查找'index',而poll 定义在顶层的命名空间'sports' 中。

    #在lesson1.urls.py中加入以下路由
    url(r'^url1test/', include('urltest.urls_1', namespace='url1test')),
    url(r'^url2test/', include('urltest.urls', namespace='url2test')),
    url(r'^url1_login/$', views.ToUrl1Login.as_view()),
    url(r'^url2_login/$', views.ToUrl2Login.as_view()),
    
    #在urltest文件夹下新建url_1.py并加入以下代码
    from django.conf.urls import url
    from urltest import views
    urlpatterns = [
    url(r'^login/$', views.Url1Login.as_view(), name='login'),
]

    #在urltest.url.py中加入以下路由
    url(r'^login/$', views.Url2Login.as_view(), name='login'),
    
    # 在views.py中加入以下视图类
    class Url1Login(View):
    def get(self, request):
        return HttpResponse("我是url1test.login")


class Url2Login(View):
    def get(self, request):
        return HttpResponse("我是url2test.login")


class ToUrl1Login(View):
    def get(self, request):
        return redirect(reverse('url1test:login'))


class ToUrl2Login(View):
    def get(self, request):
        return redirect(reverse('url2test:login'))

当输入/url1_login/时 跳到ToUrl1Login然后跳到url1test:login(即namespace='url1test',name='login'的路由 即/url1test/login/ 打印我是url1test.login)


8.附录 本文章代码:

view.py

    # -*- coding: utf-8 -*-
from __future__ import unicode_literals

from django.shortcuts import render
from django.views import View
from django.http import HttpResponse
from django.shortcuts import reverse, redirect
# Create your views here.


class Test1(View):
    def get(self, request):
        msg = "Test1 sucessful"
        return HttpResponse(msg)


class Test2(View):
    def get(self, request, year):
        msg = "Test2 sucessful  %s 年" % year
        return HttpResponse(msg)


class Test3(View):
    def get(self, request, year, month):
        msg = "Test3 sucessful %s 年 %s 月" % (year, month)
        return HttpResponse(msg)


class Test4(View):
    def get(self, request, year):
        msg = "Test4 sucessful %s 年" % year
        return HttpResponse(msg)


class Test5(View):
    def get(self, request, month, year):  # 这里我们交换了year和month的顺序
        msg = "Test5 sucessful %s 年 %s 月" % (year, month)
        return HttpResponse(msg)


class Test6(View):
    def get(self, request, num='1'):  # 这里我们交换了year和month的顺序
        msg = "Test6 sucessful num=%s" % num
        return HttpResponse(msg)


class Test7(View):
    def get(self, request):  # 这里我们交换了year和month的顺序
        msg = "Test7 sucessful"
        return HttpResponse(msg)


class Test8(View):
    def get(self, request, name, date):  # 这里我们交换了year和month的顺序
        msg = "Test8 sucessful by %s in %s" % (name, date)
        return HttpResponse(msg)


class Articles(View):
    def get(self, request):
        return redirect('/test1/9999/')

class Reverse_test(View):
    def get(self, request):
        return redirect(reverse('reverse_test', args=('2021',)))


class Url1Login(View):
    def get(self, request):
        return HttpResponse("我是url1test.login")


class Url2Login(View):
    def get(self, request):
        return HttpResponse("我是url2test.login")


class ToUrl1Login(View):
    def get(self, request):
        return redirect(reverse('url1test:login'))


class ToUrl2Login(View):
    def get(self, request):
        return redirect(reverse('url2test:login'))

def Error404(request):
    return HttpResponse("哎呦 404 尴尬了!")

lesson1.urls.py

from django.conf.urls import url, include
from django.contrib import admin
from urltest import views

urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^test1/9999/$', views.Test1.as_view()),
    url(r'^test2/([0-9]{4})/$', views.Test2.as_view(), name='reverse_test'),
    url(r'^test3/([0-9]{4})/([0-9]{2})/$', views.Test3.as_view()),
    url(r'^test4/(?P[0-9]{4})/$', views.Test4.as_view()),
    url(r'^test5/(?P[0-9]{4})/(?P[0-9]{2})/$', views.Test5.as_view()),
    url(r'^test6/(?P[0-9]+)/$', views.Test6.as_view()),
    url(r'^test7/', include('urltest.urls')),
    url(r'^test8/', include('urltest.urls'), {'name': 'lethe', 'date': '2018'}),
    url(r'^articles/$', views.Articles.as_view()),
    url(r'^reverse/$', views.Reverse_test.as_view()),

    url(r'^url1test/', include('urltest.urls_1', namespace='url1test')),
    url(r'^url2test/', include('urltest.urls', namespace='url2test')),
    url(r'^url1_login/$', views.ToUrl1Login.as_view()),
    url(r'^url2_login/$', views.ToUrl2Login.as_view()),

]

handler404 = 'urltest.views.Error404'

urltest.urls.py

from django.conf.urls import url
from urltest import views
urlpatterns = [
    url(r'^test7/$', views.Test7.as_view()),
    url(r'^test8/$', views.Test8.as_view()),
    url(r'^login/$', views.Url2Login.as_view(), name='login'),
]

urls_1.py

from django.conf.urls import url
from urltest import views
urlpatterns = [
    url(r'^login/$', views.Url1Login.as_view(), name='login'),
]

目录结构

注: 本文章是本人的CSDN博客中对应的文章转过来的

你可能感兴趣的:(ubuntu,django,python)