一、视图介绍和项目准备
二、URLconf
浏览者通过在浏览器的地址栏输入网址请求网站
对于Django开发的网站,有哪一个视图进行处理请求,是由url匹配找到的,配置流程如下:
2.1 settings.py中
指定url配置:ROOT_URLCONF= ‘项目.urls’
2.2 项目urls.py
匹配成功后,包含到应用的urls.py:path(‘’,include(‘应用.urls’))
2.3 应用 urls.py
path(‘’,views.函数名)
2.4 提示
- 如果使用正则匹配,推荐r’',不转义
- 不能在开始加反斜杠(path(‘/path’)),推荐在结束加反斜杠(path(‘path/’))
- 请求的url被看做是一个普通的python字符串,进行匹配时不包括域名、get和post参数,如请求地址:http://127.0.0.1:8000/18/?a=10,去掉域名和参数部分后,只剩下 18/ 进行正则匹配
三、路由命名与reverse反解析
3.1 路由命名
from django.urls import path
from book.views import index
urlpatterns = [
# name就是url的名字,可以通过name找到这个路由
path('index/', index, name='home'),
]
3.2 reverse反解析,根据名字动态找路由
from django.http import HttpResponse
from django.shortcuts import render, redirect, reverse
from book.models import BookInfo, PeopleInfo
# Create your views here.
def index(request):
"""
登录成功、注册成功等都需要跳转到首页
1、不使用路由名字时的跳转页面
return redirect('/index/')
2、使用路由名字时的跳转页面,路由是动态获取
path = reverse('index')
return redirect(path)
"""
3.3 namespace 应用命名空间
3.3.1 项目urls中定义namespace
from django.contrib import admin
from django.urls import path, include
from book.views import index
urlpatterns = [
path('admin/', admin.site.urls),
# 在include中添加第二参数 namespace,这样原来路由的name就变成了 namespace:name, 如 book:home
# namespace习惯上使用子应用的名字,容易识别还不会重名
path('', include('book.urls', namespace='book')),
]
3.3.2 book应用urls中定义app_name
from django.urls import path
from book.views import index
app_name = 'book'
urlpatterns = [
# name就是url的名字,可以通过name找到这个路由
path('index/', index, name='home'),
]
3.3.3 应用Views中使用namespace:name反解析
from django.shortcuts import render, redirect, reverse
from book.models import BookInfo, PeopleInfo
# Create your views here.
def index(request):
"""
登录成功、注册成功等都需要跳转到首页
1、不使用路由名字时的跳转页面
return redirect('/index/')
2、使用路由名字时的跳转页面,路由是动态获取
path = reverse('home')
return redirect(path)
3、如果设置了namespace就需要通过namespace:name来获取路由
path = reverse('book:home')
return redirect(path)
"""
四、使用PostMan对请求进行测试
PostMan是一款功能强大的网页调试与发送网页HTTP请求的Chrome插件,可以直接去对我们写出来的路由和视图函数进行调试,是后端程序员必须会用的一个工具。
4.1 安装方式
4.1.1 Chrome商店直接搜索PostMan扩展程序进行安装
4.1.2 官网下载桌面版https://www.postman.com/downloads/
安装
注册免费账号,
保存账号密码,省得每次都得输入
4.1.3 将已下载好的PostMan插件文件夹拖入Chrome浏览器
4.2 使用方法
五、HttpRequest对象
利用HTTP协议向服务器传参有四种途径:
- 提取URL的特定部分如/weather/beijing/2018,可以在服务器端的路由中用正则表达式截取;
- 查询字符串( query string),形如key1=alue&key=value2;
- 请求体(body)中发送的数据,比如表单数据、json、xml等
- 在http报文的头(header)中
5.1 URL路径参数
- 如果想从URL中获取值,需要在正则表达式中使用分组
- 获取值分为两种方式
– 位置参数:参数的位置不能错
–关键字参数:参数的位置可以变,跟关键字保持一致即可 - 注意:两种参数的方式不要混合使用,在一个正则表达式中只能使用一种参数方式
- 分别使用以上两种获取URL值的方式提取出18 188
5.1.1 位置参数
正则分组匹配所有整数数字 (\d+)
from django.urls import path
from book.views import index, detail
from django.conf.urls import url
app_name = 'book'
urlpatterns = [
# name就是url的名字,可以通过name找到这个路由
path('index/', index, name='home'),
# http://127.0.0.1:8000/category_id/book_id
# 根据位置来获取url中传递的参数
url(r'^(\d+)/(\d+)/$', detail),
]
5.1.2 关键字参数
利用正则别名(?P\d+)传递关键字,推荐使用,不用考虑位置问题,只要关键字对应就行。
实际项目路由都是关键字参数
from django.urls import path
from book.views import index, detail1, detail2
from django.conf.urls import url
app_name = 'book'
urlpatterns = [
# name就是url的名字,可以通过name找到这个路由
path('index/', index, name='home'),
# http://127.0.0.1:8000/category_id/book_id
# 根据位置来获取url中传递的参数
url(r'^(\d+)/(\d+)/$', detail1),
# 关键字传递参数,推荐使用
url(r'^(?P<category_id>\d+)/(?P<book_id>\d+)/$', detail2),
]
# 关键字传递参数,函数接收关键字
def detail2(request, categeory_id, book_id):
print(categeory_id, book_id)
return HttpResponse('detail')
5.2 查询字符串
获取请求路径中的查询字符串参数(形如?1=v1&k2=v2),可以通过 requestget属性获取,返回QueryDict对象。
注意:查询字符串不区分请求方式,即假使客户端进行POST方式的请求,依然可以通过 request GET获取请求中的查询字符串数据。
PostMan模拟
5.2.1查询关键字通过 request.GET 参数接收
5.2.2Django中的QueryDict对象与普通python字典的区别
HttpRequest对象的属性GET、POST都是QueryDict类型的对象
与python字典不同, QueryDict类型的对象用来处理同一个键带有多个值的情况
- 方法get:根据键获取值,get(‘key’, 默认值)
如果一个键同时拥有多个值将获取最后一个值
如果键不存在则返回None值,可以设置默认值进行后续处理 - 方法 getlist():根据键获取值,值以列表返回可以获取指定键的所有值,getlist(键,默认值)
如果键不存在则返回空列表,可以设置默认值进行后续处理
# 查询字符串
def detail3(request, categeory_id, book_id):
"""
查询字符串,以百度查询python为例
https://www.baidu.com/s?wd=python&rsv_spt=1&rsv_iqid=0x8662fdc7003bb4a1&issp=1&f=8&rsv_bp=1&rsv_idx=2&ie=utf-8&tn=49055317_10_hao_pg&rsv_enter=1&rsv_dl=ib&rsv_sug3=17&rsv_sug1=16&rsv_sug7=100
上面的url以问号作为分隔,前面是路由,https://www.baidu.com/s
问号后面是get传递的参数,称之为查询字符串,它的形式是,?key=value&key=value&key=value...
成熟系统中,用户在登录输入用户名和密码的时候,理论上,用户名和密码都应该以POST方式进行传递
现在,为了便于学习,采用get方式传递用户名和密码
get传递的用户名和密码在 request.GET 中
"""
# 前端:http://127.0.0.1:8000/2/200?user_name=zhangsan&password=123
# query_params = request.GET
# print(query_params) # <QueryDict: {'user_name': ['zhangsan'], 'password': ['123']}>
# print(type(query_params)) # <class 'django.http.request.QueryDict'>
# # 后台获取用户名密码
# user_name = query_params['user_name']
# print(user_name) # zhangsan
# password = query_params.get('password')
# print(password) # 123
"""
QueryDict 与普通python字典的区别
1、QueryDict可以获取url中的一键多值,以 key:[value1, ..., value2] 的形式存储
2、QueryDict获取的一键多值,以普通字典key的方式提取,只能提取到最后的一个值(value2),不能提取到值列表[value1, ..., value2]
3、想获取QueryDict的一键多值,需要用QueryDict的getlist方法,形如:QueryDict.getlist('user_name')
"""
# 前端:http://127.0.0.1:8000/2/200?user_name=zhangsan&password=123&user_name=lisi
query_params = request.GET
print(query_params) # <QueryDict: {'user_name': ['zhangsan', 'lisi'], 'password': ['123']}>
print(type(query_params)) # <class 'django.http.request.QueryDict'>
# 后台获取用户名密码
user_name = query_params['user_name'] # 字典key方法,只能获取一键多值的最后一个
print(user_name) # lisi
users = query_params.getlist('user_name') # QueryDict.getlist方法,可以获取一键多值的值列表
print(users) # ['zhangsan', 'lisi']
password = query_params.get('password') # QueryDict.get方法,同字典key方法
print(password) # 123
return HttpResponse('detail-3')
5.3 请求体
请求体数据格式不固定,可以是表单类型字符串,可以是JSON字符串,可以是ML字符串应区别对待,
可以发送请求体数据的请求方式有 POST、PUT、PATCH、DELETE。
Django默认开后了CSRF防护,会对上述请求方式进行CSRF防护验证,在测试时可以关闭CSRF防护机制,方法为在 settings py文件中注释掉CSRF中间件。
注意:①网址url以斜线结束。②注释掉settings中的CRSF安全设置
5.3.1 POST表单数据
# POST表单数据,
def detail4(request, categeory_id, book_id):
print(categeory_id, book_id)
"""
1、使用request.POST方法获取前端传输的数据
2、request.POST方法获取的结果为QueryDict,与request.GET获取的结果是样的
3、一键一值和一键多值的数据处理方式与GET方法完全相同
"""
data = request.POST
print(data) # <QueryDict: {'user_name': ['zhangsan', 'lisi'], 'password': ['123']}>
user_name = data['user_name']
print(user_name) # lisi
user_name = data.get('user_name')
print(user_name) # lisi
users = data.getlist('user_name')
print(users) # ['zhangsan', 'lisi']
password = data.get('password')
print(password) # 123
return HttpResponse('detail-4')
5.3.2 POST json 数据
非表单类型的请求体数据, Django无法自动解析,可以通过 request.body属性获取最原始的请求体数据,自己按照请求体格式(JSON/XML等)进行解析 request.body返 bytes回类型,然后通过decode()解码为JSON形式的字符串数据,再通过json.loads()转换为字典数据,就可使用了。
# POST JSON数据,
def detail5(request, categeory_id, book_id):
import json
print(categeory_id, book_id)
"""
1、json数据的样式,注意:①只能用双引号,不能用单引号。②最好一行数据后面不能加逗号
{
"user_name": "zhangsan",
"password": "123"
}
2、通过Ajax发送的JSON数据并没有记录在 request.POST 中,而是记录在 request.body 中
3、request.body获取到的是bytes类型数据,可以通过decode()转换为JSON形式的str类型,再通过json.loads转换为字典
4、json模块:
json.dumps,将字典转换为JSON形式的字符串
json.loads,将JSON形式的字符串转换为字典
"""
data = request.POST
print(data) # <QueryDict: {}>
body = request.body
print(body) # b'{\r\n "user_name":"zhangsan",\r\n "password":"123"\r\n}'
print(type(body)) # <class 'bytes'>
body_str = body.decode() # 对bytes数据解码,结果为str
print(body_str) # {
# "user_name": "zhangsan",
# "password": "123"
# }
print(type(body_str)) # <class 'str'>
body_dict = json.loads(body_str) # 将JSON形式的字符串转换为字典
print(body_dict) # {'user_name': 'zhangsan', 'password': '123'}
print(type(body_dict)) # <class 'dict'>
return HttpResponse('detail-5')
5.4 http报文头(header) request.META
可以通过 request.META属性获取请求头headers中的数据,request.META为字典类型。
常见的请求头如:
- CONTENT_LENGTH-The length of the request body (as a string).
- CONTENT_TYPE-The MIME type of the request body.
- HTTP ACCEPT-Acceptable content types for the response.
- HTTP_ACCEPT_ENCODING-Acceptable encodings for the response.
- HTTP_ACCEPT_LANGUAGE-Acceptable languages for the response.
- HTTP host-the http host header sent by the client
- HTTP_REFERER-The referring page, if any
- HTTP_USER_AGENT-The client’s user-agent string.
- QUERY_STRING-The query string, as a single (unparsed)string.
- REMOTE ADDR-The iP address of the client
- REMOTE HOST The hostname of the client
- REMOTE_USER-The user authenticated by the Web server, if any.
- REQUEST METHOD-A string such as "GET"or “POST”
- SERVER NAME- The hostname of the server.
- SERVER_PORT-The port of the server (as a string)
# http报文头(header) request.META
def detail6(request, categeory_id, book_id):
# print(request.META)
content_type = request.META['CONTENT_TYPE']
print(content_type) # text/plain
name = request.META['HTTP_NAME']
print(name) # ruhua
return HttpResponse('detail-6')
5.5 其他常见HttpRequest对象属性
- method :一个字符串,表示请求使用的HTP方法,常用值包括:get’pos
- user:请求的用户对象
- path:一个字符串,表示请求的页面的完整路径,不包含域名和参数部分
- encoding:一个字符串,表示提交的数据的编码方式
- 如果为None则表示使用浏览器的默认设置,一般为utf-8
- 这个属性是可写的,可以通过修改它来修改访问表单数据使用的编码,接下来对属性的任何访问将使用新的 encoding值。 - FILES:一个类似于字典的对象,包含所有的上传文件
# 其他常见HttpRequest对象属性
def detail7(request, categeory_id, book_id):
print(request.method)
return HttpResponse('detail-7')