共计 6738 个字符,预计需要花费 17 分钟才能阅读完成。
一. 路由层之路由匹配
1. 什么是路由
- 路由可以看成是跟在 ip 和 port 之后的地址
2.url() 方法
# 示例
urlpatterns = [url(r'^admin/', admin.site.urls),
url(r'^login/', views.login_func),
url(r'^register/$', views.register_func),
]
url()
方法的第一个参数其实是 正则表达式, 一旦第一个参数匹配到了内容直接结束匹配, 并调用对应的视图函数
3. 路由匹配注意事项
- 不需要在路由前面添加反斜杠
"/"
, 因为每个 url 自带 - 建议在正则表达式之前添加原生字符
"r"
- 每个由正则匹配成功并通过分组捕获的参数都会作为一个普通的 Python 字符串传递给视图函数
- 如果路由结尾没有
"/"
, 在第一次正则匹配机制没有匹配到想要的内容时, 会在匹配字符后加一个"/"
, 然后 Django 内部重定向在匹配一次
4. 取消自动添加斜杠 "/"
- 上面测试了路由后面不添加
"/"
一共匹配了两次 - 而自动添加斜杠这种操作是可以取消的
# setting.py 文件
APPEND_SLASH = False # 默认 True 自动添加斜杠
- 设置之后如果不添加斜杠就无法访问资源
建议自动添加
二. 分组命名匹配
1. 无名分组
-
url() 方法中第一个参数正则表达式分组 : 给正则表达式前后加一个小括号
-
会将括号内正则表达式匹配到的内容当做位置参数传递给后边的视图函数
url(r'^login/$', views.login_func)
# 无名分组
url(r'^login/(\d+)/$', views.login_func)
# 视图函数
def login_func(request,*args):
print(args)
return Httpresponse(args)
2. 有名分组
- 将正则表达式分组捕获到的内容定义一个名字
- 会将括号内正则表达式匹配到的内容当做关键字参数传递给后面的视图函数
url(r'^login/$', views.login_func)
# 有名分组
url(r'^login/(?P<id>\d+)/$', views.login_func)
# 视图函数
def login_func(request,**kwargs):
print(kwargs)
return Httpresponse(args)
3. 无名有名是否可以结合使用
- 不能 结合使用
url(r'^login/(\d+)/(?P<id>\d+)/$', views.login_func)
# 官方说不能混着用, 混着用只能取到有名分组捕获的值
# 只要不混着用, 有名分组和无名分组支持多个相同类型的传参
- 可以单个重复使用
url(r'^login/(\d+)/(\d+)/$', views.login_func)
url(r'^login/(?P<id>\d+)/(?P<id>\d+)/$', views.login_func)
三. 反向解析
1. 什么是反向解析
- 反向解析就是通过一些方法得到一个结果, 该结果可以直接访问对应的 url 并触发视图函数
2. 反向解析的作用
- 在使用一个 Django 项目时, 我们经常需要将一个 url 嵌入到生成的内容中去, 如果将这些 url 固定写死, 那么可扩展性很差, 并且一定程度上会产生过期的 url
- 使用反向解析就是当路由频繁变化的时候, 让 html 界面上的连接地址做到动态解析
3. 如何使用反向解析
- 给路由与视图函数对应关系添加一个别名 (名字由自己指定, 只要不冲突即可)
# 路由层
url(r'^login/$', views.login_func,name='login_name')
- 根据该别名可动态解析出一个结果, 该结果可以直接访问到对应的路由
# 前端中使用(模板层)
<a href="{% url 'login_name' %}"> 登入 </a>
# 后端中使用(视图层)
from django.shortcuts import reverse
url = reverse('login_name')
ps : redirect() 括号内也可以直接写别名
4. 无名分组反向解析
- 路由层配置
url(r'^login/(\d+)/', views.login_func,name='login_name')
- 视图层配置
from shortcuts import reverse
url = reverse('login_name',args=(1,)) # 随便给个数字
- 模板层
<a href="{% url 'login_name' 1 %}"> 登入 </a> # 随便给个数字
路由层中分组匹配得到的数字并不是我们这样写死的, 一般情况下放的是数据的主键值, 我们可以通过获取到数据的主键. 进而定位到数据对象, 从而可以对数据进行编辑和删除
# 路由层
url(r'^login/(\d+)/', views.login_func,name='login_name')
# 视图层
def edit(request,edit_id):
reverse('login_name',args=(edit_id,))
# 模板层
{% for user_obj in user_list %}
<a href="{% url 'login_name' user_obj.id %}">kkk</a>
5. 有名分组反向解析
- 路由层配置
url(r'^login/(?P<id>\d+)/', views.login_func,name='login_name')
- 视图层配置
from shortcuts import reverse
url = reverse('login_name',kwargs=(id:111)) # 随便给个数字
url= =
reverse('login_name',args=(111,)) # 也可以这样写
- 模板层配置
<a href="{% url 'login_name' id=111 %}"> 登入 </a> # 随便给个数字
<a href="{% url 'login_name' 11 %}"> 登入 </a> # 也可以这样写
由上面的视图层与模板层的第二种书写方式可以看出 : 无名有名都 可以使用一种反向解析形式 : 就是 无名 反向解析
四. 路由分发
1. 路由分发简介
django 是专注于开发应用的,当一个 django 项目特别庞大的时候, 所有的路由与视图函数映射关系全部写在一个 urls.py 里面很明显太冗余并且不便于管理
其实 django 中的每一个应用都可以有自己的 urls.py、static 文件夹、templates 文件夹 , 基于上述特点, 使用 django 做 分组开发 非常的简便
每个人只需要写自己的应用即可, 最后由组长统一汇总到一个空的 django 项目中然后使用路由分发将多个应用关联到一起
- 利用路由分发之后, 总路由不再干路由与视图函数的直接对应关系, 而是做一个分发处理, 进而识别当前 url 所属的应用, 最后直接分发给对应的应用去处理就行了, 并且应用路由重名也无关要紧
2. 路由分发设置
- 总路由文件 : urls.py
🔰注意 : 总路由正则后面不能添加 "$"
, 不然一配到 app01 就结束了
from django.contrib import admin
from django.urls import path,re_path,include
# 方式一 : 复杂写法
from app01 import urls as app01_ulrs
from app02 import urls as app02_ulrs
urlpatterns = [path('admin/', admin.site.urls),
re_path(r'^app01/', include(app01_ulrs)),
re_path(r'^app02/', include(app02_ulrs)),
re_path(r'^app03/', include(app03_ulrs))
]
# 方式二 : 高级写法
urlpatterns = [path('admin/', admin.site.urls),
re_path(r'^app01/', include('app01.ulrs')),
re_path(r'^app02/', include('app02.ulrs')),
re_path(r'^app03/', include('app03.ulrs'))
]
- 每个应用路由 (子路由) 文件 : urls.py
from django.contrib import admin
from django.urls import path,re_path
from [app 名] import views
urlpatterns = [re_path(r'^home/',views.home_func),
re_path(r'^index/',views.index_func),
re_path(r'^edit/',views.edit_func),
]
五. 名称空间
1. 为什么使用名称空间
当多个应用设置了相同的别名, 在反向解析的时候前面路由会被后面的路由覆盖, 那么就无法触发前面路由对应的视图函数, 正常情况下, 反向解析是无法自动识别前缀的, 为了避免这种错误, 引入了名称空间
2. 应用命名空间与实例命名空间
- name_app : 应用命名空间 : 通常在应用 app 的 urls.py 文件中指定 (Django2 版本以后不指定报错)
# app01
app_name='app01' # 应用命名空间
urlpatterns = [re_path(r'^home/',views.home_func,name='home_name')
]
- namespace : 实例命名空间 : 通常在总路由文件中指定
2. 解决方式 1 : 使用名称空间
- 总路由设置 : urls.py 文件
urlpatterns = [path('admin/', admin.site.urls),
re_path(r'^app01/', include('app01.ulrs',namespace='app01')),
re_path(r'^app02/', include('app02.ulrs',namespace='app02')),
re_path(r'^app03/', include('app03.ulrs',namespace='app03'))
]
- 子路由设置 : urls.py 文件
# app01
app_name='app01'
urlpatterns = [re_path(r'^home/',views.home_func,name='home_name')
]
# app02
app_name='app02'
urlpatterns = [re_path(r'^home/',views.home_func,name='home_name')
]
# app03
app_name='app03'
urlpatterns = [re_path(r'^home/',views.home_func,name='home_name')
]
- 视图文件 : views.py 文件
# app01
from django.shortcuts import reverse
def home_func(request):
res = reverse('app01:home_name')
return HttpResponse(res) # /app01/home/
# app02
from django.shortcuts import reverse
def home_func(request):
res = reverse('app02:home_name')
return HttpResponse(res) # /app02/home/
# app03
from django.shortcuts import reverse
def home_func(request):
res = reverse('app03:home_name')
return HttpResponse(res) # /app03/home/
- 模板层文件
<a href="{% url 'app01:name_name' %}">app01</a>
<a href="{% url 'app02:home_name' %}">app02</a>
<a href="{% url 'app03:home_name' %}">app03</a>
3. 解决方式二 : 手动添加前缀
# app01
urlpatterns = [re_path(r'^home/',views.home_func,name='app01_home_name'),
]
# app02
urlpatterns = [re_path(r'^home/',views.home_func,name='app02_home_name'),
]
# app03
urlpatterns = [re_path(r'^home/',views.home_func,name='app03_home_name'),
]
六. 伪静态
1. 静态页面
- 写好的页面, 数据已经固定死了不会变化
2. 动态页面
- 页面内容可以随着时间、环境、或数据库的变化而发生改变
3. 伪静态页面
- 目的是为了更好的被搜索引擎收录以及 seo 查询几率而通过一定的规则, 把动态页面的地址转换成以 htm 或 html 结尾的地址, 看起来是静态的, 实际是依然是动态页面
- 比如博客园的文章地址结尾就是
.html
, 但我们是可以对文章内容进行修改的
ps : 再如何优化也比不过加钱居士
4. 修改匹配规则实现伪静态
- 路由层文件
urlpatterns = [re_path(r'home.html/',views.home_func),
]
# 访问 : 127.0.0.1:8888/home.html/
七.Django 版本区别
Django 1.x
版本与 2.x
、3.x
版本的区别
1. 路由层中的路由匹配方法
1.x
中使用的是 url() 方法, 第一个参数是正则表达式2.x
与3.x
中使用的是 path() 方法, 第一个参数不支持正则表达式, 些什么就匹配什么
如果想要在
2.x
和3.x
中的第一个参数中使用正则表达式, 则需要导入 re_path 方法
python
from django.urls import path,re_pathre_path 等价于
1.x
中的 url 方法
2.path 方法中的五种常用转换器
str : 匹配除了路径分隔符(/)之外的非空字符串,这是默认的形式
int : 匹配正整数,包含 0。slug : 匹配字母、数字以及横杠、下划线组成的字符串。uuid : 匹配格式化的 uuid,如 075194d3-6885-417e-a8a8-6c931e272f00。path : 匹配任何非空字符串,包含了路径分隔符(/)(不能用? 号)
3. 自定义转换器
class MonthConverter:
regex='\d{2}' # 属性名必须为 regex
def to_python(self, value):
return int(value)
def to_url(self, value):
return value # 匹配的 regex 是两个数字,返回的结果也必须是两个数字
from django.urls import path,register_converter
from app01.path_converts import MonthConverter
# 注册转换器
register_converter(MonthConverter,'mon')
from app01 import views
urlpatterns = [path('articles/<int:year>/<mon:month>/<slug:other>/', views.article_detail, name='date_time'),
]
八. 安装本地虚拟环境
1. 为什么使用本地虚拟环境
- 在时间开发过程中,我们会给不同的项目配备不同的环境
- 项目用到什么就装什么,用不到的一概不装
- 不同的项目解释器环境都不一样
2.requirements.txt 是什么
- 使用别人写好的项目需要安装一大堆的库
- 而 requirements.txt 文件里面就是该项目所依赖的库以及对应的版本
- 使用下面命令自动安装所有依赖项
pip install -r requirements.txt
3. 虚拟环境说明
- 创建虚拟环境类似于你重新下载了一个纯净的 Python 解释器(里面只有 pip 和 setuptools 工具)
- 反复的创建虚拟环境类似于反复的下载 Python 解释器, 会消耗一定的硬盘空间
- 目前不推荐使用虚拟环境, 所有的模块统一都下载到本地
4. 创建虚拟环境
- 打开 pycharm----->File----->New Project----->Pure Python
- 创建成功查看初始的 package : 打开 Pycharm----->File----->settings----->Project:[项目名]----->Python Interpreter
- 下次创建新项目可以直接选择已经创建好的虚拟环境