Django控制器
配置路由
通过对urls.py的配置将用户请求映射到处理函数。
Django的URL字符串匹配实际上基于正则表达式,这允许单条URL可以匹配一类请求。参见Django Book中的示例:
from django.conf.urls import url
from . import views
urlpatterns = [
url(r'^articles/2003/$', views.special_case_2003),
url(r'^articles/([0-9]{4})/$', views.year_archive),
url(r'^articles/([0-9]{4})/([0-9]{2})/$', views.month_archive),
]
实例解析:
-
/articles/2005/03/
请求将匹配列表中的第三个模式。Django 将调用函数views.month_archive(request, '2005', '03');无论如何匹配,匹配的内容均将作为Python字符串传递给视图函数。 -
/articles/2005/3/
不匹配任何URL 模式,因为列表中的第三个模式要求月份应该是两个数字。 -
/articles/2003/
将匹配列表中的第一个模式不是第二个,因为模式按顺序匹配,第一个会首先测试是否匹配。请像这样自由插入一些特殊的情况来探测匹配的次序。 -
/articles/2003
不匹配任何一个模式,因为每个模式要求URL以一个反斜线结尾。
在Python 正则表达式中,命名正则表达式组的语法是(?P
from django.conf.urls import url
from . import views
urlpatterns = [
url(r'^articles/2003/$', views.special_case_2003),
url(r'^articles/(?P<year>[0-9]{4})/$', views.year_archive),
url(r'^articles/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/$', views.month_archive),
]
以命名组的语法重写上述代码,两者区别在于捕获的值作为关键字参数而不是位置参数传递给视图函数
/articles/2005/03/
请求将调用views.month_archive(request, year='2005', month='03')函数,而不是views.month_archive(request, '2005', '03')。
针对正则表达式中的命名组和非命名组,如果有命名参数url解析器将使用命名参数,否则将以位置参数传递所有匹配的字符串。
进行匹配时将不包括GET或POST请求方式的参数以及域名:
-
http://www.example.com/myapp/
-
http://www.example.com/myapp/?page=3
对同一个URL的无论是POST请求、GET请求、或HEAD请求方法都将映射到相同的函数。
urlpatterns 中的每个正则表达式在第一次访问它们时被编译。这使得系统相当快。
使用include
urlpatterns可以包含另一URLConf模块:
from django.conf.urls import include, url
urlpatterns = [
# ... snip ...
url(r'^community/', include('django_website.aggregator.urls')),
url(r'^contact/', include('django_website.contact.urls')),
# ... snip ...
]
注意,这个例子中的正则表达式没有包含$(字符串结束匹配符),但是包含一个末尾的反斜杠.
每当Django 遇到django.conf.urls.include()
时,它会去掉URL 中匹配的部分并将剩下的字符串发送给包含的URLconf 做进一步处理。
from django.conf.urls import include, url
from apps.main import views as main_views
from credit import views as credit_views
extra_patterns = [
url(r'^reports/(?P<id>[0-9]+)/$', credit_views.report),
url(r'^charge/$', credit_views.charge),
]
urlpatterns = [
url(r'^$', main_views.homepage),
url(r'^help/', include('apps.help.urls')),
url(r'^credit/', include(extra_patterns)),
]
在这个例子中,URL/credit/reports/
将被credit.views.report()
这个函数处理。
编写views函数
views函数接受封装了HTTP请求的request对象作为参数, 返回response对象作为HTTP响应.
若返回str对象, django会将其封装为response对象, 也可以返回模板渲染结果或者redirect对象.
django.http.JsonResponse
将一个dict对象构造为JSON格式的响应:
`return JsonResponse({'result': 'ok'})`
使用模板
编写hello.py并保存在templates下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Hello</title>
</head>
<body>
<p>{{ hello }}</p>
</body>
</html>
修改HelloWorld/settings.py,修改 TEMPLATES 中的 DIRS: 'DIRS': [os.path.join(BASE_DIR, 'templates')]
。
修改 view.py,增加一个新的对象,用于向模板提交数据:
from django.shortcuts import render
def hello(request):
context = {}
context['hello'] = 'Hello World'
return render(request, 'hello.html',context)
render函数原形:
render(request, template_name[, context][, content_type][, status][, using])[source]
render(渲染)通常使用3个位置参数:
render(request, template_name, context = None)
分别为HttpRequest对象,模板文件名和上下文词典并返回一个渲染后的 HttpResponse 对象。模板引擎可以在上下文context中搜索对象并进行渲染。
可选参数:
-
content_type
:生成的文档要使用的MIME 类型。默认为DEFAULT_CONTENT_TYPE 设置的值。 -
status
: 响应的状态码,默认为200. -
using
用于加载模板使用的模板引擎的名称.如:-
'django.template.backends.django.DjangoTemplates'
-
'django.template.backends.jinja2.Jinja2'
-
render方法返回响应字符串,render_to_response则返回HttpResponse对象。
def hello(request):
context = dict()
response = render_to_response('test-cookies.html', context)
return response
重定向
重定向将对某一URL的请求,转到另外的URL。
Django中常用3中方法实现页面重定向。
在模板视图函数中使用redirect()
一般情况下redirect()接受一个绝对或相对URL的字符串,并返回一个临时重定向。
关键字参数permanent的默认值为False,传入permanent=True则可以返回一个永久重定向。
from django.shortcuts import redirect
def hello(request):
return redirect(r'^admin/')
在URL配置中使用redirect_to
配置ulrs.py
from django.conf.urls import url
from django.contrib import admin
from FirstDjango.view import hello
from django.views.generic.base import RedirectView
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^hello/', hello),
url(r'^world/', RedirectView.as_view(url='/hello/'))
]
访问127.0.0.1/world/
的效果等同于访问127.0.0.1/hello/
。
使用redirects app进行重定向
-
在settings.py 中 增加 'django.contrib.redirects' 到你的 INSTALLED_APPS 设置。
-
增加 'django.contrib.redirects.middleware.RedirectFallbackMiddleware' 到的MIDDLEWARE_CLASSES 设置中。
-
运行 manage.py syncdb. 创建 django_redirect 表,包含 site_id, old_path and new_path 字段。
获得请求参数
HTTP方法用于表示用户提交请求的动作类型, 常用的有GET
和POST
方法.
Django将HTTP请求封装为request, 我们可以从中获得请求参数等信息.
Django的URL匹配不区分请求方法,不对请求参数进行匹配,对同一个URL的不同方法的请求将会映射到同样的处理函数.但是我们可以通过request对象获得HTTP方法的信息.
GET方法
GET方法会将请求参数包含在URL中,一般用于发送获取而不改变服务器数据的请求。
GET方法适合发送搜索查询等请求,因为数据被保存在URL中可以方便地作为书签,分享或重新提交。
HttpRequest.GET属性是一个封装了GET请求参数的dict,只需要在词典中访问响应的参数即可。
form-get.html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form action="/search-post/" method="get">
<input type="text" name="search_content">
<input type="submit" value="submit">
</form>
<p>{{ result }}</p>
</body>
</html>
search.py:
def search_get(request):
context = dict()
if 'search_content' in request.GET:
context['result'] = request.GET['search_content']
return render(request, 'form-post.html', context)
urls.py:
from django.conf.urls import url
from django.contrib import admin
from SecondDjango.views import *
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'form-get/', search),
url(r'^search-get', search_get),
]
POST方法
POST方法是更常用的提交数据的方法,它常用来提交要求改变服务器状态的请求如登录请求.
Django为POST方法提供了CSRF保护,这只需要在模板中添加csrf_token
即可。
HttpRequest.POST属性是一个封装了除file_upload相关参数外POST请求参数的dict,只需要在词典中访问响应的参数即可。因为可能存在空参数的情况,所以要先进行相关校验。
form-post.html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form action="/search-post/" method="post">
{% csrf_token %}
<input type="text" name="search_content">
<input type="submit" value="submit">
</form>
<p>{{ result }}</p>
</body>
</html>
与form-get.html相比,多了{% csrf_token %}
用来提供和csrf保护。
search.py:
from django.shortcuts import render
from django.core.context_processors import csrf
# Create your views here.
def search(request):
return render(request, 'form-post.html', None)
def search_get(request):
context = dict()
if 'search_content' in request.GET:
context['result'] = request.GET['search_content']
return render(request, 'form-post.html', context)
urls.py:
from django.conf.urls import url
from django.contrib import admin
from SecondDjango.views import *
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^form-post/', search),
url(r'^search-post/', search_post),
]
文件上传
Django上传文件的内容包含在HttpResponse.FILE中。
编写file-upload.html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>File Upload</title>
</head>
<body>
<form action="/handle-upload/" method="post" enctype="multipart/form-data">
{% csrf_token %}
<input type="file" name="file">
<br><br>
<input type="submit" value="upload">
</form>
</body>
</html>
编写file-upload-success.html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>File Upload Success</title>
</head>
<body>
<p>{{ filename }} uploaded successfully</p>
</body>
</html>
编写views.py:
def handle_upload(request):
print('handling upload')
file = request.FILES['file']
filename = str(request.FILES['file'])
print(filename)
if not os.path.exists('upload/'):
os.mkdir('upload/')
out = open('upload/' + filename, 'wb+')
for chunk in file.chunks():
out.write(chunk)
print('write finished')
# render response
context = dict()
context['filename'] = filename
return render(request, 'file-upload-success.html', context)
def upload(request):
return render(request, 'file-upload.html')
配置urls.py:
from django.conf.urls import url
from django.contrib import admin
from SecondDjango.views import *
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^handle-upload/', handle_upload),
url(r'^upload/', upload),
]
session 与 cookie
Http协议是无状态协议,以请求-响应的模式工作用户不保持在线状态。session和cookie是用来保持对用户跟踪的常用方法。
cookies
cookies是保存在客户端硬盘上的小文件,浏览器在发送请求时会将cookies包含在HttpRequest中一同发送。
服务端可以在HttpResponse中重新设置cookies, 浏览器收到cookies之后会自动更新保存在客户端硬盘上的cookie文件。
编写test-cookies.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Test Cookies</title>
</head>
<body>
尹大人被打了{{ num }}次了!
{{ beat }}
</body>
</html>
编写views.py
def test_cookies(request):
context = dict()
if 'num' in request.COOKIES:
num = int(request.COOKIES['num']) + 1
else:
num = 1
beat = ''
for i in range(num+1):
beat += '啊!'
context['num'] = str(num)
context['beat'] = beat
response = render_to_response('test-cookies.html', context)
response.set_cookie('num', str(num))
return response
因为要使用response.set_cookie
所以采用render_to_response渲染。
配置urls.py
from django.conf.urls import url
from django.contrib import admin
from SecondDjango.views import *
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^test-cookies/', test_cookies),
]
session
session(会话)对象是保存了追踪用户信息的词典,一般情况下若浏览器未关闭或未超时session将会有效.
session使用cookie在客户端保存用于识别用户的token, 数据保留在服务端.
Django提供了基于缓存、文件和数据库的session引擎, 若要启动session首先在settings.py中进行配置.
-
修改 MIDDLEWARE_CLASSES 设置,并确定其中包含了
'django.contrib.sessions.middleware.SessionMiddleware'
-
修改INSTALLED_APPS设置,确定其中包含了
django.contrib.sessions
默认情况下以上两个设置为支持session的状态。此外还需设置session引擎SESSION_ENGINE
-
默认为基于数据库的引擎
django.contrib.sessions.backends.db
-
基于文件的引擎
django.contrib.sessions.backends.file
-
这里采用最简单的基于缓存的引擎
django.contrib.sessions.backends.cache
编写login-session.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Login Session</title>
</head>
<body>
<form action="/login-validate/" method="post">
{% csrf_token %}
<input type="text" name="username">
<input type="password" name="password">
<input type="submit" value="submit">
</form>
</body>
</html>
编写login-success.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Login Success</title>
</head>
<body>
<p>Welcome, {{ current_user }}!</p>
</body>
</html>
编写keep-online.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Keep Online</title>
</head>
<body>
<p>{{ username }}, you are still online.</p>
</body>
</html>
编写views.py
def login(request):
return render(request, 'login-session.html')
def login_validate(request):
context = dict()
if request.POST['password'] == 'exciting':
request.session['current_user'] = 'NaiveUser'
context['current_user'] = request.session['current_user']
return render(request, 'login-success.html', context)
def keep_online(request):
context = dict();
context['username'] = request.session['current_user']
return render(request, 'keep-online.html', context)
可以方便的对HttpRequest.session进行操作,然后使用render将其渲染到HttpResponse中返回客户端。
配置urls.py
from django.conf.urls import url
from django.contrib import admin
from SecondDjango.views import *
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^login-session/', login),
url(r'^login-validate/', login_validate),
url(r'^keep-online/', keep_online),
]
访问127.0.0.1:8000/login-session/
输入"NaiveUser","exciting"登录。在关闭浏览器之前访问127.0.0.1:8000/keep-online/
,可以看到:
访问127.0.0.1:8000/test-cookies/
,然后再次发送请求(刷新)。可以发现服务器跟踪了访问的次数。