Django学习纪录 16.URL配置与视图进阶技巧

之前有在用Django写一些小网站,现在暑假想说再来複习一下之前买的这本书
http://img2.58codes.com/2024/20118889bj9fH1vhuR.jpg
于是我就把它写成一系列的文章,也方便查语法
而且因为这本书大概是2014年出的,如今Django也已经出到2.多版
有些内容也变得不再支援或适用,而且语法或许也改变了
所以我会以最新版的Python和Django来修正这本书的内容跟程式码

目录:django系列文章-Django学习纪录

16. URL配置与视图进阶技巧

16.1 主题1-汇入模组v.s.汇入函式

来看一下我们的urls.py

from django.contrib import adminfrom django.urls import path, re_pathfrom restaurants.views import menu, welcome, list_restaurants, comment, register, indexfrom django.contrib.auth.views import LoginView, LogoutViewurlpatterns = [    path('admin/', admin.site.urls),    re_path(r'menu/(\d{1,5})', menu),    path('welcome/', welcome),    path('restaurants_list/', list_restaurants),    re_path(r'comment/(\d{1,5})', comment),    path('index/', index),    path('accounts/login/', LoginView.as_view(template_name='login.html'), name='login'),    path('accounts/logout/', LogoutView.as_view(), name='logout'),    path('accounts/register/', register),]

这种写法如果当专案越来越複杂时,撰写的URL对应越来越多
这时就会产生出几个问题:
1.过多的视图函式要汇入导致汇入句太长
2.每一个使用到的视图函式都必须确定有被汇入
3.不同应用中的视图函式名称可能发生冲突

解决方式

汇入整个模组,而不是汇入个别的函式

from django.contrib import adminfrom django.urls import path, re_pathimport django.contrib.auth.viewsimport restaurants.viewsurlpatterns = [    path('admin/', admin.site.urls),    re_path(r'menu/(\d{1,5})', restaurants.views.menu),    path('welcome/', restaurants.views.welcome),    path('restaurants_list/', restaurants.views.list_restaurants),    re_path(r'comment/(\d{1,5})', restaurants.views.comment),    path('index/', restaurants.views.index),    path('accounts/login/', django.contrib.auth.views.LoginView.as_view(template_name='login.html'), name='login'),    path('accounts/logout/', django.contrib.auth.views.LogoutView.as_view(), name='logout'),    path('accounts/register/', restaurants.views.register),]

如此一来汇入句变得清爽,也比较不会有忘记汇入的问题
而且名称冲突的问题透过完整汇入路径而被解决

16.2 主题2-使用字串进行配置

16.2.1 用字串取代函式

新版的Django已不再支援使用字串进行配置

16.3 主题3-除错模式的URL配置

在开发阶段我们经常需要做一些测试
这时就会多出一些页面与URL pattern
不过我们不希望它们在正式上线时出现
那么可以这样做:

...from django.conf import settingsimport restaurants.views...if settings.DEBUG:    urlpatterns += [        path('test/', restaurants.views.test),    ]

这样就可以使得/test/只有在除错模式时才有效

16.4 主题4-URL配置与视图函式的参数

16.4.1 从URL中取出参数

使用位置取出

这就是之前讲过的部分
要注意的是当超过一个以上的参数要被传递时
Django只会依序地将值赋予
因此我们要介绍一个更弹性的作法

使用关键字取出

就像python的函式允许使用关键字参数
URL传递参数时也允许使用关键字参数

urlpatterns = [    ...    re_path(r'test/(?P<p1>\d{1,5})/(?P<p2>\d{1,5})', restaurants.views.test),]
def test(request, p1, p2):    ...

透过(?P<关键字>要撷取的参数)可以从URL中将要撷取的参数以关键字的方式取出
例如/test/1/2会将'1'给p1,'2'给p2
这完全取决于名称而非位置
我们也可以改写一下comment

re_path(r'comment/(?P<id>\d{1,5})', restaurants.views.comment)

使用这个方法就不需要考虑参数的顺序了,有些时候会方便许多
而以上这两个方法是允许混用的,只是容易造成错误,并不推荐

16.4.2 传递额外的参数

如果今天我们想要让/firstmenu/对应到/menu/1/这个页面
但是/firstmenu/却不能提供参数给视图函式
这时可以这样做

def menu(request, id=1):    ...
urlpatterns = [    ...    re_path(r'menu/(\d{1,5})', restaurants.views.menu),    path('firstmenu/', restaurants.views.menu),    ...]

但是如果又多出几个,譬如/secondmenu/的话那就没办法了
使用另外一种方法

urlpatterns = [    ...    re_path(r'menu/(\d{1,5})', restaurants.views.menu),    path('firstmenu/', restaurants.views.menu, {'id':'1'}),    path('secondmenu/', restaurants.views.menu, {'id':'2'}),    ...]

当不同的URL要使用同一个视图函式时,这会是一个很好的办法
而且如果要同时从URL中抽取参数,又提供额外的字典参数,也是可以的
不过当两者混用产生冲突时,会以字典参数为主,这是比较需要注意的

通用视图

假如现在有两个视图函式,长的差不多,程式码也很多重複
那其实可以写成一个通用视图
mysite/templates/users_list.html

{% extends 'base.html' %}{% block title %} 使用者列表 {% endblock %}{% block content %}    <table>        <tr>            <th>使用者帐号</th>            <th>使用者姓名</th>        </tr>        {% for u in users %}        <tr>            <td>{{u.username}}</td>            <td>{{u.last_name}}{{u.first_name}}</td>        </tr>        {% endfor %}    <table>{% endblock %}

比如这两个视图函式

from django.contrib import authdef list_users(request):    users = auth.models.User.objects.all()    return render(request, 'users_list.html', locals())def list_restaurants(request):    restaurants = Restaurant.objects.all()    return render(request, 'restaurants_list.html', locals())
path('restaurants_list/', restaurants.views.list_restaurants),path('users_list/', restaurants.views.list_users),

这两个视图有着大量重複的逻辑,不如将共有的部分写成一个通用视图

def list(request, model):    objs = model.objects.all()    return render(request, '{0}s_list.html'.format(model.__name__.lower()), locals())
path('restaurants_list/', restaurants.views.list, {'model': restaurants.models.Restaurant}),path('users_list/', restaurants.views.list, {'model': auth.models.User}),

记得要将模板中的usersrestaurants变量改为objs
资料库模型的属性__name__可以取出模型的名称
再透过lower函式转为小写
这样就解决了~

16.5 主题5-分层的URL配置

就如同模板可以隶属于不同的应用里一样
Django也允许我们将URL的配置分散到各个应用
再透过全站等级的根URL配置分层下去负责
settings.py中的

ROOT_URLCONF = 'mysite.urls'
...from django.contrib import admin...urlpatterns = [    path('admin/', admin.site.urls),    ...]

当有人向网站发出URL请求时,Django会由ROOT_URLCONF所指定的根URL配置来找寻对应的视图,接着如果发现include关键字,则会进入下一层,到指定的配置档中继续试着配对URL
举个例子
mysite/restaurants/urls.py

from django.urls import path, re_pathimport restaurants.viewsurlpatterns = [    re_path(r'menu/(\d{1,5})', restaurants.views.menu, name='menu'),    re_path(r'comment/(?P<id>\d{1,5})', restaurants.views.comment),    path('restaurants_list/', restaurants.views.list, {'model': restaurants.models.Restaurant}),]

mysite/mysite/urls.py

from django.urls import path, re_path, includeurlpatterns = [    ...    path('restaurants', include(restaurants.urls)),]

当网站接收到URL请求: /resraurants/menu/1/,它会先配对/resraurants/成功,因为还没到结尾所以配对未结束,所以任何以/resraurants/开头的URL都会算做配对成功,无论是/resraurants/或是/resraurants/menu/1/或是/resraurants/comment/2/
接着会寻找include中指定的配置档再去配对,同时截掉目前已经配对成功的部份,因此在次层需要配对的URL从/resraurants/menu/1/变为/menu/1/,最后配对re_path(r'menu/(\d{1,5})', restaurants.views.menu, name='menu')成功
在搬移配置的时候要注意:
1.有关的页面请求都要加上新的URL前缀(如上例为/resraurants/)
2.必须自己修正在其他页面中重导到那些页面所使用的URL(因为原本可能没有前缀)

16.5.1 视图函式参数的传递

假设

...import app1...urlpatterns = [    re_path(r'foo/(?P<p1>\w+)/', include(app1.urls), {'p2': 'hello'}),]

app1/urls.py

...import app1.views...urlpatterns = [    path('bar1/', app1.views.bar1),    path('bar2/', app1.views.bar2),]

p1和p2都会往下传递给所有在app1.urls的视图函式,即bar1bar2
要注意的是,如果bar1bar2并不需要这个参数,则会产生错误

上一篇:Django学习纪录 15.模板进阶技巧

下一篇:Django学习纪录 17.视图类别


关于作者: 网站小编

码农网专注IT技术教程资源分享平台,学习资源下载网站,58码农网包含计算机技术、网站程序源码下载、编程技术论坛、互联网资源下载等产品服务,提供原创、优质、完整内容的专业码农交流分享平台。

热门文章