Django中的视图

Django之视图

​  一个视图函数(类),简称视图,是一个简单的python函数(类),它接收web请求并返回web响应。响应可以是一个网页的HTML内容,一个重定向,一个404错误,一个XML文档,或者一张图片。

​  无论视图本身包含什么逻辑,都要返回响应。代码写在哪里无所谓,只要它在你当前项目目录下面,除此之外,没有更多的要求了。

​  为了将代码放在某处,大家约定俗成将视图放置在项目(project)或应用程序(app)目录中的名为views.py的文件当中。

1. 一个简单的视图

以下是一个以HTML文档的形式返回当前日期和时间的视图:

from django.http import HttpResponse
import datetime

def current_datetime(request):
    now = datetime.datetime.now()
    html = "<html><body>It is now %s.</body></html>" % now
    return HttpResponse(html)

让我们来逐行解释下上面的代码:

  • 首先,我们从 django.http模块导入了HttpResponse类,以及Python的datetime库。

  • 接着,我们定义了current_datetime函数。它就是视图函数。每个视图函数都使用HttpRequest对象作为第一个参数,并且通常称之为request

    注意,视图函数的名称并不重要;不需要用一个统一的命名方式来命名,以便让Django识别它。我们将其命名为current_datetime,是因为这个名称能够比较准确地反映出它实现的功能。

  • 这个视图会返回一个HttpResponse对象,其中包含生成的响应。每个视图函数都负责返回一个HttpResponse对象。

Django使用请求和响应对象来通过系统传递状态。

当浏览器向服务端请求一个页面时,Django创建一个HttpRequest对象,该对象包含关于请求的元数据。然后,Django加载相应的视图,将这个HttpRequest对象作为第一个参数传递给视图函数。

每个视图负责返回一个HttpResponse对象。

2. FBV和CBV

定义

  FBV(function based view):基于函数的视图

  CBV(class based view):基于类的视图

区别

​  FBV:把所有的处理逻辑都写在函数中,在函数中判断前端发来的请求方式时POST还是GET,然后执行对应的逻辑

​  CBV:在一个CBV的视图中,将不同请求的方法分别定义成类下面的不同函数;这样前端发来的请求执行类中对应的函数即可

2.1 FBV

FBV视图

from django.shortcuts import render,redirect,reverse
from app01 import models

# 增加出版社
def publisher_add(request):
    # POST请求方式的处理逻辑
    if request.method == 'POST':
        pub_name = request.POST.get('pub_name')    # key名对应input标签中name字段的值
        if not pub_name:
            return render(request,'publisher_add.html',{'error':'输入不能为空'})
        ret = models.Publisher.objects.create(name=pub_name)    # 返回的是新插入的对象
        # 跳转至展示页面
        return redirect(reverse('app01:pub'))
      
		# GET请求处理逻辑
    return render(request,'publisher_add.html') # get请求的处理逻辑

URLconf

url(r'^/publisher/add/$',views.publisher_add,name="pub_add"),

2.2 CBV

CBV视图

from django.shortcuts import render,redirect,reverse
from app01 import models
from django.views import View	# 需要导入View基类,进行继承 

class PublisherAdd(View):
    # 处理GET请求的逻辑
    def get(self,request,*args,**kwargs):
        return render(request, 'publisher_add.html')  # get请求的处理逻辑

    # 处理POST请求的逻辑
    def post(self,request,*args,**kwargs):
        pub_name = request.POST.get('pub_name')    # key名对应input标签中name字段的值
        if not pub_name:
            return render(request,'publisher_add.html',{'error':'输入不能为空'})
        ret = models.Publisher.objects.create(name=pub_name)    # 返回的是新插入的对象
        # 跳转至展示页面
        return redirect(reverse('app01:pub'))

URLconf

使用CBV时,URLconf的写法也要有所变化

url(r'^/publisher/add/$',views.PublisherAdd.as_view(),name="pub_add"),

3. 给视图加装饰器

3.1 使用装饰器装饰FBV

如给publisher_list视图函数加一个计算函数执行所用时间的装饰器

from app01 import models
from django.views import View
import time
from functools import wraps

def timmer(func):
    @wraps(func)
    def inner(*args,**kwargs):
        start = time.time()
        ret = func(*args,**kwargs)
        print('{}函数执行的时间是:{}'.format(func.__name__,time.time()-start))
        return ret
    return inner

@timmer
def publisher_list(request):
    # 查询所有的出版社对象
    all_publishers = models.Publisher.objects.all()

    # 将结果返回给页面
    return render(request,'publisher_list.html',{'all_publishers':all_publishers})

访问publisher_list.html页面之后,触发publisher_list函数,后台打印内容如下

publisher_list函数执行的时间是:0.015687942504882812

3.2 使用装饰器装饰CBV

​ 类中的方法与独立函数不完全相同,因此不能直接将函数装饰器应用与类中的方法,我们需要先将其转化为方法装饰器

​ Django中提供了method_decorator装饰器用于将函数装饰器转换为方法装饰器:通过from django.utils.decorators import method_decorator推荐使用

CBV添加装饰器的方法有三种,如下(另,仍引用上述的timmer装饰器)

1)加在方法上
from django.shortcuts import render,redirect,reverse
from app01 import models
from django.views import View
import time
from functools import wraps
from django.utils.decorators import method_decorator

def timmer(func):
    @wraps(func)
    def inner(*args,**kwargs):
        start = time.time()
        ret = func(*args,**kwargs)
        print('{}函数执行的时间是:{}'.format(func.__name__,time.time()-start))
        return ret
    return inner

class PublisherAdd(View):
    # 处理GET请求的逻辑
    @method_decorator(timmer)
    def get(self,request,*args,**kwargs):
        return render(request, 'publisher_add.html')  # get请求的处理逻辑

    # 处理POST请求的逻辑
    @method_decorator(timmer)
    def post(self,request,*args,**kwargs):
        # 获取提交的数据
        pub_name = request.POST.get('pub_name')    # key名对应input标签中name字段的值

        # 校验提交数据是否为空
        if not pub_name:
            return render(request,'publisher_add.html',{'error':'输入不能为空'})
        # 插入数据库
        print(pub_name,type(pub_name))  # 太空出版社 <class 'str'>

        ret = models.Publisher.objects.create(name=pub_name)    # 返回的是新插入的对象
        print(ret,type(ret))    # Publisher object <class 'app01.models.Publisher'>
        # 跳转至展示页面
        return redirect(reverse('app01:pub'))

触发PublisherAdd逻辑中的GET与POST请求,后台打印结果如下:

bound_func函数执行的时间是:0.0005960464477539062
[11/Feb/2020 15:43:42] "GET /app01/publisher/add/ HTTP/1.1" 200 338
[11/Feb/2020 15:43:47] "POST /app01/publisher/add/ HTTP/1.1" 200 356
bound_func函数执行的时间是:0.0006589889526367188
2)加在dispath方法上
  1. 自己在类中写dispath方法,继承父类等dispath

    class PublisherAdd(View):
        # 处理GET请求的逻辑
        @method_decorator(timmer)
        def dispatch(self, request, *args, **kwargs):
            ret = super().dispatch(request,*args,**kwargs)
            return ret
    
        def get(self,request,*args,**kwargs):
            return render(request, 'publisher_add.html')  # get请求的处理逻辑
    
        # 处理POST请求的逻辑
        def post(self,request,*args,**kwargs):
            # 获取提交的数据
            pub_name = request.POST.get('pub_name')    # key名对应input标签中name字段的值
    
            # 校验提交数据是否为空
            if not pub_name:
                return render(request,'publisher_add.html',{'error':'输入不能为空'})
            # 插入数据库
            print(pub_name,type(pub_name))  # 太空出版社 <class 'str'>
    
            ret = models.Publisher.objects.create(name=pub_name)    # 返回的是新插入的对象
            print(ret,type(ret))    # Publisher object <class 'app01.models.Publisher'>
            # 跳转至展示页面
            return redirect(reverse('app01:pub'))
    

    触发PublisherAdd逻辑中的GET与POST请求,后台打印结果如下:

    bound_func函数执行的时间是:0.0013780593872070312
    [11/Feb/2020 15:48:47] "GET /app01/publisher/add/ HTTP/1.1" 200 338
    [11/Feb/2020 15:48:51] "POST /app01/publisher/add/ HTTP/1.1" 200 356
    bound_func函数执行的时间是:0.0006721019744873047
    
  2. 直接通指定加在dispath方法上

    @method_decorator(timmer,name='dispatch')
    class PublisherAdd(View):
        # 处理GET请求的逻辑
    
        def get(self,request,*args,**kwargs):
            return render(request, 'publisher_add.html')  # get请求的处理逻辑
    
        # 处理POST请求的逻辑
        def post(self,request,*args,**kwargs):
            # 获取提交的数据
            pub_name = request.POST.get('pub_name')    # key名对应input标签中name字段的值
    
            # 校验提交数据是否为空
            if not pub_name:
                return render(request,'publisher_add.html',{'error':'输入不能为空'})
            # 插入数据库
            print(pub_name,type(pub_name))  # 太空出版社 <class 'str'>
    
            ret = models.Publisher.objects.create(name=pub_name)    # 返回的是新插入的对象
            print(ret,type(ret))    # Publisher object <class 'app01.models.Publisher'>
            # 跳转至展示页面
            return redirect(reverse('app01:pub'))
    

    触发PublisherAdd逻辑中的GET与POST请求,后台打印结果如下:

    bound_func函数执行的时间是:0.0013499259948730469
    [11/Feb/2020 15:52:11] "GET /app01/publisher/add/ HTTP/1.1" 200 338
    bound_func函数执行的时间是:0.0006899833679199219
    [11/Feb/2020 15:52:13] "POST /app01/publisher/add/ HTTP/1.1" 200 356
    
3)加在类上
@method_decorator(timmer,name='get')
@method_decorator(timmer,name='post')
class PublisherAdd(View):
    # 处理GET请求的逻辑

    def get(self,request,*args,**kwargs):
        return render(request, 'publisher_add.html')  # get请求的处理逻辑

    # 处理POST请求的逻辑
    def post(self,request,*args,**kwargs):
        # 获取提交的数据
        pub_name = request.POST.get('pub_name')    # key名对应input标签中name字段的值

        # 校验提交数据是否为空
        if not pub_name:
            return render(request,'publisher_add.html',{'error':'输入不能为空'})
        # 插入数据库
        print(pub_name,type(pub_name))  # 太空出版社 <class 'str'>

        ret = models.Publisher.objects.create(name=pub_name)    # 返回的是新插入的对象
        print(ret,type(ret))    # Publisher object <class 'app01.models.Publisher'>
        # 跳转至展示页面
        return redirect(reverse('app01:pub'))

触发PublisherAdd逻辑中的GET与POST请求,后台打印结果如下:

[11/Feb/2020 15:54:20] "GET /app01/publisher/add/ HTTP/1.1" 200 338
bound_func函数执行的时间是:0.0005879402160644531
[11/Feb/2020 15:54:23] "POST /app01/publisher/add/ HTTP/1.1" 200 356
bound_func函数执行的时间是:0.0006330013275146484

注意推荐使用method_decorator

4. request对象

​  当一个页面被请求时,Django就会创建一个包含本次请求元信息的HttpRequest对象。

​  Django会将这个对象自动传递给响应的视图函数,一般视图函数约定俗成地使用request参数承接这个对象。

《官方文档连接》

​  也就是说,一次请求的所有信息都被封装在了HttpRequest对象中,而在Django中通过request参数接收此对象,想要获取什么信息,直接从这个参数中获取即可。

4.1 request属性

常用的属性

request.method			# 获取请求方法 GET POST
request.GET					# 获取url上的查询参数 /dd/?id=1&name=tom	注:与请求方式无关
request.POST				# 获取post请求方法提交的数据 {k1:v1,k2:v2}		前端常用form表单提交,urlencode
request.path_info		# 返回当前路径信息,不包含IP、端口和参数 /app01/publisher/add/
request.body				# 获取请求提byte类型 b'pub_name=China%E5%87%BA%E7%89%88%E7%A4%BE'
request.COOKIES			# 获取cookie的数据
request.session			# 获取session数据
request.FILES				# 获取上传的文件
request.META				# 获取头信息

​  如上,即request的常用属性,当然除此之外还有其他属性,此处不一一列举,有需要可参考官方文档即可:https://docs.djangoproject.com/en/1.11/ref/request-response/

此处需要注意的是

​  1. Django将请求报文中的请求行、头部信息、内容主体封装成HttpRequest类中的属性

​  2. 所有属性应该被认为是只读的,除非另有说明

文件上传示例

HttpRequest.Files
		一个类似于字典的对象,包含所有的上传文件信息。
  	FILES 中的每个键为<input type="file" name="" /> 中的name,值则为对应的数据。
		
    注意,FILES 只有在请求的方法为POST 且提交的<form> 带有enctype="multipart/form-data" 的情况下才会
包含数据。否则,FILES 将为一个空的类似于字典的对象。
def upload(request):
    """
    保存上传文件前,数据需要存放在某个位置。默认当上传文件小于2.5M时,django会将上传文件的全部内容读进内存。从内存读取一次,写磁盘一次。
    但当上传文件很大时,django会把上传文件写到临时文件中,然后存放到系统临时文件夹中。
    :param request: 
    :return: 
    """
    if request.method == "POST":
        # 从请求的FILES中获取上传文件的文件名,file为页面上type=files类型input的name属性值
        filename = request.FILES["file"].name
        # 在项目目录下新建一个文件
        with open(filename, "wb") as f:
            # 从上传的文件对象中一点一点读
            for chunk in request.FILES["file"].chunks():
                # 写入本地文件
                f.write(chunk)
        return HttpResponse("上传OK")

4.2 request方法

  1. HttpRequest.get_host()

    获取主机的IP与端口信息,例如 127.0.0.1:8000

  2. HTTPRequest.get_full_path()

    获取路径信息,与path_info属性对比,ge t_full_path方法包含请求参数

  3. HttpRequest.is_secure()

    判断请求是否安全,如果请求是安全的,则返回True;即请求是通过HTTPS发起的

  4. HttpRequest.is_ajax()

    判断请求是否是ajax请求,如果是则返回True,否则返回False

注意

​   以上仅常用方法介绍,其他方法学习可参考官网

5. response对象

​  与由Django自动创建的 HttpRequest对象相比,HttpResponse对象是我们的职责范围了。我们写的每个视图都需要实例化,填充和返回一个HttpResponse。

5.1 使用方法

传递字符串

from django.http import HttpResponse
response = HttpResponse("this is a test page")
response = HttpResponse("Text only, please.", content_type="text/plain")

设置或删除响应头信息

response = HttpResponse()
response['Content-Type'] = 'text/html; charset=UTF-8'
del response['Content-Type']

5.2 response的属性

HttpResponse.content			# 响应内容

HttpResponse.charset			# 响应内容的编码

HttpResponse.status_code	# 响应的状态吗

6. JsonResponse对象

JsonReponse是HttpResponse的子类,专门用来生成JSON编码的响应,相当于将json转换和响应的动作的封装

例如,前后端分离项目,前后端仅靠json格式数据进行交互

from django.http.response import JsonResponse

def json_data(request):
    msg = {'name':'tom','age':18}
    return JsonResponse(msg)	# Content-Type: application/json

在这里插入图片描述

默认只能传递字典类型,如果要传递非字典类型(如列表)需要设置一下safe关键字参数

response = JsonResponse([1, 2, 3], safe=False)

7. Django shortcut functions

《官方文档连接》

from django.shortcuts import render,redirect,reverse

7.1 render

1)render函数定义
def render(request, template_name, context=None, content_type=None, status=None, using=None):
    """
    Returns a 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)

可知:render方法,结合一个给定的模版和一个给定的上下文字典,并返回一个渲染后的HttpResponse对象

2)参数介绍
  • request:用于生成响应的请求对象
  • template_name:要使用的模版文件的完整名称,可选的参数
  • context:添加到模版上下文的一个字典。默认是一个空字典。如果字典中的某个值是可调用的,视图将在渲染模版之前调用它
  • content_type:生成的文档要使用的MIME类型。默认为DEFAULT_CONTENT_TYPE设置的值。默认为"text/html"
  • status:响应的状态码。默认为200
  • useing:用于家在模版的模版引擎的名称
3)使用示例
from django.shortcuts import render

def my_view(request):
    # 视图的代码写在这里
    return render(request, 'myapp/index.html', {'foo': 'bar'})

上述代码等价于:

from django.http import HttpResponse
from django.template import loader

def my_view(request):
    # 视图代码写在这里
    t = loader.get_template('myapp/index.html')
    c = {'foo': 'bar'}
    return HttpResponse(t.render(c, request))

7.2 redirect

redirect重定向本质:就是响应头 Location:地址

1)redirect函数定义
def redirect(to, *args, **kwargs):
    """
    Returns an HttpResponseRedirect to the appropriate URL for the arguments
    passed.

    The arguments could be:

        * A model: the model's `get_absolute_url()` function will be called.

        * A view name, possibly with arguments: `urls.reverse()` will be used
          to reverse-resolve the name.

        * A URL, which will be used as-is for the redirect location.

    By default issues a temporary redirect; pass permanent=True to issue a
    permanent redirect
    """
    if kwargs.pop('permanent', False):
        redirect_class = HttpResponsePermanentRedirect
    else:
        redirect_class = HttpResponseRedirect

    return redirect_class(resolve_url(to, *args, **kwargs))
2)参数介绍

其中redirect函数的参数可以为如下:

  • 一个模型:将调用模型的get_absolute_url()函数
  • 一个视图,可以带有参数:将使用urlresolvers.reverse来反向解析名称
  • 一个绝对的或相对的URL,将原封不动的作为重定向的位置

默认返回一个临时的重定向;传递Permanent=True可以返回一个永久的重定向

3)使用示例

有多种方式来使用redirect函数

传递一个具体的ORM对象

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

传递一个视图的名称

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

传递要重定向到的一个具体的网址

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

传递要重定向到的一个完整的网址

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

默认情况下,redirect返回一个临时重定向,以上所有的形式都接收一个permanent参数;如果设置为True,将返回一个永久的重定向

def my_view(request):
    ...
    object = MyModel.objects.get(...)
    return redirect(object, permanent=True)  

扩展

​ 临时重定向(响应状态吗:302)和永久重定向(响应状态吗:301)对普通用户来说是没什么区别的,它主要是面向的是搜索引擎的机器人。

​ A页面临时重定向到B页面,那么搜索引擎收录的就是A页面;

​ A页面永久重定向到B页面,那么搜索引擎收录的就是B页面。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值