django-原理-URL dispatcher
views层
处理用户request并且输出response,访问顺序如下
1.django决定了使用的URLconf,就是ROOT_URLCONF设置,如果HttpRequest本身有一个urlconf属性(middlewar设置),这时会替换ROOT_URLCONF 
2.django加载python模块,查找urlpatterns变量,这时django.conf.urls.url()的一个列表
3.django以url方式运行,从第一个匹配的url停下
4.匹配了正则表达式后,Django引入并且调用给定的view,view可能是独立的或者继承自(class-based view)
  view通过以下参数获得
  a.HttpRequest
  b.匹配的表达式没有返回name groups
  c.kwargs传递到django.conf.urls.url()
5.如果没有匹配的url,django调用
例子:简单的URLconf
from django.conf.urls import url
from . import views
urlpatterns = [
    url(r'^articles/2003/$', views.special_case_2003),
    url(r'^articles/([0-9]{4})/$', views.year_archive),
    url(r'^articles/([0-9]{4})/([0-9]{2})/$', views.month_archive),
    url(r'^articles/([0-9]{4})/([0-9]{2})/([0-9]+)/$', views.article_detail),
]
推荐加上r,不需要转义;不需要加上起始的/
/articles/2005/03/	请求打到第三个url上,调用函数views.month_archive(request, '2005', '03')
/articles/2005/3/	不会匹配任何url
/articles/2003/ 	匹配第一个url而不是第二个,因为是按顺序查找,并且调用函数views.special_case_2003(request)
/articles/2003		不会匹配url因为第一个结尾需要内容
/articles/2003/03/03/ 调用views.article_detail(request, '2003', '03', '03')
Named groups
可以使用命名的正则表达式组,获取url bit,并且把它们传递给view;
语法是(?P<name>pattern)
name是group的名字
pattern是需要匹配的模式
下面是named groups的例子
from django.conf.urls import url
from . import views
urlpatterns = [
    url(r'^articles/2003/$', views.special_case_2003),
    url(r'^articles/(?P<year>[0-9]{4})/$', views.year_archive),
    url(r'^articles/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/$', views.month_archive),
    url(r'^articles/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/(?P<day>[0-9]{2})/$', views.article_detail),
]
这样传递给view函数的量,会带上参数名而不是依赖位置的
/articles/2005/03/ 		调用views.month_archive(request, year='2005', month='03')
/articles/2003/03/03/ 	调用views.article_detail(request, year='2003', month='03', day='03')
这样URLconfs会更加明确;
但是有些开发者认为这样太啰嗦
URLconf搜索内容
只搜索请求的RUL,并不会处理GET和post参数,或者域名
比如,对于https://www.example.com/myapp/URLconf 会处理myapp/
对于https://www.example.com/myapp/?page=3也只处理myapp/
URLconf并不会区分请求的method,对于任何的url都会处理
捕获的参数都是string
url(r'^articles/(?P<year>[0-9]{4})/$', views.year_archive)
year传递给views.year_archive()之后是string,即使是int型的也是string
指定默认的参数
方便的方法是指定一个默认的参数给views,这里有一个URLconf 和view的例子
# URLconf
from django.conf.urls import url
from . import views
urlpatterns = [
    url(r'^blog/$', views.page),
    url(r'^blog/page(?P<num>[0-9]+)/$', views.page),
]
# View (in blog/views.py)
def page(request, num="1"):
    # Output the appropriate page of blog entries, according to num.
    ...
例子中两个请求都指向 views.page,但是第一个使用了默认值num=1
错误处理
找不到匹配或者出现异常,会调用异常处理view;
默认只支持4个参数,需要更多可以定制;
https://docs.djangoproject.com/en/1.10/topics/http/views/#customizing-error-views
值必须设置到root URLconf中,在其他地方设置没有效果;
handler400 – See django.conf.urls.handler400.
handler403 – See django.conf.urls.handler403.
handler404 – See django.conf.urls.handler404.
handler500 – See django.conf.urls.handler500.
包含其他URLconfs
包含其他URLconfs的就是root
from django.conf.urls import include, url
urlpatterns = [
    # ... snip ...
    url(r'^community/', include('django_website.aggregator.urls')),
    url(r'^contact/', include('django_website.contact.urls')),
    # ... snip ...
]
from django.conf.urls import include, url
from apps.main import views as main_views
from credit import views as credit_views
extra_patterns = [
    url(r'^reports/$', credit_views.report),
    url(r'^reports/(?P<id>[0-9]+)/$', credit_views.report),
    url(r'^charge/$', credit_views.charge),
]
urlpatterns = [
    url(r'^$', main_views.homepage),
    url(r'^help/', include('apps.help.urls')),
    url(r'^credit/', include(extra_patterns)),
]
例子中/credit/reports/会被credit_views.report()处理
这样一个url使用过多时,可以减少冗余
比如下面这rul
from django.conf.urls import url
from . import views
urlpatterns = [
    url(r'^(?P<page_slug>[\w-]+)-(?P<page_id>\w+)/history/$', views.history),
    url(r'^(?P<page_slug>[\w-]+)-(?P<page_id>\w+)/edit/$', views.edit),
    url(r'^(?P<page_slug>[\w-]+)-(?P<page_id>\w+)/discuss/$', views.discuss),
    url(r'^(?P<page_slug>[\w-]+)-(?P<page_id>\w+)/permissions/$', views.permissions),
]
可以这样简化
from django.conf.urls import include, url
from . import views
urlpatterns = [
    url(r'^(?P<page_slug>[\w-]+)-(?P<page_id>\w+)/', include([
        url(r'^history/$', views.history),
        url(r'^edit/$', views.edit),
        url(r'^discuss/$', views.discuss),
        url(r'^permissions/$', views.permissions),
    ])),
]
捕获参数
包含的URLconf能够捕获父url的参数,下面的写法合法
# In settings/urls/main.py
from django.conf.urls import include, url
urlpatterns = [
    url(r'^(?P<username>\w+)/blog/', include('foo.urls.blog')),
]
# In foo/urls/blog.py
from django.conf.urls import url
from . import views
urlpatterns = [
    url(r'^$', views.blog.index),
    url(r'^archive/$', views.blog.archive),
]
这样username变量会被传递到include的URLconf中
嵌套argument
from django.conf.urls import url
urlpatterns = [
    url(r'blog/(page-(\d+)/)?$', blog_articles),                  # bad
    url(r'comments/(?:page-(?P<page_number>\d+)/)?$', comments),  # good
]
传递额外的选项给view函数
django.conf.urls.url()函数可以传入第三个参数,第三个参数是字典;
from django.conf.urls import url
from . import views
urlpatterns = [
    url(r'^blog/(?P<year>[0-9]{4})/$', views.year_archive, {'foo': 'bar'}),
]
例子中 /blog/2005/url将会调用函数
views.year_archive(request, year='2005', foo='bar').
这个特性用在The syndication feed framework模块中,参考
https://docs.djangoproject.com/en/1.10/ref/contrib/syndication/
如果传入参数和请求参数具有相同的key value,会以传入参数为准;
向include传递额外参数
如果向include()传递参数,包含的URLconf每行都会传递额外参数;
# main.py
from django.conf.urls import include, url
urlpatterns = [
    url(r'^blog/', include('inner'), {'blogid': 3}),
]
# inner.py
from django.conf.urls import url
from mysite import views
urlpatterns = [
    url(r'^archive/$', views.archive),
    url(r'^about/$', views.about),
]
设置两次
# main.py
from django.conf.urls import include, url
from mysite import views
urlpatterns = [
    url(r'^blog/', include('inner')),
]
# inner.py
from django.conf.urls import url
urlpatterns = [
    url(r'^archive/$', views.archive, {'blogid': 3}),
    url(r'^about/$', views.about, {'blogid': 3}),
]
不管参数是否合法,这样做都会传入参数,因此使用这种方式要确保参数合法性;
解析ruls
获取url是一个django的通用需求
django提供url工具
urls使用的位置
- 模板中url tag
- python代码中reverse() 函数
- 高级别的代码中get_absolute_url()方法
from django.conf.urls import url
from . import views
urlpatterns = [
    #...
    url(r'^articles/([0-9]{4})/$', views.year_archive, name='news-year-archive'),
    #...
]
在模板中可以这么获得
<a href="{% url 'news-year-archive' 2012 %}">2012 Archive</a>
{# Or with the year in a template context variable: #}
<ul>
{% for yearvar in year_list %}
<li><a href="{% url 'news-year-archive' yearvar %}">{{ yearvar }} Archive</a></li>
{% endfor %}
</ul>
在python中这么获得
from django.urls import reverse
from django.http import HttpResponseRedirect
def redirect_to_year(request):
    # ...
    year = 2006
    # ...
    return HttpResponseRedirect(reverse('news-year-archive', args=(year,)))
在一些脚本中
使用namespace
两个polls应用的实例,一个author-polls,一个publisher-polls
urls.py
from django.conf.urls import include, url
urlpatterns = [
    url(r'^author-polls/', include('polls.urls', namespace='author-polls')),
    url(r'^publisher-polls/', include('polls.urls', namespace='publisher-polls')),
]
polls/urls.py
from django.conf.urls import url
from . import views
app_name = 'polls'
urlpatterns = [
    url(r'^$', views.IndexView.as_view(), name='index'),
    url(r'^(?P<pk>\d+)/$', views.DetailView.as_view(), name='detail'),
    ...
]
python代码中,这样能获得
reverse('polls:index', current_app=self.request.resolver_match.namespace)
url中这样获得
{% url 'polls:index' %}
如果正在渲染其他页面,polls:index会解析最后注册的polls
author-polls:index总是解析author-polls的index页
url namespace和included URLconfs
可以设置app_name属性,在同一级别上可以设置urlpatterns属性
polls/urls.py
from django.conf.urls import url
from . import views
app_name = 'polls'
urlpatterns = [
    url(r'^$', views.IndexView.as_view(), name='index'),
    url(r'^(?P<pk>\d+)/$', views.DetailView.as_view(), name='detail'),
    ...
]
urls.py
from django.conf.urls import include, url
urlpatterns = [
    url(r'^polls/', include('polls.urls')),
]
RULs定义的 polls.urls有一个命名空间polls
如果include()一些 url()
也可以映入
(<list of url() instances>, <application namespace>)
比如
from django.conf.urls import include, url
from . import views
polls_patterns = ([
    url(r'^$', views.IndexView.as_view(), name='index'),
    url(r'^(?P<pk>\d+)/$', views.DetailView.as_view(), name='detail'),
], 'polls')
urlpatterns = [
    url(r'^polls/', include(polls_patterns)),
]
 
                    
                     
                    
                 
                    
                
 
 
                
            
         
         浙公网安备 33010602011771号
浙公网安备 33010602011771号