Python Web开发Django框架视图应用指导

内容导读

  1. 关于视图
  2. 请求与响应对象
  3. 模板响应对象
  4. 生成响应的快捷方式
  5. 类视图
  6. 通用视图

一、关于视图

Python的Django框架中,视图用于处理HTTP请求,并返回响应数据,实现前后端的交互。

下面看一下视图的基本结构:

def view_name(request, *arg = None, **kwargs = None):
    代码段
    return HttpResponse(response)

view_name:表示视图名称。

request:必选参数,接收请求对象(HttpRequest类的实例)。

args和kwargs:可选参数,用于接收URL中的额外参数。

返回值是返回的响应对象(HttpResponse类或其子类的实例)。

视图本质上是一个Python函数。

在应用的views.py文件中,定义一个返回当前日期和时间的视图curr_time()。

from django.http import HttpResponse
import datetime
def curr_time(request):
    now = datetime.datetime.now()
    # 视图将页面的样式以硬编码形式写在了代码中。
    response = "<html><body>It is %s.</body></html>" % now
    return HttpResponse(response)

将页面的样式以硬编码形式写在视图代码中会造成两个问题:

Django提倡将页面样式放在模板文件之中,在视图文件中使用上下文字典向模板传递数据。

(1)将视图curr_time()中的样式代码放在time.html中,具体代码如下。

<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8">
    <title>当前时间</title>
  </head>
  <body>
    It is {{now}} .
  </body>
</html>

(2)修改views.py文件中的视图函数代码。

def curr_time(request):
    t = loader.get_template("time.html")  # 加载模板
    now = datetime.datetime.now()   # 获取当前时间
    context = {	                  # 上下文字典
        'now': now,
    }
    response = t.render(context, request)  # 渲染模板
    return HttpResponse(response)

二、请求与响应对象

2.1 请求对象HttpRequest

请求对象由Django自动创建,由视图的request参数接收,Django项目中所有请求的处理都离不开请求对象。

请求对象是HttpRequest类的实例,该对象中封装了HTTP请求。

HttpRequest的常用属性一:

HttpRequest的常用属性二:

QueryDict:

HttpRequest对象的GET与POST属性都获取一个QueryDict对象,QueryDict就是字典的子类,它实现了字典的所有方法。QueryDict与字典唯一的区别是,它的一个键可以对应多个值。

2.2 响应对象HttpResponse

1、HttpResponse类

创建请求对象的工作由Django完成,但创建响应对象是开发人员的工作,开发人员编写的每个视图中都需实现响应对象的实例化、填充和返回。响应对象是HttpResponse类或其子类的实例,这些类都定义在django.http模块中。

HttpResponse类的常用属性:

使用HttpResponse类创建响应对象的简单方式是传递一个字符串(该字符串将作为页面的内容呈现)到HttpResponse类的构造函数。

response1 = HttpResponse("Here's the text of the Web page.")
response2 = HttpResponse("Text only, please.", content_type="text/plain")
response3 = HttpResponse(b'Bytestrings are also accepted.')

HttpResponse类的构造函数也可接收一个可迭代对象。HttpResponse()接收到可迭代对象后,立刻以字符串形式存储可迭代对象中的内容,并废弃可迭代对象。

响应对象创建后,可使用write()方法向其中追加内容。

response = HttpResponse()
response.write("<p>Here's the text of the Web page.</p>")
response.write("<p>Here's another paragraph.</p>")

Django支持以类似字典操作的方式增加和删除响应消息中的字段。

response = HttpResponse()
response['Age'] = 120		# 增加字段Age
del response['Age']		# 删除字段Age

需要注意的是,与字典不同,若要删除的字段不存在,Django不会抛出KeyError异常;若HTTP字段值中包含换行符,Django会抛出BadHeaderError异常。

2、HttpResponse的子类

HttpResponse有很多子类,其中HttpResponseDirect和JsonResponse是HttpResponse类的两个重要子类。

(1)HttpResponseRedirect

创建HttpResponseRedirect对象时必须将用来重定向的URL作为第一个参数传给构造方法,这个URL可以是完整的链接,也可以是不包含域名的绝对路径或相对路径。

return HttpResponseRedirect("http://example.com/")	 # 链接
return HttpResponseRedirect("/search/")		 # 绝对路径
return HttpResponseRedirect("search/")		 # 相对路径

需要注意HttpResponseRedirect只支持硬编码链接,不能直接使用URL名称。若要使用URL名称,需要先使用反向解析方法reverse()解析URL。

(2)JsonResponse

JSON是Web开发中常用的数据格式,视图函数常常需要返回JSON类型的响应。HttpResponse的子类JsonResponse能更方便地实现此项功能。

from django.http import JsonResponse 
def json_view(request):
response = JsonResponse({'foo':'bar'},safe = False)
         return response

当json_view()视图被调用时,页面会显示JSON数据“{'foo':'bar'}”。

默认情况下,JsonResponse只能转储dict类型的数据,若要转储非dict数据,需要将其参数safe设置为False。

from django.http import JsonResponse 
def json_view(request):
	response = JsonResponse(['coding', 'fish'],safe = False)
	return response

HttpResponse也能满足返回JSON类型响应的需求,但在返回之前需要先调用json.dumps()将数据转储为JSON字符串。

(3)其他HttpResponse的子类

三、模板响应对象

标准HttpResponse对象是静态结构,它在构造时被提供有预设样式的内容,虽然可以修改这些内容以生成不同的响应,但修改这些内容并不容易。Django.template.response模块定义了TemplateResponse以解决这一问题。

1、TemplateResponse

TemplateResponse类接收给定的模板、上下文、内容类型、HTTP状态和字符集以生成TemplateResponse对象。

TemplateResponse类的构造方法声明如下:

TemplateResponse.__init__(request,template,context = None,
content_type = None,status = None,charset = None,using = None)

request:当前视图函数接收到的请求对象。

template:接收模板对象、模板名称或模板名称列表。

context:接收一个用于填充模板上下文的dict类型的数据,默认为None。

content_type:HTTP响应信息头部包含的值,用于设置MIME类型和字符集的编码。

charset:响应使用的编码格式。

using:加载模板时使用的模板引擎的名称。

常用属性:

常用方法:

2、模板响应对象的渲染

TemplateResponse对象在被返回之前必须先经过渲染,渲染的本质是将模板与上下文结合,生成字节流。

一个TemplateResponse对象只能被渲染一次。

在渲染TemplateResponse对象前,TemplateResponse的render()方法会检查is_rendered属性,判断TemplateResponse对象是否需要渲染。

若想强制重新渲染,可以手动为content属性赋值。

# 创建TemplateResponse对象
from django.template.response import TemplateResponse
t = TemplateResponse(request, 'original.html', {})
t.render()
print(t.content)
# 重新调用render()但不改变上下文,仍使用原来的上下文
t.template_name = 'new.html'
t.render()
print(t.content)
# 修改content属性,上下文发生改变
t.content = t.rendered_content
print(t.content)

一些操作(如缓存操作)必须在已渲染的模板上执行,但操作执行时机难以把握,因为真正的渲染过程发生在穿过了某些中间件之后。

当然可以自定义中间件处理逻辑,将逻辑代码放在渲染完成后调用,但所有响应都会穿过的中间件中不应定义某些特有响应的逻辑。

此时可以利用模板响应对象add_post_render_callback()方法,为对象添加回调函数来解决这一问题。

为TemplateResponse对象添加回调函数这一操作在视图中完成。

from django.template.response import TemplateResponse
def my_render_callback(response):
    do_post_processing() 	# 处理过程
def my_view(request):
	……
    # 创建一个响应对象
    response = TemplateResponse(request, 'mytemplate.html', {})
    # 添加回调函数
    response.add_post_render_callback(my_render_callback)
    # 返回响应
    return response

任何可使用HttpResponse的地方都可以使用TemplateResponse对象,例如使用一个模板和包含查询集的上下文返回一个TemplateResponse对象。

from django.template.response import TemplateResponse
def blog_index(request):
    return TemplateResponse(request, 'entry_list.html', 
                                               {'entries': Entry.objects.all()})

四、生成响应的快捷方式

render()函数定义在django.shortcuts模块中,该函数的声明如下:

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

request:请求对象。

template_name:模板名称或模板序列的名称。

context:接收一个用于填充模板上下文的dict类型的数据,默认为None。

content_type:用于指定响应信息的MIME类型,如“text/html; charset = UTF-8”。

status:指定响应的状态码,默认为200。

using:指定加载模板时所用的模板引擎名称。

使用render()函数重写4.1中的视图函数,具体代码如下:

from django.shortcuts import render
def curr_time(request):
         now = datetime.datetime.now()	
         context = {		# 上下文字典
	'now': now,
         }
         return render(request, "time.html",context)

除render()外,shortcuts模块中还定义了快捷方式redirect()、get_object_or_404()、get_list_or_404()。

redirect()函数用于快速返回HttpResponseRedirect对象,该函数的声明如下:

redirect(to, * args, permanent = False, ** kwargs)

默认情况下redirect()生成临时重定向,将它的permanent设置为True后会生成永久重定向。

传入一个模型对象:

from django.shortcuts import redirect
def my_view(request):
    ...
    obj = MyModel.objects.get(...)
    return redirect(obj)

传入相对URL:

def my_view(request):
    ...
    return redirect('/some/url/')

传入一个视图:

def my_view(request):
    ...
    return redirect('some-view-name', 
                             foo='bar')

传入绝对URL:

def my_view(request):
    ...
    return redirect('http://example.com/')

get_object_or_404()是一个非常实用的函数,常与对象查询结合使用。不同的函数返回值对应不同的查询结果:如果查找成功,返回查询集;如果查询失败,返回404页面。

get_object_or_404()函数的语法格式如下:

get_object_or_404(klass, * args, ** kwargs)

klass:可以是一个模型类、Manager或者QuerySet对象

kwargs:用于接收查询参数,查询参数应可应用于get()或filter()方法。

get_list_or_404()函数从模型中提取数据后将其强制转换为列表返回,若数据为空则抛出Http404异常。

from django.shortcuts import get_list_or_404
def my_view(request):
    my_objects = get_list_or_404(MyModel, published=True)

五、类视图

虽然一个视图处理用户的一个请求,但HTTP提供了多种请求方式(GET、POST、PUT等),用户使用应用的某个功能时,该功能可能以任意一种方式发起请求,例如商品管理功能使用GET方式发起的呈现商品列表的请求、使用POST方式发起的修改商品请求等。

此时视图需要结合条件分支,对每种请求方式分别进行处理。然而若所有请求方式的处理逻辑都定义在同一个视图中,视图很可能庞大且臃肿。为了解决这一问题,Django设计了类视图。

1、定义类视图

类视图允许在views.py的一个类中定义不同的方法,以处理同一功能以不同请求方式发送的请求。

以函数形式定义视图:

from django.http import HttpResponse
def my_view(request):
    if request.method == 'GET':
        return HttpResponse('GET result')
    elif request.method == 'POST':
        return HttpResponse('POST result')

以类的形式定义视图:

from django.http import HttpResponse
from django.views import View
class MyView(View):
    def get(self, request):
        return HttpResponse(' GET result')
    def post(self,request):
        return HttpResponse('POST result')

Django的URLconf期望将和请求关联的参数直接传递给可调用的函数而非定义了方法的类,所以URL配置中会调用视图类的as_view()方法。

as_view()方法的功能是接收请求,获取请求方法request.method,并根据request.method返回相应的视图方法。

# urls.py
from django.urls import path
from views import MyView
urlpatterns = [
    path('about/', MyView.as_view()),
]

path()函数在接收到URL“about/”时,会调用MyView类的as_view()方法,根据不同的请求方式执行类视图MyView中的不同请求方法。

2、基础视图类

View是所有类视图的基类之一,具有处理视图与URL之间的映射关系、HTTP方法调度等功能。

除View外,Django还定义两个基础视图类:TemplateView和RedirectView,这两个基础视图类定义在django.views.generic.base模块中,它们可以像View一样被继承与使用。

TemplateView为模板视图类,它结合了模板与视图,可以通过指定视图类使用的模板文件和上下文数据,快速定义一个视图。

RedirectView为重定向视图类,它继承了View类,具有View类提供的所有功能;此外它定义了一些独有的属性和方法,实现了重定向功能。

RedirectView类的常用方法为get_redirect_url(),该方法用于构造重定向的目标URL,它的语法格式如下:

get_redirect_url(self, *args, **kwargs)

get_redirect_url()方法默认使用类的url属性设置的目标URL,若url属性未设置,该方法尝试根据pattern_name属性设置的URL名称,以反向解析的方式匹配URL。

方式一:Python类中定义属性的标准方法

class MoringGreetingView(GreetingView):
    greeting = "G'Day"
    def get(self, request):
        return HttpResponse(self.greeting)
class MoringGreetingView(GreetingView):
    greeting = "G'Day"
    def get(self, request):
        return HttpResponse(self.greeting)

方式二:将类属性配置为as_view()方法的关键字参数

urlpatterns = [
    path('about/',     
    GreetingView.as_view(greeting="G'day")),
]

六、通用视图

通用视图是视图开发中常见任务的抽象,使用通用视图,只需编写少量代码,便可快速开发数据的公共视图。

1、通用视图分类

2、通用视图与模型

将模型作为额外参数传递给通用视图,可以快速开发视图。除了额外接收模型外,基于通用视图的开发流程与基于基础视图的开发流程基本相同。

首先,创建Django项目,在项目中创建应用booklist,在应用的models.py文件中定义模型Publisher和Author,利用通视图呈现数据,代码如下。

class Publisher(models.Model):
    name = models.CharField(max_length=30)
    address = models.CharField(max_length=50)
    city = models.CharField(max_length=60)
    state_province = models.CharField(max_length=30)
    country = models.CharField(max_length=50)
    website = models.URLField()
    class Meta:
        ordering = ["-name"]
    def __str__(self):
        return self.name

在应用的views.py文件中定义一个继承了ListView的视图,来呈现数据库中的出版者信息表,代码如下。

# views.py
from django.views.generic import ListView
from books.models import Publisher
class PublisherList(ListView):
    model = Publisher

在应用的urls.py文件中配置URL,具体代码如下:

urlpatterns = [
    path('publishers/', PublisherList.as_view()),
]

在项目的urls.py文件中配置URL,具体代码如下:

path('', include('booklist.urls')),

在模板目录templates中创建目录booklist,在booklist下创建模板文件publisher_list.html,编写模板代码,遍历上下文对象,在页面上逐条显示数据,具体代码如下:

<h2>Publishers</h2><hr>
<ul>
    {% for publisher in object_list %}
        <li>{{ publisher.name }}</li>
    {% endfor %}
</ul>

3、添加额外的上下文对象

若想获取视图所采用的模型类之外的一些附加信息,例如,在每一个出版者的详情页显示已出版书籍的列表,该如何实现呢?

此时若要实现以上需求,需要对通用视图的数据进行修改。通用视图通过get_context_data()方法返回嵌入模板中的上下文字典,重写该方法。

def get_context_data(self, **kwargs):
        context = super().
                         get_context_data(**kwargs)
        # 将书籍信息的查询集加入上下文对象
        context['book_list'] = Book.objects.all()
        return context

4、通过queryset控制页面内容

之前使用model属性指定了通用视图中使用的数据模型,还可以使用queryset属性指定视图呈现的数据。

from django.views.generic import DetailView
from books.models import Publisher
class PublisherDetail(ListView):
    context_object_name = 'publisher'
    queryset = Publisher.objects.all()

实际上model = Publisher是queryset = Publisher.objects.all()的简写,相比model,queryset对数据的控制更加灵活,它不仅可以获取全部的数据对象,也可以获取排序后的数据、对数据进行过滤等等。

5、重要属性和方法

更多精彩内容请关注本站!

  • 8
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值