目录
视图处理组件是路由的后置服务模块,主要有两种实现视图处理的模式:函数式编程和面向对象编程。本节主要讲面向函数式编程实现。
视图处理函数的声明和规范
视图处理函数主要咋views.py
模块中,本身就是一个python‘函数,能够接受web请求,并返回web响应数据。
1.视图处理函数的定义
从前面章节中,就定义过视图函数,这里以前面我们说的公共模块为例,在文件personal_blog/common/views.py
下定义函数如下:
from django.http import HttpResponse
def index(request):
content = '<html><body><h1>hello views!</h1></body></html>'
return HttpResponse(content)
每个视图处理函数默认都接受一个HttpRequest
参数,通常是用一个request接受。最后函数返回一个HttpResponse
响应数据。
2.定义URL路由
定义好视图函数后,就不要和路关联。如下,修改子路由的common/urls.py
,代码如下:
from django.urls import path, re_path
from . import views
# 路由模块名称
app_name = 'common'
# 添加路由配置
urlpatterns = [
path('', views.index, name='index'),
]
3.常见错误处理
django中,视图处理函数可以根据不同的错误直接返回指定的错误页面,对应HTTP规范中则会有各种错误码分别用于表示不同的错误信息。重构视图函数如下:
def index(request):
# 数据处理过程
# 自定义错误
if flag == 'OK':
content = '<html><body><h1>hello views!</h1></body></html>'
return HttpResponse(content)
elif flag == 'NOT FOUND':
return HttpResponseNotFound('<h1>404错误,要访问的页面不存在</h1>')
elif flag == 'NOT DENIED':
return HttpResponseNotAllowed('<h1>405错误,访问失败</h1>')
elif flag == 'FORBIDDEN':
return HttpResponseForbidden('<h1>403错误,没有权限访问该页面</h1>')
elif flag == 'SERVERERROR':
return HttpResponseServerError('<h1>500错误,服务器内部出现错误</h1>')
对于404,django框架内置了django.http.Http404
错误类型,可以直接展示自定义的HTML错误信息,如下:
def index(request):
# 404错误页面
try:
# 数据处理过程
content = '<html><body><h1>hello views!</h1></body></html>'
except:
raise Http404('page not found!')
return HttpResponse(content)
4.自定义错误视图
可以参考上一节的内容。
数据响应的快捷方式
Django封装了一些快捷处理函数,如下:
render()
:请求转发,在响应数据中可以使用请求对象。redirect()
:请求重定向。get_object_or_404()
:查询指定数据,如果数据不存在,直接返回404错误。get_list_or_404()
:查询指定类型的多条数据,如果数据不存在,直接返回404错误。render_to_response()
:请求转发,在响应数据中不能使用请求对象(最新版已移除此函数)。
1.render
render(
request, template_name, context=None, content_type=None, status=None, using=None
)
参数:
- request:请求对象
- template_name:HTML网页模板路径
- context:响应上下文
- content_type:响应数据类型
- status:状态码
- using:使用的引擎
示例:重构首页index的视图处理函数,首先在项目根目录下的html_file文件下,创建首页文件index.html,如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>博客首页</title>
</head>
<body>
<h1>博客首页</h1>
{{ message }}
</body>
</html>
然后修改公共模块的视图处理函数,代码如下:
from django.shortcuts import render
def index(request):
return render(request, 'index.html', {'message': "欢迎访问博客"})
render的底层同样是使用HttpResponse实现,源代码如下:
from django.template import loader
def render(
request, template_name, context=None, content_type=None, status=None, using=None
):
"""
Return an HttpResponse whose content is filled with the result of calling
django.template.loader.render_to_string() with the passed arguments.
"""
content = loader.render_to_string(template_name, context, request, using=using)
return HttpResponse(content, content_type, status)
底层通过loader加载器加载并渲染template_name路径指向的文件,然后把文件数据封装到HttpResponse中并返回。
2.redirect
redirect(to, *args, permanent=False, **kwargs)
参数:
- to:重定向的URL请求地址
- permanent:是否永久重定向(默认False)。
基本操作方式有3中:
1.通过数据模型的get_absolute_url()
重定向。
以前面博客项目的文章数据模型为例,在文章模型汇总定义如下函数:
from django.db import models
from django.urls import reverse
class Article(models.Model):
...
def get_absolute_url(self):
return reverse('article:article_detail', kwargs={'article_id': self.id})
然后在视图处理函数再,就可以直接通过对象返回了。如下,重构根据编号查询文章的视图处理函数:
def article_detail(request, article_id):
"""查询指定编号的文章,article_id变量会接受路由中传递的数据"""
print("查询指定编号的文章,编号:%s" % article_id)
article = Article.objects.get(pk=article_id)
return redirect(article)
2.通过路由反向解析返回具体的事务页面。
如下,可以通过redirect直接反向解析路由地址,功能和reverse一样:
def article_publish(request):
"""发表文章"""
# 假如发表一篇文章,并已经得到了文章对象article
return redirect('article:article_detail', article_id=article.id)
3.直接通过硬编码指定路径。
这种方式不推荐,代码如下:
def article_publish(request):
"""发表文章"""
# 假如发表一篇文章,并已经得到了文章对象article
to = 'article/' + article.id + '/detail/'
return redirect(to)
3.get_object_or_404
在插叙你指定模型的数据时,Django中封装了ORM支持三种处理方式:1.通过模型类的objects属性进行查询;2.通过模型类提供的管理器对象Manager进行查询;3.通过定义模型类的静态方法进行查询。项目中常用第三种。
get_object_or_404函数用于查询指定数据,如果数据不存在或存在多条,直接返回404错误。
重构查询指定编号的文章的函数,如下:
def article_detail(request, article_id):
"""查询指定编号的文章,article_id变量会接受路由中传递的数据"""
print("查询指定编号的文章,编号:%s" % article_id)
article = get_object_or_404(Article, pk=article_id)
return redirect(article)
4.get_list_or_404
查询指定类型的多条数据,如果数据不存在,直接返回404错误。
重构文章查询的相关函数,代码如下:
from django.shortcuts import render, redirect, get_object_or_404, get_list_or_404
from article.models import Article
def article_list(request):
"""查询指文章列表"""
articles = get_list_or_404(Article)
return render(request, 'article/articles.html', {'articles': articles})
def article_year(request, year):
"""查询指定年份的文章,year变量会接受路由中传递的数据"""
articles = get_list_or_404(Article, pub_time__year=year)
return render(request, 'article/articles.html', {'articles': articles})
def article_month(request, year, month):
"""查询指定月份的文章,year和month变量会接受路由中传递的数据"""
articles = get_list_or_404(Article, pub_time__year=year, pub_time__month=month)
return render(request, 'article/articles.html', {'articles': articles})
注意:如果要使用__month
这样的日期时间条件,则必须在配置文件添加时间配置选项,一般配置LANGUAGE_CODE = ‘zh-Hans’,通是一定要添加USE_TZ = False,来关闭时间自动转换,才能正常存储时间和使用日期时间的限定条件查询数据对象。
视图相关装饰器
Django有一些和网站数据访问有关的功能,被封装成装饰器,主要有如下4中形式。
1.基于请求访问的装饰器
装饰器 | 描述 |
---|---|
django.views.decorators.http.require_http_methods | HTTP规范的请求方式 |
django.views.decorators.http.require_GET | 只允许GET请求方式 |
django.views.decorators.http.require_POST | 只允许POST请求方式 |
django.views.decorators.http.require_safe | 允许安全的GET/HEAD请求方式 |
示例:
@require_http_methods(['GET', 'POST'])
def author_register(request):
....
2.基于数据优化的装饰器
项目汇总有些数据修改少,但是查询多,可以使用django.views.decorators.http.condition
装饰器实现。具体细节后面讲解。
3.基于响应优化的装饰器
目前主流的浏览器都支持gzip压缩/解压缩操作,可以将数据通过gzip压后返回给客户端,节省流量。示例如下:
@gzip_page
def articles_author(request, author_id):
'''查询指定作者的所有文章'''
# 查询得到作者对象
author = get_object_or_404(Author, pk=author_id)
# 查询作者的所有文章
articles = author.article_set.all()
return render(request, 'article/articles.html', {'articles': articles})
4.基于缓存的网站性能优化
比如django.views.decorators.cache
,可以用于缓存。具体缓存在后面有专门的章节讲。