第四章  视图

  4.1  探究视图

  一、视图说明

  视图(View)是Django的MTV架构模式的V部分,主要负责处理用户请求和生成相应的相应部分,然后在页面或其它类型文档中显示。也可以理解为视图是MVC架构里面的C部分(控制器),主要处理功能和业务上的逻辑。

  下面是视图函数的return相应类型:

相应类型 说明
HttpResponse('Hello world') HTTP状态码200,请求已成功被服务器接收
HttpResponseRedirect('/admin/')

HTTP状态码302,重定向Admin站点的URL

HttpResponsePermanentRedirect('/admin/') HTTP状态码301,永久重定向Admin站点的URL
HttpResponseBadRequest('BadRequest') HTTP状态码400,访问的页面不存在或者请求错误
HttpResponseNotFound('NotFound') HTTP状态码404,网页不存在或网页的URL失效
HttpResponseNotForbidden('NotFound') HTTP状态码403,没有访问权限
HttpResponseNotAllowed('NotAllowedGet') HTTP状态码405,不允许使用该请求方式
HttpResponseServerError('ServerError') HTTP状态码500,服务器内部错误

  响应类型代表HTTP状态码,其核心作用是WEB Server服务器用来告诉客户端当前的网页请求发生了什么事,或者当前Web服务器的响应状态。上述响应主要来自于django.http,该模块是实现响应功能的核心。在实际开发中,可以使用该模块实现文件下载功能,在index的urls.py和views.py中分别添加一下代码:

#urls.py代码
path('download.html',views.download), #views.py代码
import csv def download(request):
response = HttpResponse(content_type='text/csv')
response['Content-Disposition'] = 'attachment; filename="somefilename.csv"'
writer = csv.writer(response)
writer.writerow(['First row', 'A', 'B', 'C'])
return response

  上述文件下载功能说明如下:

    1、当接收用户的请求后,视图函数download首先定义HttpResponse的相应类型为文件(text/csv)类型,生成response对象。

    2、然后在response对象上定义Content-Disposition,设置浏览器下载文件的名称。attachment设置文件的下载方式,filename为文件名。

    3、最后使用csv模块加载response对象,把数据写入response对象所设置的CSV文件并将response对象返回到浏览器上,从而实现文件下载。运行结果如下图:

http://127.0.0.1:8000/download.html

  django.http除了实现文件下载之外,要使用该模块生成精美的HTML网页,可以在响应内容中编写HTML源码,如HttpResponse('<html><body>...</body></html>')。尽管这是一种可行的方法,但并不符合实际开发。因此,Django在django.http模块上进行封装,从而有了render()、render_to_response()和redirect()函数。

  render()和render_to_response()实现的功能是一致的。render_to_response()自2.0版本依赖已开始启用,并不代表在2.0版本无法使用,只是大部分开发者都使用render()。因此,本书只对render()进行讲解,render()的语法如下:

  render(request, template_name, context = None, content_type = None, status = None, using = None)

  函数render()的参数request和template_name是必须参数,其余的参数是可选参数。各个参数如下:

    1、request:浏览器向服务器发送的请求对象,包含用户信息、请求内容和请求方式等。

    2、template_name:HTML模板文件名,用于生成HTML网页。

    3、context:对HTML模板的变量赋值,以字典格式表示,默认情况下是一个空字典。

    4、content_type:响应数据的数据格式,一般情况下使用默认值即可。

    5、status:HTTP状态码。默认为200

    6、using:设置HTML模板转换生成HTML网页的模板引擎

  项目的templates有index.html模板,这是一个伪华为商城的网页,static用于存放该HTML模板的静态资源。我们在urls.py和views.py中编写如下代码:

TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [os.path.join(BASE_DIR, 'templates'),
#增加如下这一行
os.path.join(BASE_DIR, 'index/templates')]
,
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
},
},
] #在index下面的views.py中修改index函数如下
def index(request):
return render(request, 'index/index.html', context={'title': '首页'}, status=500)

  从视图函数的context={'title':'首页'}可知,将index.html模板变量title的值设为首页,返回的状态码为500。启动项目,运行结果如下:

  除了render函数外,还有redirect()函数。redirect()函数用于实现请求重定向,重定向的链接以字符串的形式表示,链接的地址信息可以支持相对路径和绝对路径,代码如下:

#在index项目下面urls.py中编写如下代码:
path('login.html',views.login) #在index项目下面views.py中的视图函数编写如下代码:
from django.shortcuts import render,redirect def login(request):
#相对路径,代表首页地址
return redirect('/')
#绝对路径,完整的地址信息
#return redirect('http://127.0.0.1:8000/')

  

  4.2  数据可视化

   视图除了接受用户请求和返回响应内容之外,还可以与模型(Model)实现数据交互(操作数据库)。视图相当于一个处理中心,负责接收用户请求,然后根据请求信息读取并处理后台数据,最后生成HTML网页返回给用户。

from django.db import models

# Create your models here.

class Product(models.Model):
id = models.IntegerField(primary_key=True)
name = models.CharField(max_length=50)
type = models.CharField(max_length=20)

  上述代码将Product类和数据表Product构成映射关系,代码只是搭建两者的关系,在数据库中并没有生成相应的数据表。需要通过python manage.py makemigrations创建

#根据models.py生成相关的.py文件,该文件用于创建数据表
python manage.py makemigrations
Tracking file by folder pattern:  migrations
Migrations for 'index':
index\migrations\0001_initial.py
- Create model Product Following files were affected
E:\test5\MyDjango\index\migrations\0001_initial.py
Process finished with exit code 0
#创建数据表
python manage.py migrate
Tracking file by folder pattern:  migrations
Operations to perform:
Apply all migrations: admin, auth, contenttypes, index, sessions
Running migrations:
Applying contenttypes.0001_initial... OK
Applying auth.0001_initial... OK
Applying admin.0001_initial... OK
Applying admin.0002_logentry_remove_auto_add... OK
Applying admin.0003_logentry_add_action_flag_choices... OK
Applying contenttypes.0002_remove_content_type_name... OK
Applying auth.0002_alter_permission_name_max_length... OK
Applying auth.0003_alter_user_email_max_length... OK
Applying auth.0004_alter_user_username_opts... OK
Applying auth.0005_alter_user_last_login_null... OK
Applying auth.0006_require_contenttypes_0002... OK
Applying auth.0007_alter_validators_add_error_messages... OK
Applying auth.0008_alter_user_username_max_length... OK
Applying auth.0009_alter_user_last_name_max_length... OK
Applying auth.0010_alter_group_name_max_length... OK
Applying auth.0011_update_proxy_permissions... OK
Applying index.0001_initial... OK
Applying sessions.0001_initial... OK

  下面是执行完成后,在数据库中可以看到新创建的数据库表

  从图中可以看到Django会默认创建多个数据库表,其中数据表index_product对应index的models.py所定义的Product类,其余的数据表都是Django内置的功能所生成的,主要用于Admin站点、用户认证和Session会话功能。

  下面在数据库表index_product中添加如下所示的数据:

python manage.py shell

#导入数据里的类
In [1]: from index.models import Product

#使用create往数据库里面添加数据
In [2]: Product.objects.create(name='荣耀',type='手机')
Out[2]: <Product: Product object (None)> In [3]: Product.objects.create(name='畅玩',type='手机')
Out[3]: <Product: Product object (None)> In [4]: Product.objects.create(name='华为',type='手机')
Out[4]: <Product: Product object (None)> In [11]: Product.objects.create(name='移动电源',type='通用配件')
Out[11]: <Product: Product object (None)>

  完成数据表的数据添加后,接着将数据表的数据展现在网页上。首先将模板文件index.html左侧导航栏的代码注释掉,然后在同一位置添加Django的模板语法:

{#    <ul id="cate_box" class="lf">#}
{# <li>#}
{# <h3><a href="#">手机</a></h3>#}
{# <p><span>荣耀</span><span>畅玩</span><span>华为</span><span>Mate/P系列</span></p>#}
{# </li>#}
{# <li>#}
{# <h3><a href="#">平板 & 穿戴</a></h3>#}
{# <p><span>平板电脑 </span><span>手环</span><span>手表</span></p>#}
{# </li>#}
{# </ul>#} <ul id="cate_box" class="lf">
{% for type in type_list %}
<li>
<h3><a href="#">{{ type.type }}</a></h3>
<p>
{% for name in name_list %}
{% if name.type == type.type %}
<span>{{ name.name }}</span>
{% endif %}
{% endfor %}
</p>
</li>
{% endfor %}
</ul>

  新添加的代码是Django的模板语法,主要将视图的变量传递给模板,通过模板引擎转换成HTML语言。上述代码使用循环和判断语句对变量进行分析处理,具体的模板语法会在后续的章节中讲解。最后在视图函数中编写代码,将数据表的数据与模板连接起来,实现世界可视化,代码如下:

def index(request):
type_list = Product.objects.values('type').distinct()
name_list = Product.objects.values('name','type')
context = {'title': '首页', 'type_list': type_list, 'name_list': name_list}
return render(request, 'index.html', context=context, status=200)

  上述代码中,视图函数处理流程如下:

    1、type_list用于查询数据表字段type的数据并将数据去重,name_list用于查询数据表字段type和name的全部数据,这两种独特的查询方式都是由Django内置的ORM框架提供的。

    2、将查询所得的数据以字典的数据格式写入变量context中,变量context是render()函数的参数值,其作用是将变量传递给HTML模板。

    3、当HTML模板接收到变量type_list和name_list后,模板引擎解析模板语法并生成HTML文件。运行结果如下:

  从上述例子可以看到,如果想要将数据库的数据展现在网页上,需要由视图、模型和模板共同实现,实现步骤如下:

    1、定义数据模型,以类的方式定义数据表的字段。在数据库创建数据表时,数据表有模型定义的类生成。

    2、在视图导入模型所定义的类,该类也称为数据表对象,Django为数据表对象提供独有的数据操作方法,可以实现数据库操作,从而获取数据表的数据。

    3、视图函数获取数据后,将数据以字典、列表、或对象的方式传递给HTML模板,并由模板引擎接收和解析,最后生成相应的HTML网页。

  提示:

    在上述模板视图函数中,变量context是以字典的形式传递给HTML模板的。在实际开发过程中,如果传递的变量过多,使用变量context时就显得非常冗余,而且不利于日后的维护和更新。因此,使用locals()取代变量context,代码如下:

locals()使用技巧
def index(request):
type_list = Product.objects.values('type').distinct()
name_list = Product.objects.values('name','type')
title = '首页'
return render(request, 'index.html',context=locals(), status=200)

    locals()的使用方法:在视图函数中所定义的变量名一定要与HTML模板的变量名相同才能生效,如视图函数的type_list与HTML模板的type_list,两者的变量名一致才能将视图函数的变量传递给HTML模板。

  4.3  获取请求信息

    视图是用于接收并处理用户的请求信息,请求信息存放在视图函数的参数request中。为了进一步了解参数request的属性,在PyCharm中使用debug模式启动项目,并在视图函数中设置断点功能,然后查看request对象的全部属性:

                        参数request的属性

  从图中可以看到参数request的属性,这代表用户的请求信息,以下是开发过程中常用的属性:

属性 说明 实例
COOKIES 获取客户端(浏览器)Cookie信息 data = request.COOKIES
FILES                                             字典对象,包含所有的上传文件。该字典有三个键:filename为上传文件的文件名;content-type为上传文件的类型;content为上传文件的原始内容 file = request.FILES
GET 获取GET请求的请求参数,以字典形式存储 //如{'name':'TOM'}request.POST.get('name')
META 获取客户端的请求头信息,以字典形式存储 //获取客户端的IP地址request.META.get('REMOTE_ADDR')
POST 获取POST请求的请求参数,以字典形式存储 //如{'name':'TOM'}request.POST.get('name')
method 获取该请求的请求方式(GET获POST请求) data = request.method
path 获取当前请求的URL地址 path = request.path
user 获取当前请求的用户信息 //获取用户名name = request.user.username

   上述属性中的GET、POST和method是每个Web开发人员必须掌握的基本属性,属性GET和POST用于获取用户的请求参数,属性method用户获取用户的请求方式。以视图函数login为例:

#index/urls.py下面添加如下路由
path('login.html', views.login), #index/views.py添加如下内容
def login(request):
if request.method == 'POST':
name = request.POST.get('name')
#绝对路径,完整的地址信息
#return redirect('http://127.0.0.1:8000/')
#相对地址,代表首页地址
return redirect('/')
else:
if request.GET.get('name'):
name = request.GET.get('name')
else:
name = 'Everyone'
return HttpResponse('username is' + name)

  视图函数login分别使用了属性GET、POST和method,说明如下:

    1、首先使用method用户的请求方式进行判断,一般情况下,用户打开浏览器访问某个URL地址都是GET请求;而在网页上输入信息并点击某个按钮时,以POST请求居多,如用户登录、注册等。

    2、若判断请求方式为POST(GET),则通过属性POST(GET)来获取用户提交的请求参数。不同的请求方式需要使用不同的属性来获取用户提交的请求参数。

  在浏览器上分别输入以下URL地址:

    http://127.0.0.1:8000/index/login.html

    http://127.0.0.1:8000/index/login.html?name=Tom

  第二条URL地址多出了?name=Tom,这是GET请求的请求参数。GET请求参数以?为标识,请求参数以等值的形式表示,等号前面的是参数名,后面的是参数值,如果涉及多个参数,每个参数之间用&拼接。运行结果如下:

    

    

    运行结果如图

  

  4.4  通用视图

  通用视图是通过定义和声明类的形式实现的,根据用途划分为三大类:TemplateView、ListView和DetailView。三者说明如下:

      1、TemplateView直接返回HTML模板,但无法将数据库的数据展示出来。

      2、ListView能将数据库的数据传递给HTML模板,通常获取某个表的所有数据。

      3、DetailView能将数据库的数据传递给HTML模板,通常获取数据表的单条数据。

    根据4.2节实现的功能,我们将其视图函数改用ListView实现。例如:

#index/urls.py下修改地址信息

#通用视图ListView
path('index/',views.ProductList.as_view()),

  如果URL所指向的处理程序是由通用视图执行,那么在编写URL时,URL所指向的处理程序应当是一个通用视图,并且该通用视图上必须使用as_view()方法。因为通用视图实质上是一个类。使用as_view()方法相当于对类进行实例化并由类方法as_view()执行处理。最后在views.py中编写通用视图ProductList的代码,代码如下:

# 通用视图
from django.views.generic import ListView
class ProductList(ListView):
# context_object_name设置Html模版的变量名称
context_object_name = 'type_list'
# 设定HTML模版
template_name='index.html'
# 查询数据
queryset = Product.objects.values('type').distinct() # 重写 get_queryset 方法,对模型product进行数据筛选。
def get_queryset(self):
# 获取URL的变量id
print(self.kwargs['id'])
# 获取URL的参数name
print(self.kwargs['name'])
# 获取请求方式
print(self.request.method)
type_list = Product.objects.values('type').distinct()
return type_list # 添加其他变量
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['name_list'] = Product.objects.values('name','type')
return context

  通用视图ProductList的代码说明如下:

    1、定义ProductList类,该类继承自ListView类,具有ListView的所有特性。

    2、context_object_name设置HTML模板的变量

    3、template_name设置HTML模板的变量

    4、queryset查询数据库数据,查询结果会赋值给context_object_name所设置的变量

    5、重写函数get_queryset,该函数的功能与queryset实现的功能一致

    6、重写函数get_context_data,该函数设置HTML模板的其他变量。

  通用视图的代码编写规则有一定的固定格式,根据这个固定格式可以快速开发数据视图。除此之外,通用视图还可以获取URL的参数和请求信息,使得通用视图更加灵活,以get_queryset函数为例:

#在index模块urls.py下面路径
path('index/<id>.html', views.ProductList.as_view(), {'name':'phone'}), #在index模块views.py下面添加下面函数
#通用视图ProductList类
def get_queryset(self):
#获取URL的变量id
print(self.kwargs['id'])
#获取URL的参数name
print(self.kwargs['name'])
#获取请求方式
print(self.request.method)
type_list = Product.objects.values('type').distinct()
return type_list

  上述代码演示了如何在通用视图中获取URL的参数变量和用户的请求信息,代码说明如下:

    1、首先对URL设置变量id和参数name,这两者设置方式都是日常开发中经常使用的。

    2、通用视图在处理用户请求时,URL的变量和参数都会存放在通用视图的属性kwargs中,因此使用self.kwargs['xxx']可以获取变量值或参数值,xxx代表变量(参数)名。

    3、要获取用户请求信息,可以从属性self.request中获取。self.request和视图函数的参数request的使用方法是一致的。http://127.0.0.1:8000/index/index/5.html运行结果如下图:

  从上面的例子可以看出,通用视图的代码量感觉比视图函数多,但是通用视图是可以被继承的。假如已经写好了一个基于类的通用视图,若要对其添加扩展功能,只需继承原本这个类即可。如果写的是视图函数,其扩展性就没有那么灵活,可能需要使用装饰器等高级技巧,或者重新编写新的视图函数,而且新函数的部分代码与原本函数的代码相同。

  

  4.5  本章小结

  视图是Django的MTV架构模式的V部分,主要负责处理用户请求和生成相应的响应内容,然后在页面或其他类型文档中显示。也可以理解为视图是MVC架构里面的C部分(控制器),主要处理功能和业务上的逻辑。

  视图函数完成请求处理后,必须通过return方式返回数据内容给用户,常用的返回方式由render()、render_to_response()和redirect()函数实现。其中,render()he render_to_response()实现的功能是一致的。render_to_sponse()自2.0版本以来已开始被弃用,并不代表在2.0无法使用,只是大部分开发者都使用render()。

  render()的参数request和template_name是必须参数,其余的参数是可选参数。参数说明如下:

    1、request:浏览器向服务器发送的请求对象,包含用户信息、请求内容和请求方式等。

    2、template_name:HTML模板文件名,用于生成HTML网页。

    3、context:对HTML模板的变量赋值,以字典格式表示,默认情况下是一个空字典。

    4、content_type:响应数据的数据格式,一般情况下使用默认值即可。

    5、status:HTTP状态码,默认为200。

    6、using:设置HTML模板转换生成HTML网页的模板引擎。

  如果想要将数据库的数据展现在网页上,需要有视图、模型和模板共同实现,实现步骤如下:

    1、定义数据模型,以类的方式定义数据表的字段。在数据库创建数据表时,数据表由模型中定义的类生成。

    2、在视图中导入模型所定义的类,该类也称为数据表对象,Django为数据表对象提供独有的的数据操作方法,可以实现数据库操作,从而获取数据表的数据。

    3、视图函数获取数据后,将数据以字典、列表或对象的方式传递给HTML模板,并有模板引擎接受和解析,最后生成相应的HTML网页。

  用户的请求信息都存放在视图函数的参数request中,其中属性GET、POST和method是每个web开发人员必须掌握的基本属性,属性GET和POST用于获取用户的请求参数,属性method用于获取用户的请求方式。

  通用视图是通过定义和声明类的形式实现的,根据用途划分为三大类:TemplateVieW、ListView和DetailView。三者说明如下:

    1、TemplateView直接返回HTML模板,但无法将数据库的数据展示出来。

    2、ListView能将数据库的数据传递给HTML模板,通常获取某个表的所有数据。

    3、DetailView能将数据库的数据传递给HTML模板,通常获取数据表的单条数据。

玩转Django2.0---Django笔记建站基础四(视图)的更多相关文章

  1. 玩转Django2.0---Django笔记建站基础十三(第三方功能应用)

    第13章 第三方功能应用 在前面的章节中,我们主要讲述Django框架的内置功能以及使用方法,而本章主要讲述Django的第三方功能应用以及使用方法.通过本章的学习,读者能够在网站开发过程中快速开发网 ...

  2. django笔记 - 建站

    1,建站步骤:1)django-admin.exe startproject mysite 创建完后的目录结构: - mysite # 对整个程序进行配置 - init - settings # 配置 ...

  3. <玩转Django2.0>读书笔记:URL规则和视图

    1. 带变量的URL #urls.py from django.urls import path from .view import * urlpatterns = [ path('',index_v ...

  4. 玩转Django2.0---Django笔记建站基础十二(Django项目上线部署)

    第十二章 Django项目上线部署 目前部署Django项目有两种主流方案:Nginx+uWsGI+Django或者Apache+uWSGI+Django.Nginx作为服务器最前端,负责接收浏览器的 ...

  5. 玩转Django2.0---Django笔记建站基础十(二)(常用的Web应用程序)

    10.3 CSRF防护 CSRF(跨站请求伪造)也成为One Click Attack或者Session Riding,通常缩写为CSRF或者XSRF,是一种对网站的恶意利用,窃取网站的用户信息来制作 ...

  6. 玩转Django2.0---Django笔记建站基础十(一)(常用的Web应用程序)

    第十章 常用的Web应用程序 Django为开发者提供了常见的Web应用程序,如会话控制.高速缓存.CSRF防护.消息提示和分页功能.内置的Web应用程序大大优化了网站性能,并且完善了安全防护机制,而 ...

  7. 玩转Django2.0---Django笔记建站基础六(模型与数据库)

    第六章 模型与数据库 Django对各种数据库提供了很好的支持,包括:PostgreSQL.MySQL.SQLite和Oracle,而且为这些数据库提供了统一的调用API,这些API统称为ORM框架. ...

  8. 玩转Django2.0---Django笔记建站基础五(模板)

    第五章 模板 Django作为web框架,需要一种很便利的方法去动态地生成HTML网页,因此有了模板这个概念.模板包含所需HTML的部分代码以及一些特殊语法 Django可以配置一个或多个模板引擎(甚 ...

  9. 玩转Django2.0---Django笔记建站基础十一(二)((音乐网站开发))

    11.5 歌曲排行榜 歌曲排行榜是通过首页的导航链接进入的,按照歌曲的播放次数进行降序显示.从排行榜页面的设计图可以看到,网页实现三个功能:网页顶部搜索.歌曲分类筛选和歌曲信息列表,其说明如下: 1. ...

随机推荐

  1. 相似文本文档分析之SimHash算法

    Simhash算法: Simhash算法由Google的Charikar提出,是将一篇文档转化为n位的签名,通过比较签名的相似度来计算原文档的相似度.签名越相近,则文档越相近.因此,整个过程就不会涉及 ...

  2. Linux 内核 struct device 设备

    在最低层, Linux 系统中的每个设备由一个 struct device 代表: struct device { struct device *parent; struct kobject kobj ...

  3. 解决IDEA下tomcat启动server乱码

    亲测成功的方式: 配置TOMCAT时,在VM  opthions 添加 -Dfile.encoding=UTF-8

  4. 学习Java第五周

    通过这一段时间的学习发现Java和C++虽然都是面向对象的编程语言,有相似之处也有不同之处,相似的地方总会感觉易于接受,不同之处或者新接触的有些知识不是很好理解和掌握. 前一段时间学的内部类和接口便是 ...

  5. Dubbo-本地Bean测试

    Dubbo本地测试API的Bean 一.建立一个测试类文件 二.测试API // 自己要测试的API public static final XxApi xxApi; 三.注入Bean static ...

  6. Excel单元格的日常操作

    通过右键选择插入来移动单元格 灵活的运用"整行" 与 "整列" 选中区域之后 通过点击区域边框进行移动 按住shift之后框会变成线 更容易拖动 按住ctrl拖 ...

  7. 算法复杂度之 空间复杂度(Java)

    0.说明 根据算法书上的定义,一个算法的空间复杂度包括算法程序所占用的空间,输入初始数据所占用的空间以及算法执行过程中所需要的额外空间.本文各种结论全部参考过标准文献,本人也进行过验证.验证过程本文不 ...

  8. dos2unix命令 – 将DOS格式的文本文件转换成UNIX格式

    今天做题的时候,出现了个很冷门的: 查找子目录src下所有后缀为.txt的文件执行dos2unix命令,把文件从Dos格式转换为Linux格式,正确的命令是:find src "*.txt& ...

  9. 使用vue-baidu-map解析geojson

    这是后台给我的gejson: {"type":"FeatureCollection","features":[{"type&quo ...

  10. 《C++Primer》第五版习题答案--第二章【学习笔记】

    C++Primer第五版习题解答---第二章 ps:答案是个人在学习过程中书写,可能存在错漏之处,仅作参考. 作者:cosefy Date: 2020/1/9 第二章:变量和基本类型 练习2.1: 类 ...