03.Django反向解析路由分发

1. 请求生命周期图

image-20220304171121932

2. 项目准备

2.1 新建项目

image-20220304171539569

2.2 路径拼接问题
* 修改templates路径拼接问题

image-20220304171723491

2.3 路由层
在urls.py路由层中创建两个路由 test1, test11.
* 不要在路由后面加/
from django.conf.urls import url
from django.contrib import admin
# 0. 导入 app 应用下的 视图层
from app01 import views


urlpatterns = [
    url(r'^admin/', admin.site.urls),
    # 自定义路由
    # 1. test1 
    url(r'test1', views.test1),
    # 2. test11
    url(r'test11', views.test11)
]

2.4 视图层
在app01  views.py中创建test1, test11 两个视图函数.
# 1. 创建test1视图函数
def test1(request):
    # 返回 字符信息
    return HttpResponse('test1')


# 2. 创建test11视图函数
def test11(request):
    # 返回 字符信息
    return HttpResponse('test11')

3.路由层介绍

3.1匹配路由
正则匹配:
所有的路由都写在一个列表中,for循环遍历列表,依次匹配url函数的第一个参数,
url函数第一个参数是正则表达式,只要第一个参数正则表达式能够匹配到内容,
那么就会立刻停止往下匹配,直接执行对应的视图函数.
0. 启动程序
1. 在浏览器中输入url地址: 127.0.0.1:8000/test1
2. 在浏览器中输入url地址: 127.0.0.1:8000/test11

image-20220304174530401

3. 后端收到的请求是 test1  test11 
4. 浏览器收到的返回信息 两次都是 test1.

匹配中: test11符合了test1匹配条件

image-20220304200616724

3.2 重定向
重定向 --> 单斜杠/
* 重定向的方法解决前面的匹配模糊问题.
路由中为test1,test11加上/.
# urls.py
urlpatterns = [
    url(r'^admin/', admin.site.urls),
    # 自定义路由
    # 1. test1 
    url(r'test1/', views.test1),
    # 2. test11
    url(r'test11/', views.test11)
]
0. 启动程序
1. 在浏览器中输入url地址: 127.0.0.1:8000/test1
2. 在浏览器中输入url地址: 127.0.0.1:8000/test11
3. 后端收到的请求是 test1  test11 
4. 浏览器收到的返回信息  test1  test11 
* 输入的时候并没有在最后面写/,可以看到url中自动加上了一个.Django的功能.

image-20220304192002669

# 6. 在settings.py配置文件中设置 取消自定加斜杠 (在文件末尾加就可以了)
APPEND_SLASH = False  # 默认True
7. 在浏览器中输入url地址: 127.0.0.1:8000/test1
8. 路由中匹配不到

image-20220304193839325

image-20220304200916491

9.  删除取消加斜杆的代码
10. 在浏览器中输入url地址: 127.0.0.1:8000/test1

image-20220304194454802

这个时候Django在帮在test1后加一个/斜杆,做一个重定向.
再发送请求,第二次匹配到了,返回结果.
3.3限制开头
正则表达式符号 ^ 以什么开头.
0. 在浏览器中输入url地址: 127.0.0.1:8000/123test1
1. 正常访问test1.
* 123test1地址能被正则表达式'test1/'匹配到

image-20220304201640667

2. 设置路由的正则匹配^test1/,加上 上尖号,表示以test1开头.
    # urls.py
    url(r'^test1/', views.test),
3. 在浏览器中输入url地址: 127.0.0.1:8000/123test1
4. 404 访问的资源不存在

image-20220304202030834

5. 在浏览器中输入url地址: 127.0.0.1:8000/test1

image-20220304202223545

3.4 限制结尾
正则表达式符号 $ 以什么结尾.
0. 在浏览器中输入url地址: 127.0.0.1:8000/test1/hello
1. 正常访问test1.
* test1/hello地址能被正则表达式'^test1/'匹配到

image-20220304202752582

2.设置路由的正则匹配^test1/$,加$号,表示以test1结尾.(^$ 的组合以什么开头以什么结尾.)

image-20220304203052862

3. 在浏览器中输入url地址: 127.0.0.1:8000/test1/

image-20220304203254807

3.5 设置主页
 127.0.0.127:8000 设置一个主页.

127.0.0.127:8000 后面没有地址了就是 .
0. urls.py 添加路由关系.
1. views.py 中返回一个home页面(不演示html的页面了).
	# app01/views.py
    # 3. 设置主页 地址为 ''
    url(r'', views.home)
# 3. 创建主页的视图函数
def home(request):
    # 返回 主页
    return HttpResponse('home主页')

image-20220304205148739

2. 在浏览器中输入url地址: 127.0.0.1:8000
3. 在浏览器中输入url地址: 127.0.0.1:8000/123
4. 在浏览器中输入url地址: 127.0.0.1:8000/abc
* 如果是 '' 空字符串的话 其他不存路由都可以访问 (没法用正则去演示)
* ^$ 的组合以什么开头以什么结尾.
	# app01/views.py
    # 3. 设置主页 地址为 '^$' 以空开头,空结尾
    url(r'^$', views.home),
5. 在浏览器中输入url地址: 127.0.0.1:8000
6. 在浏览器中输入url地址: 127.0.0.1:8000/123
7. 在浏览器中输入url地址: 127.0.0.1:8000/abc
8. 只能是127.0.0.1:8000可以访问, 它的地址都无法访问了.

在这里插入图片描述

3.6 设置尾页
每次返回的资源不存在都显示404.
可以在后端判断,如果访问的资源不存在,返回一个好看的页面,而不是一堆报错代码.
也可以返回一个主页.

4.分组

正则表达式加上括号就是分组.
分组的作用: 匹配路由中符合要求的数据,作为参数,
传递给自己对应的视图函数,视图函数中使用形参接收.


/路径/(匹配子路径的正则表达式)/(匹配子路径的正则表达式)/
输入url的时候需要考虑完整的路径
4.1 无名分组
无名分组: 匹配的数据以位置参数进行传递.
0. 在路由中写正则表达式
1. 在浏览器中输入url地址: 127.0.0.1:8000/1234
2. 2. 报错,路由提供了一个位置参数需要接收.
    # urls.py
    # 1. test1 正则表达式 ([0-9]{4}) 匹配四位0-9的任意组合.
    url(r'test1/([0-9]{4})', views.test1),

image-20220304225824254

3. 用一个形参接收值,并打印.
# 1. 创建test1视图函数  接收参数
def test1(request, str_4):
    # 打印参数
    print(str_4)
    # 返回 字符信息
    return HttpResponse('test1')
4. 在浏览器中输入url地址: 127.0.0.1:8000/1234

image-20220304230237349

5. 输入url的时候需要考虑完整的路径
url缺失子路径就无法匹配.

image-20220305013155769

4.2 有名分组
无名分组: 匹配的数据以关键字参数进行传递.
正则表达式分组后可以起一个别名.
(?P<别名>正则表达式)  --> 大写的P
0. 在路由中写正则表达式
1. 在浏览器中输入url地址: 127.0.0.1:8000/1234
2. 报错,路由提供了一个关键字参数需要接收.
    # urls.py
    # 1. text1 正则表达式 ([0-9]{4}) 匹配四位0-9的任意组合.
    url(r'test1/(?p<res>[0-9]{4})', views.test1),

image-20220304231507991

3. 用一个关键字接收值,并打印.

image-20220304231822474

4.3 分组注意事项
1.一个类型的分组可以在一个路由中使用多个.
2.不同类型分组不能混用使用.(获取使用会丢失无名分组的值)
1.使用多次
    # urls.py
    # 1. test1 正则表达式 \d+ 数子类型 一个或长度多个
    url(r'test1/(\d+)/(\d+)/(\d+)', views.test1),
# 1. 创建test1视图函数  *接收所有位置参数
def test1(request, *args):
    # 打印参数
    print(*args)
    # 返回 字符信息
    return HttpResponse('test1')

image-20220304232717039

    # urls.py
    # 1. test1 正则表达式 \d+ 数子类型 一个或长度多个
    url(r'test1/(?P<int_1>\d+)/(?P<int_2>\d+)/(?P<int_3>\d+)', views.test1),
# 1. 创建test1视图函数  ** 接收所有关键字参数
def test1(request, *args):
    # 打印参数
    print(*args, kwargs)
    # 返回 字符信息
    return HttpResponse('test1')

image-20220304233531685

2.混用
    # urls.py
    # 1. test1 正则表达式 \d+ 数子类型 一个或长度多个
     url(r'^test1/(\d+)/(?P<year>\d+)/', views.test1),

image-20220304234201515

5. 反向解析

给根径起别名和对子路径分组,
后端可以通过别名取到根路径的名字,通过位置或关键字参数拿到子路径.
前端可以通过模板语法获取根路径的名字.
5.1 测试环境与需求
0.路由
1.视图函数
2.前端页面
    # urls.py
    # 1. test1 
     url(r'^test1/', views.test1),
# 1. 创建test1视图函数  
def test1(request):
    # 返回 test1 页面
    return render(request, 'test1.html')
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>test1页面</title>
</head>
<body>
    <h1>测试页面</h1>
    <a href="/test1/">111</a>
</body>
</html>

image-20220304235813729

需求: 可以随便的修改test1的名称.
5.2 起别名
url('路径', 视图函数, name='路径别名')
name参数为路径别名
    # urls.py
    # 1. test1 
     url(r'^test1/', views.test1, name='hello'),
5.3 前端反向解析
前端页面通过模板语法获取路由路径的别名.
<!--修改前端页面的a标签-->
<a href="{% url  'hello' %}">test1测试页面</a>
<p>{% url  'hello' %}</p>
前面的路径怎么改名字,使用的都是同一个别名,后端一直获取的是它的别名,
在通过别名获取,真正的路径名字.
将test1改为:as、 dsa、 asas、 点a标签的时候,都会跳转到当前的路径.

image-20220305004217976

5.4 后端反向解析
后端使用反向解析需要导入reverse模块.
from django.shortcuts import  reverse
# views.py
from django.shortcuts import reverse
# 1. 创建test1视图函数
def test1(request):
    print(reverse('hello'))
    # 返回 字符信息
    return render(request, 'test1.html')

image-20220305003911594

5.5 无名分组反向解析
0. 在路径后面添加一个无名分组.  r'^test1/([0-9]{4})'
1. 视图函数接收位置参数
2. 浏览器输入 127.0.0.1:8000/test1/1234
    # urls.py
    # 1. test1 
     url(r'^test1/([0-9]{4})', views.test1, name='hello'),
# 1. 创建test1视图函数 接收无名分组的参数
def test1(request, str_4):
    # 打印路径
    print(str_4)
    print(reverse('hello'))
    # 返回 字符信息
    return render(request, 'test1.html')

image-20220305011445676

/根路径/子路径/../

name  只能为根路径起别名.
在反向解析的时候只能拿到根路径的信息,少了子路径的参数.就停止反向解析,报错.
需要提供一个符合要求的子路径正则表达式的参数,合成一个完整的路径.
才能拿到完整的路径信息.

* 分组是的值是直接能拿到的,反向解析后面的子路径可以直接拿分组的值.
reverse 函数有一个 args参数可以传值给后面的子路径.
args = (子路径, ...)  元组

在args写上子路径正则表达式能匹配的值.
# 1. 创建test1视图函数 接收无名分组的参数
def test1(request, str_4):
    # 打印路径
    print(str_4)  # ([0-9]{4} 能匹配的值
    print(reverse('hello', args=(1111, )))
    # 返回 字符信息
    return render(request, 'test1.html')

image-20220305020429390

前端 反向解析也需要 一个符合子路径正则表达式的值,才能去解析.
直接写在 别名后面,只要能满足([0-9]{4})的值就行.
<!--修改前端页面的a标签-->
<a href="{% url  'hello' 1234 %}">test1测试页面</a>
<p>{% url  'hello' 1234 %}</p>

image-20220305022146182

# 1. 创建test1视图函数 接收无名分组的参数
def test1(request, str_4):
    # 打印路径
    print(str_4)  # ([0-9]{4} 能匹配的值
    print(reverse('hello', args=(1111, )))
    # 返回 字符信息                         str_4
    return render(request, 'test1.html', locals())
    <!--前端页面-->
    <h1>测试页面</h1>
	<!--通过模板语法取 子路径的数据-->
    <a href="{% url  'hello' str_4 %}">test1测试页面</a>
    <p>{% url  'hello' str_4 %}</p>

image-20220305022516232

5.6 有名分组反向解析
0. 在路径后面添加一个无名分组.  r'^test1/(?P<str_4>[0-9]{4})'
1. 视图函数接收位置参数
2. 浏览器输入 127.0.0.1:8000/test1/1234
    # urls.py
    # 1. test1 
     url(r'^test1/(?P<str_4>[0-9]{4})', views.test1, name='hello'),
# 1. 创建test1视图函数 接收无名分组的参数
def test1(request, str_4):
    # 打印路径
    print(str_4)
    print(reverse('hello'))
    # 返回 字符信息
    return render(request, 'test1.html', locals())
    <!--前端页面-->    
    <h1>测试页面</h1>
	<!--通过模板语法取 子路径的数据-->
    <a href="{% url  'hello' str_4=1111 %}">test1测试页面</a>
    <p>{% url  'hello' str_4 %}</p>

image-20220305134755650

前端需要为有名分组提供一个可匹配的参数,现在后端传了子路径给前端,前端使用模板语法取到子路径.
在将子路径作为参数,取根路径.
视图函数中将locals() 删除.不提供子路径参数给前端,前端就需要自己提个一个符合条件的参数.
# 1. 创建test1视图函数 接收无名分组的参数
def test1(request, str_4):
    # 打印路径
    print(str_4)
    print(reverse('hello'))
    # 返回 字符信息
    return render(request, 'test1.html')

在这里插入图片描述

6. 路由分发

Django每一个应用都可以有自己的templates文件夹, url.py, static文件夹.
基于上述的特点,django能够非常好的做到分组开发(每个人开发自己的app应用).

单独开发完成后,把多个app应用全部拷贝到一个Django项目中.
然后去配置文件中注册应用,利用路由分发的特点所有的app整合起来.
当一个Django项目中url特别多的时候,总路由urls.py代码非常冗余不好维护,
利用路由分发来减轻总路由的压力.
路由层主要写路径与视图函数的对应关系.
路由分发:将总路由拆分多个子路由,
路由不再干路由与视图的直接对应关系,而是做一个分发处理,
识别当前路径是那个app下的,直接发给对应的app应用去处理.
* url 中要携带app应用的名字,不然区分不了.

image-20220305143423574

6.1 创建多个app
* 测试就建一个就好了
0. python manage.py startapp app02  
1. 创建好之后在settings中注册
2. 在app应用下创建 url 路由层.

6.2 子路由
* 前面的正则匹配不能 加$ 结尾符
设置后过不了正则匹配这关,后面的路由分发没机会执行.

image-20220305152018330

app01应用下的路由层 视图层
# app01下的urls.py
from django.conf.urls import url
from app01 import views

urlpatterns = [
    # 注册
    url(r'reg/', views.reg)
]
# app01下的views.py
from django.shortcuts import render, HttpResponse

def reg(request):
    return HttpResponse('app01的注册页面')
app02 应用下的路由层 视图层
# app02下的urls.py
from django.conf.urls import url
from app02 import views
urlpatterns = [
    url(r'reg/', views.reg)
]
# app02下的views.py
from django.shortcuts import render, HttpResponse

def reg(request):
    # 注册
    return HttpResponse('app02的注册页面')

image-20220305142255545

6.3 总路由
0. 总路由分中导入一个include函数.
1. 导入app应用的路由模块&给子路由起别名
2. 总路由区分访问app应用,交给对应的子路由去处理.
url('^app01/', include(app01_urls)),
      根路径    include(子路由) 
用户输入的地址被正则匹配到了,再将用户输入的路径给include()函数传给子路由去继续匹配.
方式一: 导入子路由,在include函数中写对应的子路由.
# 0.导入 路由分发函数
from django.conf.urls import url, include
from django.contrib import admin

# 1.导入 子路由
from app01 import urls as app01_urls
from app02 import urls as app02_urls

urlpatterns = [  # 在include函数中写上要去的子路由
    url('^app01/', include(app01_urls)),
    url('^app02/', include(app02_urls)),
]
浏览器中输入:127.0.0.1/app01/reg
浏览器中输入:127.0.0.1/app02/reg
访问各自app的独自页面

image-20220305152639781

方式二: 不导入子路由,在include()函数中只要.的方式去获取子路由.
# 0.导入 路由分发函数()
from django.conf.urls import url, include
from django.contrib import admin

urlpatterns = [
    url(r'^admin/', admin.site.urls),
	# 通过点的方式直接拿拿到子路由
    url(r'^app01/', include('app01.urls')),
    url(r'^app02/', include('app02.urls')),
]
浏览器中输入:127.0.0.1/app01/reg
浏览器中输入:127.0.0.1/app02/reg
访问各自app的独自页面

image-20220305152802250

7.名称空间

7.1 别名问题
多个子路由使用同一个名称空间,在起别名的时候会有冲突.
# 在app01/02下urls.py中分别起别名为hello
urlpatterns = [
    url(r'^reg/', views.reg, name='hello')
]
# app01下的views.py
from django.shortcuts import HttpResponse
# 导入 reverse 函数
from django.shortcuts import reverse

# 注册
def reg(request):
    print('app1>>>:', reverse('hello'))
    return HttpResponse('app01下的注册页面')
# app02下的views.py
from django.shortcuts import HttpResponse
# 导入 reverse 函数
from django.shortcuts import reverse

# 注册
def reg(request):
    print('app2>>>:', reverse('hello'))
    return HttpResponse('app02下的注册页面')

image-20220305161222064

7.2 设置名称空间
在路由分发中设置namespace参数.设置名称空间.
0.总路由中使用 在include()函数中 为子路由声明一个名称空间.
# 总路由 urls.py 中 设置子路由的名称空间
urlpatterns = [  # 通过点的方式直接拿拿到子路由
    url('^app01/', include('app01.urls', namespace='app01')),
    url('^app02/', include('app02.urls', namespace='app02')),
]
子路由中不需要更改.
7.3 后端反向解析
视图函数中反向解析的格式 reverse('名称空间的名字:别名')
#在app01下views.py中重新添加反向解析
from django.shortcuts import HttpResponse
# 导入 reverse 函数
from django.shortcuts import reverse


# 注册
def reg(request):
    print('app1>>>:', reverse('app01:hello'))
    return HttpResponse('app02下的注册页面')
# 在app02下views.py中重新添加反向解析
from django.shortcuts import HttpResponse
# 导入 reverse 函数
from django.shortcuts import reverse


# 注册
def reg(request):
    print('app2>>>:', reverse('app01:hello'))
    return HttpResponse('app02下的注册页面')

image-20220305165555993

7.4 前端反向解析
前端使用模板语法反向解析 
<{% url ''名称空间的名字:别名' %}">
分别在app01/02下创建创建templates文件夹,
在分别创建app01/02_reg.html页面.
<!-- app01设置一个主页reg.html.-->
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>aap02-reg</title>
</head>
<body>
    <p>{% url 'app01:hello' %}</p>
    <p>{% url 'app02:hello' %}</p>
</body>
</html>
<!-- app02设置一个主页reg.html.-->
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>aap02-reg</title>
</head>
<body>
     <p>{% url 'app01:hello' %}</p>
     <p>{% url 'app02:hello' %}</p>
</body>
</html>
#在app01下views.py中重新添加反向解析
from django.shortcuts import render
# 导入 reverse 函数
from django.shortcuts import reverse


# 注册
def reg(request):
    print('app1>>>:', reverse('app01:hello'))
    return render(request, 'reg.html')
#在app02下views.py中重新添加反向解析
from django.shortcuts import render
# 导入 reverse 函数
from django.shortcuts import render
from django.shortcuts import reverse


# 注册
def reg(request):
    print('app1>>>:', reverse('app01:hello'))
    return render(request, 'reg.html')
分别返回自己reg页面.设置的时候名字重复一样,
第二个应用放回的也是第一个应用的页面.

image-20220305180908566

返回的页面不要起一样的名字.

两个应用的 templates 下的文件改为:
reg.html -->   app1_reg.html
reg.html -->   app2_reg.html

视图中分别改为:
app1_reg.html
app2_reg.html

image-20220305181818349

7.5 统一解决方式
一般情况下,有多个APP的时候在起别名的时候加上app的前缀,
这样的话就能保证多个app之间的名字不冲突.

8. 伪静态

静态网页:数据写死的了.伪静态网页:将动态网页伪装成静态网页.
* .html 后缀的页面被优先展示

伪装的目的增加本网站上seo查询力度,并且增加搜索引擎收藏本网站的概率.
搜索引擎本质就是一个巨大的爬虫程序.搜索引擎发现这个网站是一个静态页面,
会认为这个页面时不会修改了的,浏览器会优先收藏,在搜索是自己的文档会优先被浏览器展示,
 百度 xxx 
第一个就是你的信息
(刚不过人民币玩家-)
# app01 的路由层中设置
urlpatterns = [
    # 在路径后面加上 .html
    url(r'^reg.html', views.reg, name='reg'),
]
路由中添加 .html , 
访问也要加上 .html 

image-20220305183019812

9. 虚拟化环境

在程序开发中给每一个项目配置一个独有的解释器环境,环境内的模块缺什么安装什么.用不上的一概不装.
Pychrm虚拟环境:虚拟一个纯净的python解释器.	
虚拟环境不要创建太多,需要消耗硬盘空间的拓展:
每一个项目都需要很多的模块,并且每一个模块版本还可能不一样,	
开发当中会为项目配置一个requirements.txt文件里面书写了所有的模块和版本,
只需要输入一条命令就可以一键安装所有的模块和版本.
9.1 创建虚拟环境

image-20210813161343070

创建需要一些时间,会生成一个venv的文件夹.

image-20210813161537384

项目默认只有两个模块.

image-20210813161849621

10.Django版本区别

Django版本 1.x2.x3.x
django1.x路由使用的是url方法而在django2.x和3.x中路由层使用的是path方法.
url()第一个参数支持正则表达式path()第一个参数不支持正则表达式,写什么就是什么.

如果不习惯使用path ,可以导入re_path模块,支持正则表达式.
from django.urls import re_path
re_path(r'^xxx',xxx), re_path等价于url.

虽然path不支持正则,
但它支持五种转换器以及自定转换器.path('index/<int:id>/')将第二个路由里面的内容转换为整型,
以关键字的形式传递给后面的视图函数.

模型层中1.x外键默认都是级联更新级联删除的,
但是到了2.x和3.x中需要自己手动写配置参数.

11. 视图层

视图层三板斧
HttpResponse: 返回字符串类型
render:       返回HTML页面,并在返回浏览器前还能给HTML文件传值
redirect:     重定向

研究三者源码可得结论:视图函数必须要返回一个HttpResponse.
三者都继承了同一个类.   
定一个视图为直接写pass,运行后代码报错,未返回HttpResponse对象.
The view app01.views.index didn't return an HttpResponse object. It returned None instead.

image-20220305202434409

12.JsonResponse

* json格式:前后端数据交互,需要使用json作为过渡,实现跨语言传输数据.
JsonResponse模块 
    0.将数据转为json格式字符串
    1.调用HttpResponse返回json格式字符串
后端给前端浏览器返回一个json格式的字符串.
方式1
	使用json模块,将数据转为json格式字符串.
	HttpResponse返回一个json格式的字符串.
方式2
	JsonResponse模块返回一个json格式的字符串.
12.1 手动序列化
# 注册
def reg(request):
    print('app1>>>:', reverse('app01:hello'))
    # 导入 json模块字符串
    import json
    info = {'姓名': 'kid', '年龄': 18}

    # 序列化
    info_json = json.dumps(info)

    return render(request, 'app01_reg.html', locals())

image-20220305205634459

127.0.0.1:8000/app01/reg.html

{"\u59d3\u540d": "kid", "\u5e74\u9f84": 18}
12.2 中文序列化问题
json.dumps()序列化中文的时候会编码成ascii 
设置 ensure_ascii=False 不转码.
    info_json = json.dumps(info, ensure_ascii=False)
127.0.0.1:8000/app02/reg.html

{'姓名': 'kid', '年龄': 18}

image-20220305210138560

12.3 自动序列化
# 导入模块
from django.http import JsonResponse
# 注册
def reg(request):
    print('app1>>>:', reverse('app01:hello'))
    info = {'姓名': 'kid', '年龄': 18}
    return JsonResponse(info)

image-20220305210542478

12.4 中文序列化问题
查看源码JsonResponse内部还是继承了HttpResponse类
,内部也是通过json.dumps() 转码的,修改参数json_dumps_params.
JsonResponse( 数据, json_dumps_params={'ensure_ascii': False})

image-20220305211146259

  return JsonResponse(info, json_dumps_params={'ensure_ascii': False})

image-20220305211350160

14.2 传非字典数据
# 导入模块
from django.http import JsonResponse

# 注册
def reg(request):    
    user_list = ['kid',  18,]    
    return JsonResponse(user_list, json_dumps_params={'ensure_ascii': False})

image-20220305211808049

In order to allow non-dict objects to be serialized set the safe parameter to False.
由于 EcmaScript 5 之前的安全漏洞,只允许传递 dict 对象
为了允许序列化非dict对象,请将safe参数设置为False.
设置safe参数值为False.
return JsonResponse(info, json_dumps_params={'ensure_ascii': False}, safe=False)
["kid", 18, "男"]

image-20220305211941894

13. form表单上传文件

form表单上传文件类型的数据的需要设置的属性
1. method="post"                  必须是post请求
2. enctype="multipart/form-data"  编码方式是表单数据
request.FILES 获取文件信息

文件对象:
obj = request.FILES.get('input name属性的值') 获取文件对象

obj.name 获取文件的名字


将对象写到本地.
with open('文件名', 'wb') as wf:
    for i in 对象:
    	wf.write(i)
0. 在总路由写一个对应关系(直接对应视图函数不走子路由)
1. 在视图函数返回一个html页面
2. 在页面中一以POST方式提交文件
3. 在视图函数中获取文件
# 应用下的 urls.py 路由层

from app01 import views

urlpatterns = [
    url('^file/', views.file)
]
# app01 下的视图函数
# 获取form表单数据
def file(request):
    # 获取请求方式
    print(f'请求方式:{request.method}')

    # 判断请求方式
    if request.method == 'POST':

        # 查看POST请求 的文件数据 --> 字典
        print(request.FILES)

        # FILES.set 取数据
        img_obj = (request.FILES.get('file'))

        print(img_obj, type(img_obj))

    return render(request, 'file.html')
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>form表单提交文件</title>
</head>
<body>
    <div>
        <form action="" method="post" enctype="multipart/form-data">
            <input type="file" name='file'>
            <input type="submit">
        </form>
    </div>
</body>
</html>

image-20220305214654556

4. 浏览器中输入 127.0.0.1:8000/file
5. 页面中选择文件提交

image-20220305215146918

6. CSRF 中间件报错 先将其关闭

image-20220305215227054

7. 注释掉settings中的47
MIDDLEWARE = [    
    #'django.middleware.csrf.CsrfViewMiddleware'    
]  

image-20220305215427892

8. 再次提交文件

image-20220305222453648

9. 将文件保存下来
# 获取form表单数据
def file(request):
    # 获取请求方式
    print(f'请求方式:{request.method}')

    # 判断请求方式
    if request.method == 'POST':

        # 查看POST请求 的文件数据 --> 字典
        print(request.FILES)

        # get方法 取数据对象
        img_obj = (request.FILES.get('file'))
		
        
        # 接收文件  对象.name 获取文件的名字
        with open(img_obj.name, mode='wb') as rf:
            for i in img_obj:
                rf.write(i)

        
    return render(request, 'file.html')

image-20220305233417493

正常来说 with open()建的文件,没有指定路径的情况下,是在执行文件的目录下产生.
现在被移到项目目录下了.
修改 视图函数 当我们访问file 就创建文件
这个文件就出现在项目目录下.
# 获取form表单数据
def file(request):

    import os
    print(os.path.dirname(__file__))  # ...Project\django3\app01

    with open('a.txt', mode='wt',encoding='utf8') as rf:
        rf.write('123')
    return render(request, 'file.html')

image-20220306000926780

14. request补充

request.body           原生浏览器发送过来的二进制数据.
request.path           获取路由 
request.path_info      获取路由 
request.get_full_path  获取路由加路?后面的参数

* request.path  request.path_info  一样的
0. 修改前面的程序用于测试.
# app01下的views.py
# 获取form表单数据    
def file(request):
    # 获取请求方式
    print(f'请求方式:{request.method}')
    print(request.body)

    return render(request, 'file.html')

image-20220306002905361

# app01下的views.py
def file(request): 
    print(request.path) 
    print(request.path_info) 
    print(request.get_full_path()) 
    return HttpResponse('text')

image-20220306001838553

1. 在浏览器中输入:127.0.0.1:8000/file

image-20220306002041610

2. 在浏览器中输入:127.0.0.1:8000/file/123/456

image-20220306002251851

3. 在浏览器中输入:127.0.0.1:8000/file/?name=123

image-20220306002428412

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值