众所周知,Django采用的是MTV框架模式,本文介绍的就是其中的V(View视图)。用户在访问某个url后,在返回响应之前,通常需要进行一些业务逻辑上的处理,然后再将处理后的数据返回给客户端,在Django中,View视图就是专门用来做这部分负责业务逻辑的功能的,同时,视图也是Model模型与Template模板之间的桥梁,因为通常是通过模型从数据库中获取数据,经过视图处理后再渲染到模板中。Django中视图主要是以视图函数和类视图的方式来处理数据并返回响应,本文也主要是介绍这两种方式。
一、视图函数
视图函数通常写在app的views.py 文件中,定义视图函数时需要注意以下几点:
- 函数的第一个参数必须是
request ,这是一个WSGIRequest 对象(参考本文后面关于此对象的介绍),Django会将用户请求的相关信息都封装在这个对象中,我们可以直接从这个对象中获取相关请求信息。
- 函数的返回值必须是
HttpResponseBase 对象或其子类对象,通常是HttpResponse 对象,或通过render 和redirect 封装一个HTML文件后的对象,它们都是HttpResponseBase 的子类对象。
- 在
urlpatterns 中配置url映射关系时,直接配置对应函数名即可。
1、创建一个普通的视图函数
视图函数的定义,除了第一个参数必须是request 之外,如果url中定义了参数,那么在视图函数中按顺序定义同名的参数即可。
视图函数的返回值通常是一个HttpResponse 对象(一个普通的响应对象),或者通过render 和redirect 方法返回一个HTML模板,当然,如果想要给HTML模板中传递上下文参数变量,可以使用render 方法的context 参数指定一个字典即可。
"""urls.py:配置url映射关系"""
from django.urls import path
from .views import book,book_list
# 直接使用视图函数名称来进行映射即可
urlpatterns = [
path('book/<book_id>/',book),path('book/list/',book_list)
]
"""views.py:定义视图函数"""
from django.http import HttpResponse
from django.shortcuts import render
# 如访问“/book/”或“/book/3/”就会执行此视图函数的内容
def book(request,book_id=1):
text = '您正在阅读的图书id是:{}'.format(book_id)
# 返回一个普通的响应对象
return HttpResponse(text)
def book_list(request):
# 通过render函数返回一个HTML模板,render的第一个参数也必须是request
return render(request,'book_list.html')
2、WSGIRequest对象 - request参数
Django在接收到HTTP请求之后,会将HTTP请求携带的参数以及报文信息封装在一个WSGIRequest 对象中,然后传递给视图函数,也就是视图函数的第一个参数request 。对源码感兴趣的话,可以打印下这个对象,WSGIRequest 对象继承自HttpRequest ,源码位置在django.core.handlers.wsgi 。
常用的属性:
常用的方法:
-
is_secure :是否是采用的https 协议。
-
is_ajax :是否是采用ajax 发送的请求。原理是判断请求头中是否存在X-Requested-With:XMLHttpRequest 。
-
get_host :服务器的域名,如果访问时有加上端口号,则会返回域名和端口号。
-
get_full_path :返回完整路径,包含查询字符串,但不包含域名。
-
get_raw_uri :获取请求的完整url。
3、HttpResponse对象
视图函数中如果不想直接返回一个HTML模板,而是返回一个普通的响应对象,或者想自己在响应对象中定义一些数据,就可以使用HttpResponse 对象。
常用的属性:
-
content :返回的内容。
-
status_code :返回的HTTP响应状态码。
-
content_type :返回的数据的MIME类型,默认为text/html 。浏览器会根据这个属性来决定怎么显示数据,如text/html 则会解析这个字符串,text/plain 则会显示为一个纯文本。常用的Content-Type 有:
-
text/html :默认的类型,HTML文件。
-
text/plain :纯文本。如果出现中文乱码,可以在后面指定编码方式,如text/plain;charset=utf-8 。
-
text/css :css文件。
-
text/javascript :js文件。
-
multipart/form-data :文件提交。
-
application/json :json传输。
-
application/xml :xml文件。
- 设置请求头:可以使用字典的方式,如
HttpResponse()['X-Access-Token']='xxx' 。
常用的方法:
-
set_cookie :设置cookie 信息。
-
delete_cookie :删除cookie 信息。
-
write :HttpResponse 可以当作一个类似文件的对象,用此方法来写入数据到数据体content 中。
JsonResponse对象
这个对象在from django.http import JsonResponse 中,用来返回json对象,默认只能传递一个字典对象,如果传递的是非字典对象,则需要指定一个参数safe=False 。
4、render/render_to_string/redirect
render :用来返回一个HTML模板,可以通过from django.shortcuts import render 直接导入,第一个参数必须是request (即视图函数的第一个参数request ),第二个参数是模板路径字符串。如果要给模板传递上下文变量参数,可以通过字典的方式传递给context 参数。
render_to_string :是用来将一个HTML模板转换为字符串,在from django.template.loader import render_to_string 中,因为返回值是字符串,所以是不能直接返回的,而是需要传入HttpResponse 再返回,但是浏览器中呈现的依然是原先HTML模板中的内容。
redirect :是用于url的重定向,可以通过from django.shortcuts import redirect 直接导入,redirect(to,*args,permanent=False,**kwargs) 通常只需要传入对应的url即可,也就是只需要指定to 参数,permanent 表示是否需要永久性重定向,默认为False 。
from django.shortcuts import render
from django.http import HttpResponse
from django.template.loader import render_to_string
def index1(request):
# 先将模板转为一个字符串,到浏览器后又会反转回来
# html_str = render_to_string('index.html')
# return HttpResponse(html_str)
# 直接传入一个模板
return render(request,'index.html')
def index2(request):
username = request.GET.get('username')
if username:
return HttpResponse('这是首页!')
else:
return redirect('/login/')
5、限制请求方式
想要给视图函数指定或限制请求方式,可以使用django.views.decorators.http 中的装饰器来实现。
常用的装饰器:
-
require_http_methods :此装饰器可以传入一个请求method 的列表,表示此视图或url只能使用指定的请求method 来访问。
-
require_GET :指定此视图或url只能使用GET 请求,相当于@require_http_methods(['GET']) 。
-
require_POST :指定此视图或url只能使用POST 请求,相当于@require_http_methods(['POST']) 。
-
require_safe :指定此视图或url只能使用GET 或HEAD 请求,相当于@require_http_methods(['POST','HEAD']) 。
# 指定此视图只能使用GET或POST请求
@require_http_methods(['GET','POST'])
def add_article(request):
# 获取并判断此次请求对应的请求method
if request.method == 'GET':
return render(request,'add_article.html')
else:
# 如果是POST请求,则添加一条数据到Article模型(表)中
title = request.POST.get('title')
content = request.POST.get('content')
# create方法:添加一条数据并保存到数据库
Article.objects.create(title=title,content=content)
return HttpResponse('success!')
二、类视图
视图的逻辑处理除了可以定义在函数中,还可以定义在类中,即类视图,常用的类视图有三种:View 、TemplateView 和ListView 。
1、View类视图
View 类视图是一个通用的类视图,定义的类需要继承自from django.views.generic import View ,定义此类视图时需要注意以下几点:
- 如果想要指定允许的某种或多种请求方式,如
GET 等,则定义对应名称的方法即可,没有定义的方法则表示不允许这种请求方式,如def get(self,request):... ,定义方式和视图函数是一样的,比如有一个固定的request参数,返回值必须是HttpResponseBase 对象或其子类对象。
- 在配置url映射时需要使用类的
as_view() 方法,如path('detail/<book_id>/',BookDetailView.as_view()) ,当然,如果url中有指定参数,直接在类视图中的对应方法中按顺序添加同名的参数即可,也是和视图函数的定义一样的。
- 如果用户访问了不支持的或没有定义的请求方法,那么默认会先去查找并执行类中的
http_method_not_allowed(self,request,**kwargs) 方法,如果此方法没有定义,则返回一个405的错误。
from django.views.generic import View
class BookDetailView(View):
# 如访问的url为:detail/<book_id>/
def get(self,book_id):
return HttpResponse('success!')
def http_method_not_allowed(self,**kwargs):
return HttpResponse('不支持GET以外的请求方法!')
2、TemplateView类视图
如果一个url访问时并不需要专门的视图来进行处理,而是想直接返回一个固定写好的HTML文件,那么就可以使用TemplateView ,也在from django.views.generic import TemplateView 中,直接在配置url映射关系时使用它的as_view 方法并指定template_name 参数即可。
from django.urls import path
from django.views.generic import TemplateView
urlpatterns = [
path('about/',TemplateView.as_view(template_name='about.html'))
]
虽然不用定义专门的视图来处理,但如果需要传递一些参数到模板中,那么就需要定义一个TemplateView 的子类并重写get_context_data 方法,示例如下:
from django.views.generic import TemplateView
class AboutView(TemplateView):
# 指定HTML模板路径
template_name = 'about.html'
# 定义get_context_data方法,并返回一个字典,这个字典会用作模板的上下文对象
def get_context_data(self,**kwargs):
context = {'username': 'zhangsan'}
return context
# url映射时就不需要再传递模板路径了
# urlpatterns = [
# path('about/',AboutView.as_view())
# ]
3、ListView
如果页面中需要用到分页的功能,那么就可以考虑使用ListView 视图了,它是专门用作分页功能的视图的,相比于普通的视图实现,它会非常的方便快捷,也是在from django.views.generic import ListView 中,使用时需要定义一个它的子类并配置相关属性即可。
常用的属性和方法有:
-
model :页面中分页数据需要用到的ORM模型类。
-
template_name :指定返回的HTML模板。
-
paginate_by :指定这个页面中展示的数据条数。
-
context_object_name :指定这个模板中分页数据需要用到的上下文参数名称。
-
ordering :指定数据的排列方式。
-
page_kwarg :访问分页中第几页时用到的查询字符串参数,默认为page 。
-
get_context_data() :获取上下文中的数据,如果需要额外添加数据到上下文中,可以重写这个方法。因为ListView 中此方法本身就实现了许多功能,所以定义此视图时通常需要先使用super 获取父类的结果,再在此结果中添加自己额外的上下文数据。
-
get_queryset() :指定分页界面中展示所需的数据,默认为ORM模型类对应的全部数据,相当于xxx.objects.all() ,如果不想返回所有数据,也可以使用filter 等方法返回一个QuerySet 对象,如xxx.objects.filter(id__lte=50) 只返回id 大于等于50的数据。
示例:访问/article/list/ 时就会默认显示前paginate_by 条数据,访问/article/list/?p=3 时就显示第paginate_by 乘以3组数据,url中的p 是由page_kwargs 指定的,也可以不改,就使用默认的page 。
"""views.py视图文件代码片段"""
from django.views.generic import ListView
from .models import Article
class ArticleListView(ListView):
model = Article # ORM模型类
template_name = 'article_list.html' # 响应的HTML模板
context_object_name = 'articles' # 模板中分页数据用到的上下文参数名称
paginate_by = 10 # 每页显示的数据条数
ordering = 'create_time' # 指定排序字段
page_kwargs = 'p' # 访问指定页数时的查询字符串参数名称
"""urls.py映射文件代码片段"""
from django.urls import path
from .views import ArticleListView
urlpatterns = [
path('article/list/',ArticleListView.as_view())
]
<!-- article_list.html代码片段 -->
<ul>
<!-- 此处的articles就是视图中context_object_name属性指定的值 -->
{% for article in articles %}
<li>{{ article.title }}</li>
{% endfor %}
</ul>
Paginator类和Page类
在ListView 视图中默认返回的上下文参数中有两个常用的对象paginator 和page_obj ,对应于django.core.paginator.Paginator 类和django.core.paginator.Page 类,在HTML模板中会经常用到这两个对象的属性和方法。
Paginator 常用属性和方法:
-
count :总的数据条数。
-
num_pages :总共有多少页。
-
page_range :比如总共有10页,那么返回的就是range(1,11) 。
Page 常用属性和方法:
-
has_next :是否还有下一页。
-
has_previous :是否还有上一页。
-
next_page_number :下一页的页码。
-
previous_page_number :上一页的页码。
-
number :当前页的页码。
-
start_index :当前页的第一条数据的索引值。
-
end_index :当前页的最后一条数据的索引值。
4、在类视图中使用装饰器
在Django中如果想要给类方法添加装饰器,Django提供了一更加安全的使用方式,即使用from django.utls.decorators import method_decorator 装饰器,使用时将自定义的装饰器函数传入,再去装饰对应的类或者方法即可。
访问url时,在进入对应类视图的方法之前,其实会先执行类视图的dispatch 方法,所以如果想给类视图使用装饰器的话,可以直接装饰dispatch 方法。装饰的方式也有两种,一种方式是直接在这个方法上使用对应的装饰器,另一种方式则在类定义上使用对应的装饰器,推荐使用后者,具体见示例代码。
from django.views.generic import View
from django.utls.decorators import method_decorator
# my_decorator为自定义的装饰器,将它放入method_decorator会更加安全
# 方式一:推荐采用这种直接装饰类的方式,传入自定义的装饰器和要装饰的方法即可
@method_decorator(my_decorator,name='dispatch')
class BookDetailView(View):
def get(self,book_id):
return HttpResponse('success!')
# 方式二:通过重写dispatch的方式
@method_decorator(my_decorator)
def dispatch(self,**kwargs):
return super().dispatch(request,**kwargs)
注:本文为学习笔记,发现错误欢迎指出。 (编辑:李大同)
【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!
|