一、路由说明
1、路由定义的位置
Django的主要路由信息定义在工程同名目录下的urls.py文件中,该文件是Django解析路由的入口。每个子应用为了保持相对独立,可以在各个子应用中定义属于自己的urls.py来保存该应用的路由。然后用主路由文件包含各应用的子路由数据。除了上述方式外,也可将工程的全部路由信息都定义在主路由文件中,子应用不再设置urls.py。
import book_test
urlpatterns = [
path('admin/', admin.site.urls),
# 将子应用的路由添加到总工程中
# url(r'book_test/',include('book_test.urls'))
# 将应用中的路由全部注册的 url(r'book_test/sayhello',book_test.views.sayhello)
]
2、路由的执行顺序
Django在接收到一个请求时,从主路由文件中的urlpatterns列表中以由上至下的顺序查找对应路由规则,如果发现规则为include包含,则再进入被包含的urls中的urlpatterns列表由上至下进行查询。值得关注的 由上至下 的顺序,有可能会使上面的路由屏蔽掉下面的路由,带来非预期结果。
urlpatterns = [
url(r'^say', views.say),
url(r'^sayhello', views.sayhello),
]
即使访问sayhello/路径,预期应该进入sayhello视图执行,但实际优先查找到了say路由规则也与sayhello/路径匹配,实际进入了say视图执行。
注意:
需要注意路由的执行顺序,以免路由被屏蔽
- 路由命名与reverse反解析
3.1 路由命名
- 在使用include函数定义路由时,可以使用namespace参数定义路由的命名空间,这个就像flask蓝图中定义蓝图的第一个参数作用差不多
# flask蓝图
orderblue = Blueprint('order',__name__)
# 命名空间
url(r'book_test/',include('book_test.urls',namespace='books'))
命名空间的作用:避免不同应用中的路由使用了相同的名字发生冲突,使用命名空间区别开。
- 在定义普通路由时,可以使用name参数指明路由的名字
url(r'^book_index/', views.book_index,name='index'),
url(r'^sayhello',views.sayhello,name='sayhello'),
url(r'^say',views.say,name='say')
3.2 reverse反解析
使用reverse函数,可以根据路由名称,返回具体的路径, 这个就像flask中的url_for()函数
对于未指明namespace的,reverse(路由name)
对于指明namespace的,reverse(命名空间namespace:路由name)
二、请求与响应
1、请求Request
对于请求我们做的就是获取参数,还记得,请求可以如何传递参数。
- 提取URL的特定部分,如/weather/beijing/2018,可以在服务器端的路由中用正则表达式截取
- 查询字符串(query string),形如key1=value1&key2=value2
- 请求体(body)中发送的数据,比如表单数据、json、xml
- 在http报文的头(header)中
1.1 URL路径参数
对于url路径参数,我们可以使用正则表达式截取,Django会将提取的参数直接传递到视图的传入参数中。这里提一下,不知还是记得Flask中url路径参数的获取,对于flask我们采用的是转换器进行url匹配
flask
# 请求路径 http://127.0.0.1:5000/89 获取不同新闻的id
@app.route('/<int:news_id>')
def demo(news_id):
print(news_id)
return 'ok'
Django
- 未命名参数按传递顺序传递,使用正则小括号分组提取
# url(r'^weather/([a-z]+)/(\d{4})/$', views.weather)
url(r'^(\d{4})/([1-9]|1[0-2])',views.mouth)
# 必须按顺序传递参数
def mouth(request,year,mouth):
print('year:%s'%year)
print('mouth:%s'%mouth)
return HttpResponse('年份:%s, 月份: %s' %(year,mouth))
- 命名参数按名字传参
url(r'^(?P<city>[a-z]+)/(?P<year>\d{4})/$', views.city),
def city(request,city,year):
print('year:%s' % year)
print('city:%s' % city)
return HttpResponse('年份:%s, 城市: %s' %(year,city))
2、HttpRequest对象
属性:
属性 | 说明 |
---|---|
scheme | 表示请求方案(http或https 通常)的字符串 |
body | 原始HTTP请求主体作为字节字符串。这对于以不同于传统HTML表单的 方式处理数据非常有用:二进制映像,XML有效负载等 |
method | 表示请求中使用的HTTP方法的字符串。这保证是大写的 |
path | 表示所请求页面的完整路径的字符串 例: “/music/bands/the_beatles/” |
GET | 类似字典的对象,包含所有给定的HTTP GET参数 |
POST | 一个包含所有POST请求的参数,以及包含表单数据的字典。 如果需要访 问请求中的原始或非表单数据,可以使用HttpRequest.body属 |
META | 包含所有HTTP头部信息的字典。 可用的头部信息取决于客户端和服务器 |
COOKIES | 包含所有Cookie信息的字典。 键和值都为字符串。可以类似字典类型 的方式,在cookie中读写数据,但是注意cookie是不安全的,因此,不要写敏感重要的信息 |
FILES | 一个类似于字典的对象,包含所有的上传文件 |
encoding | 一个字符串,表示提交的数据的编码方式 |
- GET属性
def say(request):
print(request.method) # 请求的方式
print(request.scheme) # 请求的方案
print(request.path) # 请求的路径
print('-'*50)
print(request.GET.get('a')) # 获取请求url 后面带的参数,获取最后一个 /jfj?a=1&b=2&a=3
print(request.GET.get('b'))
print(request.GET.getlist('a')) # 获取列表
return HttpResponse('say 页面')
请求url:http://127.0.0.1:8001/book_test/say?a=csx&b=jfjfj&a=12 请求方式get
请求url:http://127.0.0.1:8001/book_test/say?a=csx&b=jfjfj&a=12 请求方式post
- POST 属性:表单数据的获取
def say(request):
print(request.method) # 请求的方式
print(request.scheme) # 请求的方案
print(request.path) # 请求的路径
print('-' * 50)
# 前端发送的表单类型的请求体数据,可以通过request.POST属性获取,返回QueryDict对象
print(request.POST.get('name'))
print(request.POST.get('age'))
print(request.POST.getlist('name'))
return HttpResponse('say 页面')
运行结果:
- 非表单数据的获取
def say(request):
print("-"*100)
string = request.body
print(string)
print(type(string))
req_data = json.loads(string)
print(type(req_data))
print(req_data['a'])
print(req_data['b'])
print("-"*100)
return HttpResponse('OK')
说明:
- 对于json数据转换成字典使用 json.loads(参数),对于传入的参数,根据python解释器的不同,传入的参数类型不同。在python3.5 一下传入的参数必须是字符串,因为从request.body 获取的bytes类型,所以我们在转换之前要进行解码。在python3.5之后传入的参数可以是字节或者是字符串,不用解码。
3、HttpResponse对象
与HttpRequest由Django自动创建的对象相比,HttpResponse对象是您的责任。您编写的每个视图都负责实例化,填充和返回 HttpResponse。该HttpResponse课程住在django.http模块中
可以使用django.http.HttpResponse来构造响应对象。
HttpResponse(content=响应体, content_type=响应体数据类型, status=状态码)
也可通过HttpResponse对象属性来设置响应体、响应体数据类型、状态码:
- content:表示返回的内容。
- status_code:返回的HTTP响应状态码。
- content_type:指定返回数据的的MIME类型
响应头可以直接将HttpResponse对象当做字典进行响应头键值对的设置:
response = HttpResponse()
response['NameAuthor'] = 'csx'
实例:
url(r'^demo1$',views.demo1),
url(r'^demo$',views.demo)
# 直接返回响应
def demo(request):
return HttpResponse('响应数据',status=400)
# 响应设计
def demo1(request):
response = HttpResponse()
response.content = '{"name":"ddd","age":18}'
response.status_code = 200
response['Content-Type'] = 'application/json'
return response
HttpResponse子类
Django提供了一系列HttpResponse的子类,可以快速设置状态码
- HttpResponseRedirect 301
- HttpResponsePermanentRedirect 302
- HttpResponseNotModified 304
- HttpResponseBadRequest 400
- HttpResponseNotFound 404
- HttpResponseForbidden 403
- HttpResponseNotAllowed 405
- HttpResponseGone 410
- HttpResponseServerError 500
JsonResponse
若要返回json数据,可以使用JsonResponse来构造响应对象,作用:
- 帮助我们将数据转换为json字符串
- 设置响应头Content-Type为 application/json
# 路由
url(r'^view_demo$',views.demo_view)
# 视图函数
def demo_view(request):
return JsonResponse({'city': 'beijing', 'subject': 'python'})
重定向
url(r'^book_index/', views.book_index,name='index'),
url(r'^views$',views.view_demo)
def view_demo(request):
return redirect('index')
4、Cookie
设置cookie
Django的cookie设置和Flask的cookie设置相似
# flask 设置cookie,max_age 过期时间,以秒为单位
@app.route('/login')
def login():
response = make_response('登录成功')
response.set_cookie('username', 'csx', max_age=3600)
response.set_cookie('password', '512279', max_age=3600)
return response
# 路由
url(r'^login',views.login),
# django
def login(request):
response = HttpResponse('登录成功')
response.set_cookie('name','csx',max_age=300)
response.set_cookie('age',19,max_age=300)
return response
获取cookie
# flask
@app.route('/')
def index():
password = request.cookies.get('password')
user = flask.request.cookies.get('username')
return '%s -- %s' % (user, password)
# 路由
url(r'^show',views.show_)
# django 获取cookie
def show_(request):
name = request.COOKIES.get('name')
age = request.COOKIES.get('age')
return HttpResponse('name: %s,age: %s' %(name,age))
删除cookie
# flask
@app.route('/logout')
def logout():
response = make_response('success')
response.delete_cookie('username')
response.delete_cookie('password')
# 路由
url(r'^show',views.show_)
# django 获取cookie
def logout(request):
response = HttpResponse('退出登录')
response.delete_cookie('name')
response.delete_cookie('age')
return response
5、Session
session 配置
- 启用session
Django项目默认启用Session
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
#默认启用了session
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
# 'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
session的存储位置
在settings.py文件中,可以设置session数据的存储方式,可以保存在数据库、本地缓存等
- 默认存储在数据库中:存储在数据库中,如下设置可以写,也可以不写,这是默认存储方式。
SESSION_ENGINE='django.contrib.sessions.backends.db'
如果存储在数据库中,需要在项INSTALLED_APPS中安装Session应用。
- 本地缓存
存储在本机内存中,如果丢失则不能找回,比数据库的方式读写更快。
SESSION_ENGINE='django.contrib.sessions.backends.cache'
- 混合存储
优先从本机内存中存取,如果没有则从数据库中存取。
SESSION_ENGINE='django.contrib.sessions.backends.cached_db'
- 存储在Redis中
在settings.py文件中做如下设置
CACHES = {
"default": {
"BACKEND": "django_redis.cache.RedisCache",
"LOCATION": "redis://127.0.0.1:6379/1",
"OPTIONS": {
"CLIENT_CLASS": "django_redis.client.DefaultClient",
}
}
}
SESSION_ENGINE = "django.contrib.sessions.backends.cache"
SESSION_CACHE_ALIAS = "default"
如果redis的ip地址不是本地回环127.0.0.1,而是其他地址,访问Django时,可能出现Redis连接错误,修改redis的配置文件,添加特定ip地址.
Session操作
通过HttpRequest对象的session属性进行会话的读写操作。
- 以键值对的格式写session。
request.session['键']=值
- 根据键读取值。
request.session.get('键',默认值)
- 清除所有session,在存储中删除值部分。
request.session.clear()
- 清除session数据,在存储中删除session的整条数据。
request.session.flush()
- 删除session中的指定键及值,在存储中只删除某个键及对应的值。
del request.session['键']
- 设置session的有效期
request.session.set_expiry(value)
①如果value是一个整数,session将在value秒没有活动后过期。
②如果value为0,那么用户session的Cookie将在用户的浏览器关闭时过期。
③如果value为None,那么session有效期将采用系统默认值,默认为两周,可以通过在settings.py中设置SESSION_COOKIE_AGE来设置全局默认值。