1、URLconf
— URL配置(URLconf)就像Django所支撑网站的目录。它的本质是URL与要为该URL调用的视图函数之间的映射表。以这种方式告诉Django,对于不同请求的URL需要去调取哪段代码。
# URLconf配置
from django.conf.urls import url
urlpatterns = {
url(正则表达式, views试图函数, 参数, 别名)
}
"""
正则表达式:一个正则表达式字符串
views视图函数:一个可调用对象,通常为一个视图函数或一个指定视图函数路径的字符串
参数:可选的要传递给视图函数的默认参数(字典形式)
别名:一个可选的name参数
"""
— Django2.0版本中的路由系统已经替换成下面的写法 官方文档:
from django.urls import path
urlpatterns = [
path('articles/2003/', views.special_case_2003),
path('articles/<int:year>/', views.year_archive),
path('articles/<int:year>/<int:month>/', views.month_archive),
path('articles/<int:year>/<int:month>/<slug:slug>/', views.article_detail),
]
2、URLconf的正则字符串参数
2.1 简单配置
from django.conf.urls import url
from api 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),
]
— 规则:
1. 一旦匹配成功则不再继续
2. 若要从URL中捕获一个值,只需要在它周围放置一对圆括号
3. 不需要添加一个前导的反斜杠,因为每个URL中Django都会主动添加。如: 应该是^articles,而不是^/articles
4. 每个正则表达式前面的'r',是可选的但是建议加上,防止字符转义
— 实例分析:
⒈/articles/2005/3/ 不匹配任何URL模式,因为列表中的第三个模式要求月份应该是两个数字
⒉/articles/2003/ 将匹配列表中的第一个模式不是第二个,因为模式按顺序匹配,第一个会首先测试是否匹配
⒊/articles/2005/03/ 请求将匹配列表中的第三个模式。Django将调用view.py中的函数:views.month_archive(request, '2005', '03')
— APPEND_SLASH:
— Django seetings.py配置文件中默认没有这个参数,但Django默认这个参数为 APPEND_SLASH = True。作用就是自动在网址结尾加'/'。
2.2 name group
— 除了可以用未经命名的正则表达式组来捕获URL中的值,并以位置参数传递给视图 。还可以用命名的正则表达式组来捕获URL中的值,后以关键字参数传递给视图。区别就是位置参数变成了关键字参数,其余不变。注意:参数永远只以字符串形式传递给对应的函数
— 在Python正则表达式中,命名正则表达式组的语法为【(?P<name>pattern)】,其中name是组的名称,pattern是要匹配的模式
- 重写未命名的正则表达式组
from django.conf.urls import url
from api 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),
]
/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')
2.3 URLconf如何处理URL
— URLconf将请求的URL当作一个普通的Python字符串,不区分请求方式的参数及域名
— eg:
在http://www.admin.com/restapi/请求中,URLconf只查找restapi/
在http://www.admin.com/restapi/?number=12请求中,URLconf仍只查找restapi/
— URLconf不检查请求的方法。也就是说,在同一个URL中无论是POST、GET、HEAD亦或DELETE请求方法,都将被路由到相同的函数
2.4 指定视图参数的默认值
# URLconf
from django.conf.urls import url
from api 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"):
....
— 上面两条URL都指定同一个page视图函数,但第一个并不会从URL中捕获到任何参数,如果第一个进行模式匹配,page()将使用【num="1"】作为默认值;如果是第二个进行模式匹配,page()将使用正则表达式捕获num值。
3、传递额外的选项给视图函数
— URLconf有一个钩子,可以传递一个Python字典作为额外的参数传递给视图函数
— django.conf.urls.url()函数可以接收一个可选的字典类型的第三个参数,表示想要传递给视图函数额外的关键字参数
from django.conf.urls import url
from api import views
urlpatterns = [
url(r'^api/(?<year>[0-9]{4})/$', views.year_archive, {'cookie': 'lee'})
]
— 在这个例子中,对于/api/2018/请求,Django将调用views.year_archive(request, year='2018', cookie='lee')。这个技术在Syndication 框架中使用,来传递元数据和选项给视图。
4、URL反向解析
— Django中提供了一个关于URL的映射的解决方案,你可以做两个方向的使用:
① 有客户端的浏览器发起一个url请求,Django根据URL解析,把url中的参数捕获,调用相应的试图,获取相应的数据,然后返回给客户端显示。
② 通过一个视图的名字,再加上一些参数和值,逆向获取相应的URL。
:| 第一个就是平常的请求有URLconf来解析的过程,第二个叫做,url的逆向解析,url逆向匹配,url的逆向查阅等
— Django提供了不同的层级的url逆向处理工具:
⑴ 在模板templates中,使用url标记,如:{% url %}
⑵ 在Python代码中,使用django.core.urlresolvers.reverse()方法
⑶ 在更高一层级的处理url中,用get_absolute_url()方法
from django.conf.urls import patterns, url
urlpatterns = [
url(r'^articles/(\d{4})/$', 'news.views.year_archive'),
]
# 根据设计,这个url的目的是将是nnnn年的文章存档(archive),即/articles/nnnn/
// 在模板中,可以这样来使用:
<a href="{% url 'news.views.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.views.year_archive' yearvar %}">{{ yearvar }} Archive</a></li>
{% endfor %}
</ul>
{# 别名设置
{% url 'some-url-name' arg arg2 as the_url %}
<a href="{{ the_url }}">链接到:{{ the_url }}</a>
#}
— 根据视图 'news.views.year_artichive'可以定位到指定的URLconf中,然后后面的2012来填充articles/\d{4},最终的结果为<a href="articles/2012/">2012 Archive</a>,这里就是根据试图和所提供的值来逆向查询url
from django.core.urlresolvers import reverse
from django.http import HttpResponseRedirect
def redirect_to_year(request):
year = 2006
return HttpResponseRedirect(reverse('news.views.year_archive', args=(year,)))
— 必须引入django.core.urlresolvers.reverse()方法,然后原理就是,根据提供的试图和参数的值来逆向查找URLconf,匹配相应的url然后把值拿回来,最后,reverse()返回的值为:articles/2006/,这样就逆向的查出了需要的url
5、Namespace(命名空间)
——命名空间是表示标识符的可见范围。一个标识符可以在多个命名空间中定义,并且在不同的命名空间中的含义互不相干,不会引起冲突。
——我们在开发项目时,会经常使用name属性反解出URL,当不小心在不同的app的urls中定义相同的name时,可能会导致URL反解错误,为了避免这种事情发生,引入了命名空间。
——由于name没有作用域,Django在反向解析URL时,搜索顺序是从全局开始,依次往里查找,当找到第一个name指定的URL后,马上返回停止查找
# 项目的urls.py
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^test1/', include("test1.urls",namespace="test1")),
url(r'^test2/', include("test2.urls",namespace="test2")),
]
# test1中的urls.py
app_name = 'test1'
urlpatterns = [
url(r'^(?P<pk>\d+)/$', views.detail, name='idnex')
]
# test2中的urls.py
app_name = 'test2'
urlpatterns = [
url(r'^(?P<pk>\d+)/$', views.detail, name='index')
]
# test1中的views.py
from django.core.urlresolvers import reverse
def index(request, pk):
return HttpResponse(reverse("test1: index", kwargs={'pk': 5}))
# test2中的views.py
from django.core.urlresolvers import reverse
def index(request, pk):
return HttpResponse(reverse("test2: index", kwargs={'pk': 5}))
——现在,我的两个app中url名称重复了,但是反转URL的时候就可以通过命名空间的名称得到我当前的URL。
语法:'命名空间名称: URL名称'
模板中使用:{% url 'test1: index' pk=5 %}
views中的函数中使用:v = reverse('test1: index', kwargs={'pk': 5})
——这样即使app中URL的命名相同,也可以反转得到正确的URL了。
6、CBV(示例)
url(r'^rate/$', rate.RateView.as_view(),
# --------------------------------------------------------
class RateView(ViewSetMixin, APIView):
def list(self, request, *args, **kwargs):
"""
:param request:
:param args:
:param kwargs:
:return:
"""
ret = {'code': 1000, 'data': None}
try:
queryset = models.Rate.objects.all()
ser = RateSerializer(instance=queryset, many=True)
ret['data'] = ser.data
except Exception as e:
ret['code'] = 1001
ret['error'] = '获取费率失败'
return Response(ret)
def retrieve(self, request, *args, **kwargs):
"""
:param request:
:param args:
:param kwargs:
:return:
"""
ret = {'code': 1000, 'data': None}
try:
pk = kwargs.get('pk')
obj = models.RateDetail.objects.filter(rate_id=pk).first()
ser = RateDetailSerializer(instance=obj, many=False)
ret['data'] = ser.data
except Exception as e:
ret['code'] = 1001
ret['error'] = '获取费率失败'
return Response(ret)
网友评论