django路由层分析

路由层

路由层简介

路由层 即django项目文件夹中的 urls.py 文件

urls.py 文件中的 urlpatterns 列表实现的路由匹配
示例:
from app01 import views

urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^index/', views.index)
]
# 列表中url函数中的第一个参数为正则表达式,第二个参数则为匹配成功后执行的函数

添加网站首页 / (404)错误提示页

# 在路由层的 urlpatterns 中添加:
# 添加首页的写法:
url(r'^$', views.home)
# 添加(404)错误提示页的写法:
# 这个要写在最下面一行,要等上面的都匹配失败了才能匹配到404
url(r'', views.error)

分组

无名分组

# 分组这个概念是由正则表达式中引出的,即 url(r'^index/(\d+)', views.index),这个正则表达式中的括号()就是分组
# 路由的分组是不会影响匹配的
# 正则表达式分组是会把分组的内容返回出来的,既 路由中的分组 会将加括号的正则表达式的内容 当做位置参数 传递给对应的视图函数中,所以对应的视图函数需要有一个位置形参来接收这个参数
# 示例:
# urls.py:
from app01 import views
urlpatterns = [
    url('^admin/', admin.site.urls),
    # 无名分组写法:正则表达式中加括号
    url('^index/(\d+)', views.index)  # 匹配一个或多个数字
]

# views.py:
def index(request, numb):  # request是默认要加的参数,而这个numb位置形参则是为了接收分组传递来的参数的
    print(numb)
	return HttpResponse("OK")

有名分组

与无名分组不同,你可以看做有名分组给 要传递给视图函数的参数赋予了一个参数名,然后传递给视图函数的时候传的就是 参数名=参数,既传递过去的是一个关键字参数,所以视图函数接收的时候要给一个关键字形参,即要有一个与路由层的这个参数名一模一样的形参名

# 示例
# urls.py:
from app01 import views
urlpatterns = [
    url('^admin/', admin.site.urls),
    # 有名分组写法,在正则表达式中的分组中写(?P<分组名>)
    url('^index/(?P<year>\d+)', views.index)  # 匹配一个或多个数字
]

# views.py
def index(request,year):  # 这个year与路由层传过来的关键字参数得同名才能接收到参数
    print(year)
    return HttpResponse("OK")

有无名分组注意事项

# 有名分组跟无名分组不能混着用!!!
# 但是支持同一类分组使用多次

# 无名分组多个
url(r'^index/(\d+)/(\d+)/', views.index)

def index(request, numb1, numb2):
    return HttpResponse("OK")

# 有名分组多个
url(r'^index/(?P<year>\d+)/(?P<month>/d+)/', views.index)

def index(request, year, month):
    return HttpResponse("OK")

解析

反向解析

路由层中的url方法中有一个属性 name
可以给每一个路由与视图函数的对应关系起一个名字(别名)
这个名字能够唯一标识出对应的路径
# 注意这个名字不能是重复的
给这一条url设置了name属性之后,前端和后端就可以通过这个name值动态获取到对应的路径:
urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'indexadd/', views.index, name="index")
]

# 后端views.py文件中获取路径方法:
# 先导入一个reverse模块
from django.shortcuts import reverse  # 与三板斧同源

reverse('index')
reverse('这里面填的是你给路由和视图函数对应关系起的 别名')

# 前端 html文件中获取路径的方法:
{% url 'index' %}
{% url '这里面填的是你给路由和视图函数对应关系起的 别名' %}

无名分组反向解析

# 同理,加上name属性:
url(r'^index/(\d+)/', views.index, name="index")


# 后端views.py文件中获取路径方法:
# 先导入一个reverse模块
from django.shortcuts import reverse  # 与三板斧同源

reverse('index', arg=(numb,))  # 元组中的 ,逗号一定要加上
reverse('别名',arg=(接收无名分组传递给视图函数的参数,))

# 前端 html文件中获取路径的方法:
{% url 'index' id %}
{% url '别名' 要传递给后端的值 %}

案例:

# views.py 文件:
from django.shortcuts import reverse

def index(request,pk):
	url = reverse('index', args=(pk,))
    user_list = models.User.objects.all()
    return render(request, 'index.html',{'user_list':user_list})
<!--html文件-->
<!DOCTYPE HTML>
<html lang="en">
    <head>
        <meta charset="utf8">
        <title>title</title>
    </head>
    <body>
        {% for user_obj in user_list %}
        	<a href="/index/{{ user_obj.pk }}/"></a>
        {% endfor %}

        {{ url 'index' user_obj.pk }}
    </body>
</html>
# urls.py文件:
urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^index/(\d+)/', views.index, name="index")
]

有名分组反向解析

# 同理,加上name属性:
url(r'^index/(?P<numb>\d+)/', views.index, name="index")

# 后端views.py文件中获取路径方法:
# 先导入一个reverse模块
from django.shortcuts import reverse  # 与三板斧同源
# 方法一:与无名分组解析相同,有名分组解析也可这样写
reverse('index', arg=(numb,))  # 元组中的 ,逗号一定要加上
reverse('别名',arg=(接收无名分组传递给视图函数的参数,))
# 方法二:(了解即可)
reverse('index',kwargs={"numb":numb1})

# 前端 html文件中获取路径的方法:
# 方法一:无名和有名分组解析都可以这样写
{% url 'index' id %}
# 方法二:(了解即可)
{% url '别名' numb=id %}

反向解析总结

总结:针对有名分组与无名分组的反向解析 统一采用一种格式即可:
# 前端
{% url 'index' numb %}

# 后端
reverse('index',args=(numb,))  # 这里的numb通常都是数据的主键值

反向解析的本质:
	就是获取到一个能够访问 别名 所对应的视图函数

路由分发

django每一个app下面都可以有自己的urls.py路由层、templates文件夹、static文件夹
项目名下的urls.py(总路由)不再做路由与视图函数的匹配关系(视图分发),而是做路由的分发

路由的分发要用到一个模块:
from django.conf.urls import include

# 路由分发,注意路由分发的总路由千万不要规定$结尾
# 写法一:
from app01 import urls as app01_urls
from app02 import urls as app02_urls  # 防止导入名字重复故取别名
url(r'^app01/', include(app01_urls)),
url(r'^app02/', include(app02_urls))
# 写法二:无需导入,直接在引号内写上 应用名.urls
url(r'^app01/', include('app01.urls')),
url(r'^app02/', include('app02.urls)')

# 在APP应用下新建urls.py文件,在该文件内写路由与视图函数的对应关系即可
from django.conf.urls import url
from app01 import views
urlpatterns = [
    url(r'^index/', views.index)
]

名称空间(了解)

url(r'^app01/',include(app01_urls,namespace='app01')),
url(r'^app02/',include(app02_urls,namespace='app02'))

# app01.urls.py:
from django.conf.urls import url
from app01 import views
urlpatterns = [
    url(r'^index/',views.index,name='index')
]
	
# app02.urls.py
from django.conf.urls import url
from app02 import views
urlpatterns = [
    url(r'^index/',views.index,name='index')
]
	
# app01.views.py
reverse('app01:index')
	
# app02.views.py
reverse('app02:index')

伪静态网页

# 针对百度搜索的优化seo
url(r'^index.html', views.index, name="app01_index")

虚拟环境

应用场景:不同的项目需要配置不同的python解释器

django1.0 与 django2.0之间的区别

django 2.0 里面的path第一个参数不支持正则,写什么就匹配什么,100%精准匹配
django 2.0 里面的re_path对应着django 1.0里面的url

虽然django 2.0 里面的path不支持正则表达式,但是他提供 5个默认的转换器
str,匹配除了路径分隔符(/)之外的非空字符串,这是默认的形式
int,匹配正整数,包含0。
slug,匹配字母、数字以及横杠、下划线组成的字符串。
uuid,匹配格式化的uuid,如 075194d3-6885-417e-a8a8-6c931e272f00。
path,匹配任何非空字符串,包含了路径分隔符(/)(不能用?)

自定义转换器

自定义转换器:
1、正则表达式
2、类
3、注册

# 自定义转换器
class FourDigitYearConverter:
	regex = '[0-9]{4}'
    def to_python(self, value):
    	return int(value)
    def to_url(self, value):
    	return '%04d' % value  # 占四位,不够用0填满,超了则就按超了的位数来!
register_converter(FourDigitYearConverter, 'yyyy')
PS:路由匹配到的数据默认都是字符串形式

FBV与CBV

FBV:function base views

CBV:function base views

CBV

url(r'^mycls/',views.MyCls.as_view())
	
class MyCls(View):
    def get(self,request):
    	return render(request,'index.html')
    def post(self,request):
    	return HttpResponse('post')
    
# 无论是FBV还是CBV,路由层都是路由对应视图函数内存地址
urlpatterns = [
    urlpatterns = [
		# url(r'^mycls/',views.view)
		url(r'^mycls/',views.MyCls.as_view())
	]
	
class MyCls(View):
    def get(self,request):
    	return render(request,'index.html')
    def post(self,request):
    	return HttpResponse('post')

JsonResponse

# 与三板斧同层
from django.http import render,HttpResponse, redirect
from django.http import JsonResponse

def index(request):
    # res = {'name':'jason大帅比','password':'123'}
    # return HttpResponse(json.dumps(res))
    return JsonResponse({'name':'jason大帅比', 'password':'123'},json_dumps.params={'ensure_ascii':False})

request.path | request.fullpath

print('path:',request.path)
print('full_path:',request.get_full_path())

path: /upload_file/
full_path: /upload_file/?name=jason

简单的文件上传

使用form表单中的file类型

注意点:
	1、mothod需要制定为post
	2、enctype需要改为formdata格式
	
后端暂时需要注意的是:
	1、配置文件中注释掉csrfmiddleware中间键
	2、通过request.FILES获取用户上传的post文件数据
    
file_obj = request.FILES.get('my_file')  # 这里的my_file为form-file中的name属性的值
print(file_obj.name)
with open(file_obj_name,'wb') as f:
    for line in file_obj.chunks():
        f.write(line)
posted @ 2019-06-10 21:40  输诚  阅读(129)  评论(0编辑  收藏  举报