Django之深入了解路由层
ORM表关系建立
换位思考,先粘在一张表上面分析, 然后再站在另一张表上分析
一对一
外键字段创建在任意一张表都可以,简易在查询频率较高的一方添加
OneToOneField
models.OneToOneField(to='Author_detail') # fk + unique
一对多
外键字段创建在多的那一方
ForeignKey
models.ForeignKey(to='Publish') # to用来指代跟哪张表有关系 默认关联的就是表的主键字段
多对多
外键关系需要创建第三张表来处理。
ManyToManyField
models.ManyToManyField(to='Author') # django orm会自动帮你创建第三张关系表
Django 请求生命周期
url 路由层
urlpatterns = [
url(r'^admin/', admin.site.urls),
]
url的第一个参数其实就是一个正则表达式,只要该正则表达式能够匹配到内容,就会立刻执行后面的视图函数,不再往下继续匹配。
路由匹配
Django settings.py配置文件中默认没有 APPEND_SLASH 这个参数,但 Django 默认这个参数为 APPEND_SLASH = True。 其作用就是自动在网址结尾加'/'。
我们定义了urls.py:
from django.conf.urls import url
from app01 import views
urlpatterns = [
url(r'^blog/$', views.blog),
]
其效果就是:
访问 http://www.example.com/blog 时,默认将网址自动转换为 http://www.example/com/blog/ 。
如果在settings.py中设置了 APPEND_SLASH=False,此时我们再请求 http://www.example.com/blog 时就会提示找不到页面。
Django 路由匹配的规律:
- 先是不加斜杠,先匹配依次试试,
- 如果匹配不上,会让浏览器重定向,url最后加上斜杠再次匹配一次,
- 如果还是匹配不上就报错了。
- 并且不会匹配GET请求
?
后面携带的参数
无名分组
将分组内正则表达式匹配到的内容当做位置参数传递给视图函数
url(r'^test/([0-9]{4})/', views.test)
访问的url:http://127.0.0.1/test/1111
# 当你的路由中有分组的正则表达式 那么在匹配到内容
# 执行视图函数的时候 会将分组内正则表达式匹配到的内容当做位置参数传递给视图函数
def test(request,xxx):
'''
此时url有第二个参数,会传递给视图函数位置参数传进来。
如果不写接收的位置参数则会报错
test() takes 1 positional argument but 2 were given
'''
print(xxx) # 1111
pass
有名分组
将分组内正则表达式匹配到的内容当做关键字参数传递给视图函数
url(r'^test/(?P<year>[0-9]{4})/', views.test)
访问的url:http://127.0.0.1/test/1111
# 当你的路由中有分组的正则表达式 那么在匹配到内容
# 执行视图函数的时候 会将分组内正则表达式匹配到的内容当做关键字参数传递给视图函数
def test(request,year):
'''
此时url有第二个参数,会传递给视图函数关键字参数传进来。
如果不写接收的关键字参数则会报错
testadd() got an unexpected keyword argument 'year'
'''
print(year) # 1111
pass
利用有名个无名分组 我们就可以在调用视图函数之前给函数传递额外的参数
注意:无名分组和有名分组不能混合使用
但是同一种分组的情况下 可以使用多次,
无名可以有多个
有名可以有多个
反向解析
给路由匹配设置一个别名,
根据这个别名,动态解析出一个结果,该结果可以直接访问对应的url。
路由匹配条件无分组的情况的反向解析
urls.py:
url(r'^home/',views.home,name='hm'),
url(r'^index/$',views.index),
views.py:
def home(request):
return HttpResponse(reverse('hm'))
def index(request):
print(reverse('hm')) # /home/
return render(request,'test.html')
test.html:
<body>
<div>TEST</div>
<p><a href="{% url 'hm' %}">点我点我</a></p>
</body>
当我们在浏览器URL输入http://127.0.0.1:8000/index/的时候,
python后端进行reverse反向解析成 别名为'hm'的路径前缀,也就是home路径,
用test.html 页面渲染,html也可以使用反向解析
python后端使用反向解析:
reverse('hm')
前端html使用反向解析:
{% url 'hm' %}
将路径解析为/home/。
无名分组情况的反向解析
urls.py:
url(r'^home/(\d+)/',views.home,name='hm'),
url(r'^index/',views.index),
views.py:
def home(request,xxx):
# 使用无名分组,视图函数必须写位置参数
print(xxx)
return HttpResponse('ok')
def index(request):
print(reverse('hm',args=(1,))) # 无名分组需要手动给别名传递一个参数才能匹配上,这个参数会传递到视图函数当做位置参数。
return render(request,'test.html')
test.html:
<body>
<div>TEST</div>
<p><a href="{% url 'hm' 1 %}">点我点我</a></p>
</body>
当一个无名分组使用别名的时候,在浏览器URL输入http://127.0.0.1:8000/index/,python后端进行reverse反向解析成 别名为'hm'的路径前缀,也就是home路径,需要手动给解析出来的路径加参数,不然匹配不成功
用test.html 页面渲染,并且html使用反向解析,也需要手动传入参数
python后端使用反向解析:
reverse('hm',args=(1,))
前端html使用反向解析:
{% url 'hm' 1 %}
将路径解析为/home/1。
有名分组的反向解析
urls.py:
url(r'^home/(?P<year>\d+)/',views.home,name='hm'),
url(r'^index/',views.index),
views.py:
def home(request,year):
# 使用有名分组,视图函数必须写关键字参数
print(year)
return HttpResponse('ok')
def index(request):
print(reverse('hm',args=(1,))) # 这样也可以,但不正规
print(reverse('hm',kwargs={"year":1})) # 最正规的写法,因为有名分组传入的是关键字参数,用kwargs参数来表示
return render(request,'test.html')
test.html:
<body>
<div>TEST</div>
<p><a href="{% url 'hm' 1 %}">点我点我</a></p> # 这样也可以,但不正规
<p><a href="{% url 'hm' year=1 %}">点我点我</a></p> # 最正规的写法,因为有名分组传入的是关键字参数
</body>
当一个无名分组使用别名的时候,在浏览器URL输入http://127.0.0.1:8000/index/,python后端进行reverse反向解析成 别名为'hm'的路径前缀,也就是home路径,需要手动给解析出来的路径加参数,不然匹配不成功。
用test.html 页面渲染,并且html使用反向解析,也需要手动传入参数
python后端使用反向解析:
reverse('hm',kwargs={"year":1})
前端html使用反向解析:
{% url 'hm' year=1 %}
将路径解析为/home/1。
例子
伪代码以编辑用户信息为例,演示具体用法:
urls.py:
url(r'^edit_user/(\d+)',views.edit_user,name='edit'),
views.py:
def edit_user(request,edit_id):
# 查出来所有 user_list
# edit_id 就是用户想要编辑数据的主键值
print(edit_id)
return render(request,'edit_user.html',{"user_list":user_list})
edit_user.hmtl:
{% for user_obj in user_list %}
<a href="/edit_user/{{ user_obj.id }}">编辑</a>
<a href="{% url 'edit' user_obj.id %}">编辑</a>
{% endfor %}
路由分发
前言,在django中所有的app都可以有自己的独立的urls.py、templates、static文件夹
那么正是由于这个特点,你的django项目可以由多个人一起开发。小组长最后只需要把所有的开发的app整合到一个空的django项目里面,在settings配置文件里注册就可以了。
路由分发解决的就是项目的总路由匹配关系过多的情况,使用路由分发 会将总路由不再做匹配的活 而仅仅是做任务分发
我们新建一个app02,现在我的目录结构是:
python3 manage.py startapp app02
- app01
- app02
- mysite
- static
- templates
- manage.py
好了之后
我们在app01目录中创建urs.py
app01/urls.py:
from app01 import views
from django.conf.urls import url
urlpatterns = [
url(r'^reg/',views.reg),
]
app01/views.py:
def reg(request):
return HttpResponse("app01 reg")
-----------------------------------
app02/urls.py:
from app02 import views
from django.conf.urls import url
urlpatterns = [
url(r'^reg/',views.reg),
]
app02/views.py:
def reg(request):
return HttpResponse("app02 reg")
总urls:mysite/urls.py:
from app01 import urls as app01_urls
from app02 import urls as app02_urls
urlpatterns = [
url(r'^app01/',include(app01_urls)),
url(r'^app02/',include(app02_urls)),
]
或者更省事的写法,不用把两个app的urls.py导过来:
urlpatterns = [
url(r'^app01/',include('app01.urls')),
url(r'^app02/',include('app02.urls')),
]
最终效果,在浏览器url中输入
http://127.0.0.1:8000/app01/reg # app01 reg
http://127.0.0.1:8000/app02/reg # app02 reg
名称空间
当多个app中出现了起别名冲突的情况 你在做路由分发的时候 可以给每一个app创建一个名称空间,然后在反向解析的时候 可以选择到底去哪个名称空间中查找别名
url(r'^app01/',include('app01.urls',namespace='app01')),
url(r'^app02/',include('app02.urls',namespace='app02'))
# 后端
print(reverse('app01:reg'))
print(reverse('app02:reg'))
# 前端
<a href="{% url 'app01:reg' %}"></a>
<a href="{% url 'app02:reg' %}"></a>
其实不用这么麻烦,
参考建议
起别名的时候统一加上应用名前缀,这样你的别名就不会重复了。
urlpatterns = [url(r'^reg/',views.reg,name='app01_reg')]
urlpatterns = [url(r'^reg/',views.reg,name='app02_reg')]
伪静态
将一个动态网页伪装成一个静态的网页,来提高搜索引擎SEO的查询频率,提高网站的曝光度!
怎么做呢,比如博客园是一个动态网站,但是看起来像一个静态网站,是因为每篇文章都有后缀名.html
那么我们也可以写,在路由匹配规则中写上
# https://www.cnblogs.com/qinyujie/p/11394671.html
url(r'^article/(\d+).html',views.article)
虚拟环境
虚拟环境就相当于重新下载了一个纯净的python解释器,之后项目用这个虚拟环境,你需要什么就安装什么,与系统环境上存在的软件不冲突。
Django版本区别
urls.py路由匹配的方法有区别。
django 1.X
导入的模块是
from django.conf.urls import url
,
urlpatterns 中 url 对应的是正则表达式,
如下:
from django.conf.urls import url
urlpatterns = [
url = ('test',view.test)
]
django 2.X
导入的模块是from django.urls import re_path,path
path中第一个参数不支持正则表达式,写了什么就只能匹配什么,匹配不到就报错。
django 2.X 觉得你习惯了之前的正则表达式来匹配,特别人性化 ,
提供一个re_path
方法,这个方法就是1.X版本中的url()
如下:
from django.urls import path,re_path
urlpatterns = [
path = ('test',view.test),
re_path = (r'^test/(\d+)',view.test)
]
django 2.X的版本中还提供了五种转换器,
- str:匹配除路径分隔符/外的字符串
- int:匹配自然数
- slug:匹配字母,数字,横杠及下划线组成的字符串
- uuid:匹配uuid形式的数据
- path:匹配任何字符串,包括路径分隔符/
urlpatterns = [
path = ('test/<str:\d+>',view.test)
path = ('test/<int:\d+>',view.test)
path = ('test/<slug:\d+>',view.test)
path = ('test/<uuid:\d+>',view.test)
path = ('test/<path:\d+>',view.test)
]
除了内置的五种转换器外,还可以自定义自己的转换器。
- 在应用文件夹下创建converter.py文件
- 在converter.py文件中创建自定义类
- 在类中定义regex 正则,to_python方法,to_url方法
class CVT185Phone:
regex = '185\d{8}'
def to_python(self, value):
return int(value)
def to_url(self, value):
return '%11d' % value
from django.urls import register_converter
from app.converter import CVT185phone
register_converter(CVT185phone,'phone185')
path('page/<phone185:msg>/',views.page,name="pages")
小例子
通过路由分发,使用app01上传文件的功能上传一个文件;
mysite/urls.py
urlpatterns = [
url(r'^app01/',include('app01.urls')),
url(r'^app02/',include('app02.urls')),
]
app01/urls.py
from app01 import views
from django.conf.urls import url
urlpatterns = [
url(r'^upload/',views.upload,name='app01_upload'),
]
app01/views.py
from django.shortcuts import reverse,render,HttpResponse,redirect
def upload(request):
if request.method == "POST":
print(request.FILES)
file_obj = request.FILES.get("myfile")
with open(file_obj.name,"wb") as f:
for i in file_obj:
f.write(i)
return render(request,'upload.html')
templates/upload.html
<body>
<form action="" method="post" enctype="multipart/form-data">
请选择文件
<input type="file" name="myfile">
<input type="submit" class="btn btn-primary">提交
</form>
Django之深入了解路由层的更多相关文章
- django 实战篇之路由层
路由层 如何给网页添加首页及尾页 urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'test',views.test), url(r'te ...
- day 45 Django 的初识2 路由层,视图层,模板层
前情提要: 今天继续学习Django 的内容, 今天主要和渲染相关 1>配置路由 >2:写函数 >3 指向url 一:路由层 1:配置静态支持文件 1:路由层的简单配置 >dj ...
- Django的日常-路由层
目录 Django的日常-2 路由层 有名分组和无名分组 反向解析 路由的分发 Django的日常-2 路由层 我们之前已经接触过路由层,只是我们可能不知道他叫这个名字,实际上在Django里面路由层 ...
- Django( 学习第三部 Django的url路由层)
目录 url路由层 路由匹配(有名分组与无名分组) 反向解析 路由分发 名称空间(了解) Django版本区别 url 路由匹配 注意事项: url方法,第一个参数是正则表达式,只要第一个参数能够匹配 ...
- Django学习——路由层之路由匹配、无名分组、有名分组、反向解析
路由层之路由匹配 """路由你可以看成就是出去ip和port之后的地址""" url()方法 1.第一个参数其实是一个正则表达式 2.一旦第 ...
- Django 路由层(urlconf)
Django 的路由层(URLconf) URL配置(conf)就像是Django所支撑的网站的目录; 本质就是:URL与调用该URL执行的视图函数的映射表; 通俗的讲:就是用户使用哪个url,URL ...
- Django 的路由层 视图层 模板层
--------------------------------------------------------------通过苦难,走向欢乐.——贝多芬 Django-2的路由层(URLconf) ...
- Django路由层
路由层简单配置 urlpatterns = [ url(r'^admin/$', admin.site.urls), url(r'^articles/2003/$', views.special_ca ...
- $Django 虚拟环境,2.0、1.0路由层区别,Httprequest对象,视图层(fbv,cbv),文件上传
1 虚拟环境:解决问题同一台机器上可以运行不同版本的django, 1 用pychanrm创建--->files-->newproject--->选择虚拟环境 2 setting ...
随机推荐
- 2019 牛客多校第一场 E ABBA
题目链接:https://ac.nowcoder.com/acm/contest/881/E 题目大意 问有多少个由 (n + m) 个 ‘A’ 和 (n + m) 个 ‘B’,组成的字符串能被分割成 ...
- Mysql命令增加、修改、删除表字段
alter add 命令用来增加表的字段: alter add命令格式:alter table 表名 add字段 类型 其他:如下所示: ) comment '单位' alter drop 命令删除表 ...
- scala中闭包的使用
闭包的实质就是代码与用到的非局部变量的混合,即: 闭包 = 代码 + 用到的非局部变量 实例1: 匿名函数中引入闭包 val multiplier = (i:Int) => i * factor ...
- de4Dot用法 解决 .net程序 reflecter反编译 “索引超出了数组界限”问题
de4Dot 反混淆工具.当你反编译 .net写的dll 或exe时出现:索引超出了数组界限 问题时 可以去网上下这个工具,通过cmd命令 打开de4dot的exe 空格 dll的全路径. 这样 :D ...
- Js_案例(电灯)
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- Linux服务器下对Oracle数据库expdp(导出)和impdp(导入)
紧接上篇文章,Oracle数据库架构已经创建完成,我的需求是:将老服务器上的数据库迁移到新的数据库上. 这就用到impdp(导入)操作. 要想实现对新数据库的impdp(导入)工作, 首先需要从老的数 ...
- 使用FastJson转化Json格式
1.下载Jar包 http://repo1.maven.org/maven2/com/alibaba/fastjson/ 2.将jar包导入工程 3.示例 package nc.testFastJso ...
- [JZOJ3691] 【CF414E】Mashmokh's Designed tree
题目 题目大意 给你一棵树,接下来对这棵树进行三种操作: 1.询问两点之间的距离. 2.让某个点变为它原来的第\(h\)个祖先的最后一个儿子. 3.求\(dfs\)序中最后一个深度为\(k\)的点. ...
- 基于VUE利用pdf.js实现文件流形式的pdf显示
首先推荐大家看一下这个demo vue-pdf.js-demo,这里面包含固定本地地址,远程pdf地址,通过打开文件的方式打开pdf 这儿我们着重介绍一下通过文件流的形式打开pdf.(所谓文件流,就是 ...
- flink提交文件出现java.io.IOException:unable to close file because the last block does not have enough number of replicas异常
当提交已经打包好的jar包时候,控制台出现以下的错误.