Django基础(28): 如何设计充满陷阱的优美URL
一个优美的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相关推荐
- Django基础(11): 表单集合Formset的高级用法详解
Formset(表单集)是多个表单的集合.Formset在Web开发中应用很普遍,它可以让用户在同一个页面上提交多张表单,一键添加多个数据,比如一个页面上添加多个用户信息.今天小编我就介绍下Djang ...
- Django基础核心技术之Model模型的介绍与设计
Django基础核心技术之Model模型的介绍与设计 原创: Yunbo Shi Python Web与Django开发 2018-05-03 Django网络应用开发的5项基础核心技术包括模型(Mo ...
- 学一点django基础
学一点Django基础 目录 文章目录 目录 一.Django框架的介绍 Django的安装 Django框架开发 创建项目的指令 Django项目的目录结构 URL 介绍 视图函数(view) Dj ...
- Day47 Django基础部分、路由配置、空间名称
1.最简单的路由配置 URL配置(URLconf)就像Django 所支撑网站的目录.它的本质是URL与要为该URL调用的视图函数之间的映射表:你就是以这种方式告诉Django,对于客户端发来的某个U ...
- Django基础-Web框架-URL路由
Django基础-Web框架-URL路由 一.Django基础–Web框架 MVC和MTV框架 MVC 把Web应用分为模型(M).视图(V).控制器(C)三层,他们之间以一种插件式的,松耦合的方式联 ...
- 基础计算机构,基础计算与设计
第七章 基础计算与设计 录入系统建模完成后,选择[生成计算数据]菜单,弹出对话框,选择[生成基础CAD数据],当进入[基础CAD]后才能显示平面图形.进入[基础CAD]后,选择[读取墙柱底力]菜单,弹 ...
- Django基础教程
一.Django基础与设计模型 1.Django是什么? Django 是用 Python 开发的一个免费开源的 Web 框架,可以用于快速搭建高性能.优雅的网站,Django 提供了许多网站后台开发 ...
- 我的Blog搭建之旅1——Django基础
我的Blog搭建之旅1--Django基础 文章目录 我的Blog搭建之旅1--Django基础 事先说明 这不是一个Django教程! === 2019.1.29 === 配置 < pytho ...
- django基础到高手知识笔记总结,50页笔记,共10大模块(第一期).md
django基础到高手知识笔记总结,50页笔记,共10大模块(第一期).md 完整笔记在这: Django基础到高手完整笔记 完整笔记目录: 第一期笔记内容 Python Web 框架要点 1. We ...
最新文章
- Java开发面试题及答案,SpringBoot统一日志处理原理
- 如何自定义SAP Spartacus店铺的购物车图表css风格
- Zookeeper面试题锦集
- Pythonic---------详细讲解
- emacs .emacs_使用Emacs应该做的6件事
- 【MySQL】MySQL 8 ERROR 1193 (HY000): Unknown system variable ‘tx_isolation‘
- leetcode之有效的括号
- 最全,从小白到交互设计大牛的105条设计原则-附PDF资料
- 经济应用数学基础二 线性代数 (第四版) 赵树嫄 编| 中国人大版 课后习题答案
- node-webkit:开发桌面+WEB混合型应用的神器
- 面向功利编程,面向Star开源? 一个开发者的2019反思总结
- python xgboost建模过程_python - Dask中的XGBoost建模 - SO中文参考 - www.soinside.com
- Elasticsearch - 短语匹配(match_phrase)以及slop参数
- 到底什么是建立时间/保持时间?
- “飞天”就是一个操作系统,最重要的功能就是资源管理;这套系统简单说就是把所有资源抽象成一台计算机,并通过互联网提供计算服务。...
- Python + PIL 处理支付宝AR红包
- pygame小项目 ~ 3 :Python完成简易飞机大战
- 字节跳动2019校招笔试题(后端开发)一
- mysql五日均线代码_5日均线--攻击线
- 解决hexo d命令报错 ERROR Deployer not found: git
热门文章
- java毕业设计城市智能公交系统Mybatis+系统+数据库+调试部署
- mysql float 转换 int_Mysql 数值类型(int,float,tinyint.......)[转]
- 从亚马逊、微软、谷歌的云之争,看国内云计算的未来
- ES6 块级作用域详解
- Nuke python添加自定义工具架
- Kubernetes 当中启用IPVS模式
- 无线网络呗主服务器限制网速怎么办,网速限制解除方法有哪些 wifi网络被限制如何解除...
- SQL注入原理以及预防措施
- 1、Latex学习笔记之基础入门篇
- kaggle项目:纽约出租车行程时间NYC Taxi Trip Duration