一个优美的URL不仅层次分明、逻辑清晰,而且便于搜索引擎收录。一个糟糕的URL不仅可读性差,而且易造成程序冲突。我们今天就来看几个例子,教你如何在利用Django开发Web APP过程中设计充满陷阱的优美URL。是的,标题你没看错。此文涉及Django程序员的饭碗问题,请认真阅读,不吝点赞。

一个简单的例子

假设我们有一个名为blog的app,包含了Category和Article两个模型,其中Category与Article是一对多的关系,那么下面三个URL你一定不会陌生,一个用来展示文章列表,一个用来展示文章详情,一个按类别的slug名展示文章列表。完整模型见Django实战专题: 开发专业博客(1)之内容管理后台开发。

from django.urls import path, re_path
from . import views# namespace
app_name = 'blog'
urlpatterns = [# 展示文章列表
path('', views.article_list, name='article_list'),
# 按类别slug名展示文章列表
re_path(r'^category/(?P<slug>[-\w]+)/$',
views.CategoryDetailView.as_view(), name='category_detail'),
# 展示文章详情
re_path(r'^article/(?P<pk>\d+)/$',
views.ArticleDetailView.as_view(), name='article_detail'),]

那么问题来了,展示文章详情的时候,展示的URL只是article/12/的形式,这个显然对搜索引擎不好。一个更好的方式根据article的title生成slug,将slug也通过URL展示出来,如article/12/my-first-article-for-google/。改进过的URL设计如下。

from django.urls import path, re_path
from . import views# namespace
app_name = 'blog'
urlpatterns = [# 展示文章列表
path('', views.article_list, name='article_list'),
# 按类别slug名展示文章列表
re_path(r'^category/(?P<slug>[-\w]+)/$',
views.CategoryDetailView.as_view(), name='category_detail'),
# 展示文章详情
re_path(r'^article/(?P<pk>\d+)/(?P<slug1>[-\w]+)/$',
views.ArticleDetailView.as_view(), name='article_detail'),
]

那么问题又来了,为啥URL中参数名是slug1,而不是slug呢?这是个误拼吗?当然不是。Django自带的通用视图DetailView即可接收整数值id,也可接受slug作为pk查询数据库并调用用相关视图(pk=primary key主键)。我们这里这样做完全是为了告诉DetailView仅根据id整数值调用视图,而忽略后面的slug,毕竟id不太容易重复,而不同文章标题的slug有可能是相同的。这个slug1纯粹是为了让URL看起来对搜索引擎更友好。更多关于通用视图的内容见Django核心基础(3): View视图详解。一旦你使用通用视图,你就会爱上她。

更进一步撒点盐

在实际blog开发过程中,我们所需要的URL数量远比上面要多,因为作者还需要查看自己已经发表的文章,查看草稿箱,创建新文章,对文章进行编辑和删除。每个操作都需要有对应的URL及与URL对应的视图函数或类。同时我们在设计每个URL的过程中还需仔细思考对应每个URL对应的权限。比如一个用户是否需要登录、是否需要有创建、修改或删除的权限才能访问该URL。

下图中的URL设计是很常见的设计模式,基本可以满足我们的上述需求。小编我还特别注明了在设计某个URL过程中关于用户权限的思考。但下面的URL中有个小问题,你能看得出来吗?

from django.urls import path, re_path
from . import views# namespace
app_name = 'blog'
urlpatterns = [# 展示文章列表 - 无需登录
path('', views.article_list, name='article_list'),
# 按类别名展示文章列表 - 无需登录
re_path(r'^category/(?P<slug>[-\w]+)/$',
views.CategoryDetailView.as_view(), name='category_detail'),
# 展示文章详情 - 无需登录
re_path(r'^article/(?P<pk>\d+)/(?P<slug1>[-\w]+)/$',
views.ArticleDetailView.as_view(), name='article_detail'),
# 草稿箱 - 需要登录
path('draft/', views.ArticleDraftListView.as_view(), name='article_draft_list'),
# 已发表文章列表 - 需要登录
path('admin/', views.PublishedArticleListView.as_view(), name='published_list'),
# 更新文章- 需要登录 - 需要更新权限
re_path(r'^article/(?P<pk>\d+)/update/$',
views.ArticleUpdateView.as_view(), name='article_update'),
# 创建文章 - 需要登录 - 需要创建权限
re_path(r'^article/create/$',
views.article_create, name='article_create'),
# 删除文章 - 需要登录 - 需要删除权限
re_path(r'^article/(?P<pk>\d+)/delete/$',
views.ArticleDeleteView.as_view(), name='article_delete'),]

没看出来没有小问题,因为上面URL中根本没有小问题。可作为开发人员的你连大问题你看不出来就是你程序员的不对了,说不定哪天就丢了饭碗。试想用户访问/article/12/update/或者/article/12/delete/时,他真的会编辑或删除id为12的文章对象吗?错,用户会直接跳转到article/12/my-first-article-for-google/页面。为什么? update和delete本身也是slug啊。Django的URL解析器是自上而下匹配的,用户在访问/article/12/update/时会优先匹配article_detail的URL,并展示第12文章的详情。那我们把展示文章详情的URL和编辑文章的url交换下顺序不就解决问题了?那么万一哪天有个聪明的用户写了篇标题为edit或delete的文章,你是不是该惊出一身冷汗?

正确的URL设计方案如下:

from django.urls import path, re_path
from . import views# namespace
app_name = 'blog'
urlpatterns = [# 展示文章列表
path('', views.article_list, name='article_list'),
# 按类别名展示文章列表
re_path(r'^category/(?P<slug>[-\w]+)/$',
views.CategoryDetailView.as_view(), name='category_detail'),
# 展示文章详情 - 登录/未登录均可
re_path(r'^article/(?P<pk>\d+)/(?P<slug1>[-\w]+)/$',
views.ArticleDetailView.as_view(), name='article_detail'),
# 草稿箱 - 需要登录
path('draft/', views.ArticleDraftListView.as_view(), name='article_draft_list'),
# 已发表文章列表(含编辑) - 需要登录
path('admin/', views.PublishedArticleListView.as_view(), name='published_list'),
# 更新文章- 需要登录和更新权限
re_path(r'^article/(?P<pk>\d+)/(?P<slug1>[-\w]+)/update/$',
views.ArticleUpdateView.as_view(), name='article_update'),
# 创建文章 - 需要登录和创建权限
re_path(r'^article/create/$',
views.article_create, name='article_create'),
# 删除文章 - 需要登录和删除权限
re_path(r'^article/(?P<pk>\d+)/(?P<slug1>[-\w]+)/delete$',
views.ArticleDeleteView.as_view(), name='article_delete'),
]

Path与Re_path的不同

Django的URL设计有path和re_path两种方式,你需要仔细观察两者的相同点和共同点:

  • 相同点:结尾一般是需要有斜线"/"的。
  • 不同点:re_path需要小"r"注明正则匹配,已"^"开头,已"$"结尾。

如果不按规范写,你的URL可能永远都匹配不到你想要的内容。如果你习惯了开发RESTful API,你还需要知道Django URL设计与RESTful API URI设计的不同。

  • RESTful API URI的结尾不能加"/",Django URL需要
  • RESTful API URI不能包含动词,只能是名词,Django URL很常用。
  • RESTful API URI代表资源的名字要以复数命名,Django URL无所谓。

当你用Django REST Framework开发Web API时,你需要遵循RESTful API的规范,比如结尾不加"/",这是与传统Web开发不同的地方。

小结

URL的设计可以很美,但也充满陷阱。希望本文能帮你避开Django URL设计中的常见陷阱。

大江狗

2019.08.23

Django基础(28): 如何设计充满陷阱的优美URL相关推荐

  1. Django基础(11): 表单集合Formset的高级用法详解

    Formset(表单集)是多个表单的集合.Formset在Web开发中应用很普遍,它可以让用户在同一个页面上提交多张表单,一键添加多个数据,比如一个页面上添加多个用户信息.今天小编我就介绍下Djang ...

  2. Django基础核心技术之Model模型的介绍与设计

    Django基础核心技术之Model模型的介绍与设计 原创: Yunbo Shi Python Web与Django开发 2018-05-03 Django网络应用开发的5项基础核心技术包括模型(Mo ...

  3. 学一点django基础

    学一点Django基础 目录 文章目录 目录 一.Django框架的介绍 Django的安装 Django框架开发 创建项目的指令 Django项目的目录结构 URL 介绍 视图函数(view) Dj ...

  4. Day47 Django基础部分、路由配置、空间名称

    1.最简单的路由配置 URL配置(URLconf)就像Django 所支撑网站的目录.它的本质是URL与要为该URL调用的视图函数之间的映射表:你就是以这种方式告诉Django,对于客户端发来的某个U ...

  5. Django基础-Web框架-URL路由

    Django基础-Web框架-URL路由 一.Django基础–Web框架 MVC和MTV框架 MVC 把Web应用分为模型(M).视图(V).控制器(C)三层,他们之间以一种插件式的,松耦合的方式联 ...

  6. 基础计算机构,基础计算与设计

    第七章 基础计算与设计 录入系统建模完成后,选择[生成计算数据]菜单,弹出对话框,选择[生成基础CAD数据],当进入[基础CAD]后才能显示平面图形.进入[基础CAD]后,选择[读取墙柱底力]菜单,弹 ...

  7. Django基础教程

    一.Django基础与设计模型 1.Django是什么? Django 是用 Python 开发的一个免费开源的 Web 框架,可以用于快速搭建高性能.优雅的网站,Django 提供了许多网站后台开发 ...

  8. 我的Blog搭建之旅1——Django基础

    我的Blog搭建之旅1--Django基础 文章目录 我的Blog搭建之旅1--Django基础 事先说明 这不是一个Django教程! === 2019.1.29 === 配置 < pytho ...

  9. django基础到高手知识笔记总结,50页笔记,共10大模块(第一期).md

    django基础到高手知识笔记总结,50页笔记,共10大模块(第一期).md 完整笔记在这: Django基础到高手完整笔记 完整笔记目录: 第一期笔记内容 Python Web 框架要点 1. We ...

最新文章

  1. Java开发面试题及答案,SpringBoot统一日志处理原理
  2. 如何自定义SAP Spartacus店铺的购物车图表css风格
  3. Zookeeper面试题锦集
  4. Pythonic---------详细讲解
  5. emacs .emacs_使用Emacs应该做的6件事
  6. 【MySQL】MySQL 8 ERROR 1193 (HY000): Unknown system variable ‘tx_isolation‘
  7. leetcode之有效的括号
  8. 最全,从小白到交互设计大牛的105条设计原则-附PDF资料
  9. 经济应用数学基础二 线性代数 (第四版) 赵树嫄 编| 中国人大版 课后习题答案
  10. node-webkit:开发桌面+WEB混合型应用的神器
  11. 面向功利编程,面向Star开源? 一个开发者的2019反思总结
  12. python xgboost建模过程_python - Dask中的XGBoost建模 - SO中文参考 - www.soinside.com
  13. Elasticsearch - 短语匹配(match_phrase)以及slop参数
  14. 到底什么是建立时间/保持时间?
  15. “飞天”就是一个操作系统,最重要的功能就是资源管理;这套系统简单说就是把所有资源抽象成一台计算机,并通过互联网提供计算服务。...
  16. Python + PIL 处理支付宝AR红包
  17. pygame小项目 ~ 3 :Python完成简易飞机大战
  18. 字节跳动2019校招笔试题(后端开发)一
  19. mysql五日均线代码_5日均线--攻击线
  20. 解决hexo d命令报错 ERROR Deployer not found: git

热门文章

  1. java毕业设计城市智能公交系统Mybatis+系统+数据库+调试部署
  2. mysql float 转换 int_Mysql 数值类型(int,float,tinyint.......)[转]
  3. 从亚马逊、微软、谷歌的云之争,看国内云计算的未来
  4. ES6 块级作用域详解
  5. Nuke python添加自定义工具架
  6. Kubernetes 当中启用IPVS模式
  7. 无线网络呗主服务器限制网速怎么办,网速限制解除方法有哪些 wifi网络被限制如何解除...
  8. SQL注入原理以及预防措施
  9. 1、Latex学习笔记之基础入门篇
  10. kaggle项目:纽约出租车行程时间NYC Taxi Trip Duration