Django的视图详解


视图的基本概念

在Django框架中,视图是指一个Python函数或类,它处理来自客户端的请求,并返回相应的响应。视图可以处理各种类型的请求,如GET、POST、PUT、DELETE等。视图通常用于渲染HTML模板、查询数据库、处理表单数据等。视图是Django框架中最重要的组成部分之一,因为它们负责处理来自客户端的请求,然后返回相应的响应。

在前面的内容中已经提到,创建视图可以通过视图函数和视图类两种方式。

视图函数是一个Python函数,它接收一个HttpRequest类型的参数,并返回一个HttpResponse类型的响应。

from django.http import HttpResponse

def index(request):
    return HttpResponse("视图函数")

视图类是一个Python类,它继承自Django框架的View类,并实现了View类中定义的方法。视图类通常用于创建复杂的视图。

from django.views import View
from django.http import HttpResponse

class IndexView(View):
    def get(self, request):
        return HttpResponse("视图类")

限制请求method装饰器

Django内置的视图装饰器可以给视图提供一些限制,比如某个视图只能通过GET的方式访问。

  • django.views.decorators.http.require_http_methods,这个装饰器需要传递一个允许访问的方法的列表。
  • django.views.decoratorshttp.require_GET,这个装饰器相当于是require_http_methods(['GET'])的简写形式,只允许GET的方式来访问视图。
  • django.views.decoratorshttp.require_POST,这个装饰器相当于是require_http_methods(['POST'])的简写形式,只允许POST的方式来访问视图。
  • django.views.decoratorshttp.require_safe,这个装饰器相当于是require_http_methods(['GET','HEAD'])的简写形式,只允许使用相对安全的方式来访问视图。(GET和HEAD不会对服务器产生增删改的行为,相对安全的请求方式)。
from django.http import HttpResponse
from django.shortcuts import render
from .models import Article
from django.views.decorators.http import require_http_methods

@require_http_methods(["GET", "POST"])
def add_article(request):
    if request.method == "GET":
        return render(request, "add_article.html")
    else:
        title = request.POST.get("title")
        content = request.POST.get("content")
        Article.objects.create(title=title, content=content)
        return HttpResponse("success")

WSGIRequest对象

Django在接收到http请求之后,会根据http请求携带的参数以及报文信息创建一个WSGIRequset对象,并且作为视图函数第一个参数传递给视图函数。这个对象完整的路径是django.core.handlers.wsgi.WSGIRequest

from django.http import HttpResponse

def index(request):
    print(request)
    print(type(request))
    return HttpResponse('index')
<WSGIRequest: GET '/index/'>
<class 'django.core.handlers.wsgi.WSGIRequest'>

WSGIRequest对象常用属性

WSGIRequest对象上大部分的属性都是只读的,因为这些属性是从客户端上传过来的,没有必要做任何修改。

  • path:请求服务器的完整路径,但不包括域名和参数。比如上面的例子,只是‘http://127.0.0.1:8000/index/’中的‘/index/’;
  • method:代表当前请求的http方法,GET、POST等;
  • GET:一个django.http.request.QueryDict对象。操作起来类似于字典。这个属性中含了所有以?xxx=xxx的参数;
  • POST:一个django.http.request.QueryDict对象。这个属性包含了所有以POST方式发送的参数;
  • FILES:一个django.http.request.QueryDict对象。这个属性中包含了所有上传的文件;
  • COOKIES:一个标准的Python字典,包含所有的cookie,键值对都是字符串类型;
  • session:一个类似于字典的对象,用来操作服务器的session;
  • META:存储的客户端发送的所有header信息;
    • CONTENT_LENGTH:请求的正文的长度;
    • CONTENT_TYPE:请求的正文的MIME类型;
    • HTTP_ACCEPT:响应可接收的Content-Type;
    • HTTP_ACCEPT_ENCODING:响应可接收的编码;
    • HTTP_ACCEPT_LANGUAGE:响应可接收的语言;
    • HTTPS_HOST:客户端发送的HOST值;
    • HTTP_REFERER:在访问这个页面上一个页面的url;
    • QUERY_STRYING:单个字符串形式的查询字符串;
    • REMOTE_ADDR:客户端的IP地址;
    • REMOTE_HOST:客户端的主机名;
    • REQUEST_METHOD:请求方法,一个字符串类似于GET或POST;
    • SERVER_NAME:服务器域名;
    • SERVER_PORT:服务器端口号。

WSGIRequest对象常用方法

  • is_secure():是否采用https协议;
  • is_ajax():是否采用ajax发送请求。原理就是判断请求头中是否存在X-Requested-With:XMLHttpRequest
  • get_host():服务器的域名。如果在访问的时候还有端口号,那么会加上端口号;
  • get_full_path(): 返回完整的path。如果有查询字符串,也会加上查询字符串;
  • get_raw_uri():获取请求的完整url。

QueryDict对象

经常用到的request.GETrequest.POST都是QueryDict对象,这个对象继承自dict,因此用法跟dict差不多。其中用得比较多的是get方法和getlist方法。

  • get():用来获取指定key的值,如果没有这个key,那么会返回None;

    name = request.GET['name']		# 若没有取到name的值,将报错:django.utils.datastructures.MultiValueDictKeyError: 'name'
    
    尽量不要使用上面的方式,而是使用GET.get()的形式进行获取
    
    name = request.GET.get('name')		# 若没有取到name的值,返回None
  • getlist():如果浏览器上传过来的key对应的值有多个,name就需要通过这个方法获取。

HttpResponse对象

Django服务器接收到客户端发送过来的请求后,会将提交上来的这些数据封装成一个HttpRequest对象传给视图函数。视图函数在处理完相关的逻辑后,也需要返回一个响应结果给浏览器。而这个响应结果,必须返回HttpResponseBase对象或者它的子类的对象。HttpResponseHttpResponseBase用得最多的子类。

HttpResponse对象常用属性

  • content:返回的内容;
  • status_code:返回的HTTP响应状态码;
  • content_type:返回的数据的MIME类型,默认是text/html。浏览器会根据这个属性来显示数据。如果是text/html,就会解析这个字符串,如果是text/plain,就会显示一个纯文本。常用的Content-Type如下:
    • text/html(默认的,html文件)
    • text/plain(纯文本)
    • text/css(css文件)
    • text/javascript(js文件)
    • multipart/form-data(文件提交)
    • application/json(json传输)
    • application/xml(xml文件)
  • 设置请求头:response['X-Access-Token'] = 'xxxx'
def index(request):
    # print(request)
    # print(type(request))
    response = HttpResponse()
    response1 = HttpResponse("<h1>AILynn</h1>", content_type='text/html;charset=utf-8')
    response.content = "plscript"
    print(response.status_code)
    response1['X-Token'] = 'plscript'
    return response1

HttpResponse对象常用方法

  • set_cookie:用来设置cookie信息;
  • delete_cookie:用来删除cookie信息;
  • writeHttpResponse是一个类似于文件的对象,可以用来写入数据到数据体(content)中。

JsonResponse类

用来将对象dump成json字符串,然后将字符串封装成Response对象返回给浏览器,对应的Content-Type是application/json。默认情况下JsonResponse只能对自定进行dump,如果想要对非字典的数据进行dump,需要给JsonResponse传递一个safe=False参数。

import json
from django.http import HttpResponse, JsonResponse

def jsonresponse_view(request):
    user = {
        "name": "艾琳",
        "age": 18,
    }
    # user_json = json.dumps(user, ensure_ascii=False)
    # response = HttpResponse(user_json, content_type="application/json")
    # return response
    response = JsonResponse(user, json_dumps_params={'ensure_ascii': False})
    return response

这里需要注意,python讲数据保存为json格式时,默认情况下会将非ASCII字符(比如中文)转换为Unicode编码的转义序列。这种转换时通过设置ensure_ascii=True来实现的。若要显示为原始的字符,可以通过将ensure_ascii=True来实现。

类视图

View

django.views.generic.base.View是主要的类视图,所有的类视图都是继承自他。我自己设计的类视图,也可以继承他,然后再根据当前请求的method,来实现不同的方法。

from django.http import HttpResponse
from django.views.generic import View


def index(request):
    return HttpResponse("success")


class BookListView(View):
    def get(self, reqeust, *args, **kwargs):
        return HttpResponse("book list")
     
class AddBookView(View):
    def get(self, request, *args, **kwargs):
        return HttpResponse("get success")

    def post(self, request, *args, **kwargs):
        book_name = request.POST.get("name")
        book_author = request.POST.get("author")
        print("name:{},author:{}".format(book_name, book_author))
        return HttpResponse("post success")

与之对应的路由

from django.urls import path
from . import views

urlpatterns = [
    path('index/', views.index, name='index'),
    path('book_list/', views.BookListView.as_view(), name="book_list"),
		path('add_book/', views.AddBookView.as_view(), name="add_book"),
]

需要注意的是,在配置路由时,对应函数视图时,是视图的名称不加括号。而对应类视图时,是视图类名加.as_view(),需要加上括号。

如果用户访问了View中没有定义的方法,比如只支持get方法,而调用了post方法,那么可以在代码中增加http_method_not_allowed(request, *args, **kwargs)去处理

class AddBookView(View):
    def get(self, request, *args, **kwargs):
        return HttpResponse("get success")

    def http_method_not_allowed(self, request, *args, **kwargs):
        return HttpResponse("您当前发送的是:%s请求,当前视图不支持!" % request.method)

其实不管是get请求还是post请求,都会去调用dispatch(request, *args, **kwargs)方法,也就是实现了这个方法,将能够对所有请求都处理到。

给类视图添加装饰器

前面的函数视图可以通过装饰器进行修饰实现增多的功能,类视图也可以添加装饰器。

  1. 装饰dispatch方法
from django.shortcuts import render, redirect, reverse
from django.http import HttpResponse
from django.views.generic import View
from django.utils.decorators import method_decorator

def login_required(func):
    def wrapper(request, *args, **kwargs):
        username = request.GET.get('username')
        if username:
            return func(request, *args, **kwargs)
        else:
            return redirect(reverse('login'))

    return wrapper


def login(request):
    return HttpResponse('book:login')


class ProfileView(View):

    def get(self, request, *args, **kwargs):
        return HttpResponse("个人信息页面")

    @method_decorator(login_required)
    def dispatch(self, request, *args, **kwargs):
        return super(ProfileView, self).dispatch(request, *args, **kwargs)
  1. 直接装饰类

def login_required(func):
    def wrapper(request, *args, **kwargs):
        username = request.GET.get('username')
        if username:
            return func(request, *args, **kwargs)
        else:
            return redirect(reverse('login'))

    return wrapper


def login(request):
    return HttpResponse('book:login')


@method_decorator(login_required, name='dispatch')
class ProfileView(View):

    def get(self, request, *args, **kwargs):
        return HttpResponse("个人信息页面")

文章作者: 老百
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 老百 !
 上一篇
阿里云ECS服务器部署记录 阿里云ECS服务器部署记录
之前购买的阿里云服务器即将到期,续费很昂贵。购买了新服务器,重新部署并迁移数据到新服务器上。
2023-11-01
下一篇 
Djang的ORM详解 Djang的ORM详解
对象关系映射(Object Relational Mapping,简称ORM)。简单的说就是用面向对象的方式,描述数据库,操作数据库,达到不用编写SQL语句就能对数据库进行增删改查等操作。
2023-10-19
  目录