首页 > 其他分享 >【11.0】Django框架之视图层

【11.0】Django框架之视图层

时间:2024-03-18 23:15:10浏览次数:466  
标签:return get 11.0 self request 视图 Django def view

【一】三板斧

【1】HttpResponse

  • HttpResponse 是 Django 中用于创建 HTTP 响应对象的类,它允许你构建并返回服务器对客户端请求的数据和状态。
  • 当需要直接返回纯文本数据(如 JSON 格式的数据)或者 HTML 页面时,可以使用 HttpResponse
from django.http import HttpResponse

def simple_view(request):
    data = {"message": "Hello, world!"}
    content = json.dumps(data)  # 将字典转换为 JSON 字符串
    response = HttpResponse(content, content_type="application/json")
    return response
  • 在这个例子中,视图函数 simple_view 创建了一个包含 JSON 数据的响应。

【2】render

  • render 函数是 Django 的模板渲染机制的一部分,通常与模板引擎(如 Django 的默认模板引擎 - Jinja2 或者其它支持的模板引擎)一起使用。
  • 当你想要返回带有动态内容的 HTML 页面时,可以使用 render 函数将请求的数据与预定义的 HTML 模板结合起来:
from django.shortcuts import render
from .models import MyModel  # 假设有一个名为 MyModel 的模型

def detail_view(request, pk):
    obj = MyModel.objects.get(pk=pk)
    context = {'object': obj}  # 将模型实例添加到上下文(context)
    return render(request, 'my_template.html', context)
  • 在这个例子中,视图函数 detail_view 使用 render 函数从数据库获取 MyModel 实例,并将其作为参数传递给名为 my_template.html 的 HTML 模板进行渲染,最终返回给客户端。

【3】redirect

  • redirect 函数用于实现网页间的重定向,即将用户从当前 URL 引导向另一个 URL。
  • 它不返回任何内容,而是引发一个 HTTP Redirection 错误,迫使客户端发送一个新的请求到指定地址:
from django.shortcuts import redirect

def login_required_view(request):
    if not request.user.is_authenticated:
        return redirect('login')  # 重定向到登录页面
    # 如果已登录,继续执行后续操作...
  • 在这个例子中,如果用户未登录,login_required_view 视图会调用 redirect 函数将用户重定向至名为 'login' 的URL对应的视图(通常是登录页面)。
  • 如果用户已登录,则继续执行原视图中的其他逻辑。

【二】JsonResponse

  • 路由配置
from django.contrib import admin
from django.urls import path
from app01 import views

urlpatterns = [
    path('admin/', admin.site.urls),
    path('json_data/', views.json_data),
]

【1】json模块序列化

import json
from django.shortcuts import HttpResponse

def json_data(request):
    user_dict = {
        "username": "dream你好",
        'age': 18,
        'password': 123123,
    }

    # 先转成JSON格式字符串
    # ensure_ascii:中文不编码
    json_str = json.dumps(user_dict, ensure_ascii=False)

    # 然后将该字符串返回
    return HttpResponse(json_str)

【2】JsonResponse对象

(1)问题引入

  • 返回的页面展示的数据中,中文字符被强制编码了,如何解决?
from django.http import JsonResponse
  • 源码分析
class JsonResponse(HttpResponse):

    def __init__(self, data, encoder=DjangoJSONEncoder, safe=True,
                 json_dumps_params=None, **kwargs):
        if safe and not isinstance(data, dict):
            raise TypeError(
                'In order to allow non-dict objects to be serialized set the '
                'safe parameter to False.'
            )
        if json_dumps_params is None:
            json_dumps_params = {}
        kwargs.setdefault('content_type', 'application/json')
        # 数据序列化发生在这里
        data = json.dumps(data, cls=encoder, **json_dumps_params)
        super(JsonResponse, self).__init__(content=data, **kwargs)

  • 通过分析源码我们可以发现数据表被序列化的位置
  • 其中 有一个参数 **json_dumps_params
    • 这个参数意思是将数据打散传入到前面的方法中

(2)解决方案

def ab_json(request):
    user_dict = {
        "username": "dream你好",
        'age': 18,
        'password': 123123,
    }
    return JsonResponse(user_dict, json_dumps_params={'ensure_ascii': False})
  • 将我们需要的参数以字典的形式传进去

(3)其他数据类型序列化

  • 我们不仅有字典格式的数据可以被序列化也有其他操作
  • 例如列表
def ab_json(request):
    user_dict = {
        "username": "dream你好",
        'age': 18,
        'password': 123123,
    }
    user_list = [11, 22, 33, 44, 55, 66, 77, 88, 99]

    return JsonResponse(user_list, json_dumps_params={'ensure_ascii': False})
  • 我们在访问数据的时候会提示下面的错误
In order to allow non-dict objects to be serialized set the safe parameter to False.
  • 我们按照提示加上需要的参数
def ab_json(request):
    user_dict = {
        "username": "dream你好",
        'age': 18,
        'password': 123123,
    }
    user_list = [11, 22, 33, 44, 55, 66, 77, 88, 99]

    return JsonResponse(user_list, safe=False, json_dumps_params={'ensure_ascii': False})

  • JsonResponse在序列化字典以外的数据格式时,会有一个安全设置,我们将参数修改即可修改数据

【二】form表单文件上传下载

form表单上传数据以及后端如何获取

【0】form知识回顾

<form action="" method="post" enctype="multipart/form-data"></form>
  • form表单想要上传文件类型的数据
    • method 参数必须改为post
    • enctype 参数必须指定成 form-data 类型

【1】数据准备

  • 路由urls.py
from django.contrib import admin
from django.urls import path
from app01 import views

urlpatterns = [
    path('admin/', admin.site.urls),
    # form 表单上传 下载文件
    path('file_upload/', views.file_upload),
]
  • 前端file.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.7.1/jquery.min.js"></script>
    <link href="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet">
    <script src="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/3.3.7/js/bootstrap.min.js"></script>

</head>
<body>
<form action="" method="post" enctype="multipart/form-data" class="form form-control">
    <p>username:<input type="text" name="username" class="form-control"></p>
    <p>file:<input type="file" name="file" class="form-control"></p>
    <input type="submit">
</form>
</body>
</html>

【2】数据处理

(1)POST请求数据

  • csrf报错,记得注释掉中间件
def file_upload(request):
    if request.method == 'POST':
        # 只能获取到普通的文本数据,无法获取到文件数据
        print(request.POST)
    return render(request, 'file.html')
<QueryDict: {'username': ['dream']}>
  • 通过这种方式,我们只能获取到我们输入的文本数据,而拿不到我们想要的文件数据

(2)文件数据获取

def file_upload(request):
    if request.method == 'POST':
        # 获取文件数据
        print(request.FILES) 
        # <MultiValueDict: {'file': [<InMemoryUploadedFile: img.png (image/png)>]}>
        
        # 提取文件数据 - 文件对象
        file_obj = request.FILES.get('file')
        # 提取文件名字 file_obj.name
        with open(file_obj.name, 'wb') as f:
            # 逐行读取文件数据
            # 官方推荐 加上 chunks 方法 等价于 一行行获取
            for line in file_obj.chunks():
                f.write(line)
    return render(request, 'file.html')
<MultiValueDict: {'file': [<InMemoryUploadedFile: img.png (image/png)>]}>

【三】总结request对象方法

【1】request.method

  • request.method:该方法返回客户端用于发起请求的HTTP方法。
  • 例如,可以是'GET'、'POST'、'PUT'、'DELETE'等。
  • 您可以使用该方法来确定请求的类型,并相应地执行特定操作。

【2】request.POST

  • request.POST:该属性是一个类似字典的对象,包含了请求中通过POST方法发送的所有参数。
  • 这些参数通常是通过HTML表单发送的。
  • 您可以使用参数的名字作为键来访问单个参数,例如request.POST['username']

【3】request.GET

  • request.GET:类似于request.POST,该属性包含了请求中通过GET方法发送的所有参数。
  • 这些参数通常会附加在URL之后,以问号分隔。
  • 您可以使用参数的名字作为键来访问单个参数,例如request.GET['page']

【4】request.FILES

  • request.FILES:该属性是一个类似字典的对象,包含了请求中通过文件上传组件发送的所有文件。
  • 当表单中包含文件上传字段时,通过request.FILES可以访问上传的文件。
  • 您可以使用文件的名字作为键来访问单个文件,例如request.FILES['file']

【5】request.path

只能获取到路由地址,无法获取到参数

  • request.path:该属性表示请求URL中的路径部分。
  • 它包含在域名之后,在任何查询参数之前。
  • 例如,如果请求的URL是"http://example.com/foo/bar/",那么request.path将为"/foo/bar/"。

【6】request.path_info

只能获取到路由地址,无法获取到参数

  • 用于表示请求URL的路径部分,不包括域名和查询参数。
  • request.path 相比,request.path_info 更加原始和未经解析。
  • 它保留了URL路径中的任何编码、特殊字符或斜杠等信息。
  • 例如,对于以下请求URL:"http://example.com/foo/bar/?page=2",request.path_info 的值将是 "/foo/bar/"。
  • 通常情况下,您可以使用 request.path 来获取丢弃域名后的路径,而使用 request.path_info 来获取原始的、未解析的路径。这在某些情况下非常有用,例如当您需要对URL进行一些自定义操作或路由处理时。

【7】request.get_full_path()

即能获取到路由地址又能获取到完整的路由地址后面的参数

  • request.get_full_path():该方法返回请求URL的完整路径,包括路径部分和任何查询参数。
  • 当您需要将完整URL作为字符串使用时,这个方法非常有用。
  • 例如,如果请求的URL是"http://example.com/foo/bar/?page=2",request.get_full_path()将返回"/foo/bar/?page=2"。

【四】FBV与CBV引入

  • 视图函数既可以是函数也可以是类

  • 我们之前写过的都是基于函数的view,就叫FBV。

    • 还可以把view写成基于类的。

【1】FBV

# FBV版添加班级
def add_class(request):
    if request.method == "POST":
        class_name = request.POST.get("class_name")
        models.Classes.objects.create(name=class_name)
        return redirect("/class_list/")
    return render(request, "add_class.html")

【2】CBV

(1)路由

# CBV 路由  -  根据请求方式的不同选择不同的入口动作
path('login/', views.MyLogin.as_view())

(2)视图

from django.views import View


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

    def post(self, request, *args, **kwargs):
        return HttpResponse("post")
  • MBV和CBV各有各的特点,都有应用

  • CBV特点

    • 能够直接根据请求方式的不同直接匹配到对应的方法执行

【3】详解

  • FBV(Function-Based Views)与 CBV(Class-Based Views)是 Django 框架中用于处理视图(Views)的两种不同的编程方式。

(1)Function-Based Views(FBV):

  • FBV 是 Django 最早支持的一种视图编程方式。
  • 使用函数作为视图的处理逻辑。函数参数通常是 request 对象,表示用户发送的 HTTP 请求。
  • 函数内部可以根据请求方法、参数、数据等进行相应的处理,并返回 HttpResponse 对象作为响应。
  • 示例代码:
    from django.http import HttpResponse
    
    def my_view(request):
        # 处理逻辑
        if request.method == 'GET':
            # 处理 GET 请求
            return HttpResponse('Hello, GET Request!')
        elif request.method == 'POST':
            # 处理 POST 请求
            return HttpResponse('Hello, POST Request!')
    

(2)Class-Based Views(CBV):

  • CBV 是 Django 提供的另一种视图编程方式,引入了面向对象的概念。
  • 使用类来表示视图,并使用类中的方法来处理不同类型的HTTP请求。
  • Django 提供了许多内置的 CBV 类,可以方便地扩展和重写这些类来实现自定义功能。
  • 示例代码:
    from django.http import HttpResponse
    from django.views import View
    
    class MyView(View):
        def get(self, request):
            # 处理 GET 请求
            return HttpResponse('Hello, GET Request!')
    
        def post(self, request):
            # 处理 POST 请求
            return HttpResponse('Hello, POST Request!')
    

(3)小结

  • 选择使用 FBV 还是 CBV 取决于具体的需求和个人偏好。
  • FBV 相对简单直观,适合编写简单的视图逻辑;
  • 而 CBV 可以通过继承和重写类来实现代码复用和可扩展性,适用于复杂的视图处理场景。
  • 在实际开发中,可以根据需求选择适合的方式来编写视图处理函数或类。

【五】CBV源码剖析

【1】as_view 方法

(1)路由 对应 函数内存地址

path('login/', views.MyLogin.as_view()),

方法/函数名 加 括号 执行优先级最高

  • 可能的原因

    • 要么是被@staicmethod方法修饰的静态方法
    • 要么是被@classmethod方法修饰的类方法
  • 查看源码

    • 绑定给类的静态方法,将类作为第一个参数传进去
	@classonlymethod
    def as_view(cls, **initkwargs):
        """
        Main entry point for a request-response process.
        """
        for key in initkwargs:
            if key in cls.http_method_names:
                raise TypeError("You tried to pass in the %s method name as a "
                                "keyword argument to %s(). Don't do that."
                                % (key, cls.__name__))
            if not hasattr(cls, key):
                raise TypeError("%s() received an invalid keyword %r. as_view "
                                "only accepts arguments that are already "
                                "attributes of the class." % (cls.__name__, key))

        def view(request, *args, **kwargs):
            self = cls(**initkwargs)
            if hasattr(self, 'get') and not hasattr(self, 'head'):
                self.head = self.get
            self.request = request
            self.args = args
            self.kwargs = kwargs
            return self.dispatch(request, *args, **kwargs)
        view.view_class = cls
        view.view_initkwargs = initkwargs

        # take name and docstring from class
        update_wrapper(view, cls, updated=())

        # and possible attributes set by decorators
        # like csrf_exempt from dispatch
        update_wrapper(view, cls.dispatch, assigned=())
        return view
  • view 这是一个闭包函数

    • 返回值是这个闭包函数的内存地址
  • 在启动Django项目时,就会立刻执行as_view方法

path('login/', views.view()),
  • 方法类似FBV方法

总结:CBV和FBV在路由匹配上本质上是一样的,都是路由 对应 函数内存地址

(2)view 方法剖析

    def view(request, *args, **kwargs):
        # 参数 cls 就是我们自己写的类
        self = cls(**initkwargs)
        # 等价于 self = MyLogin(**initkwargs) ---- 产生一个我们自己写的类的对象
        if hasattr(self, 'get') and not hasattr(self, 'head'):
            self.head = self.get
        # 给我们的对象赋值属性
        self.request = request
        self.args = args
        self.kwargs = kwargs
        '''
        在看python源码的时候,一定要时刻注意面向对象属性方法查找顺序
            先从对象自己找
            再去产生对象的类里面找
            之后再去父类找
        总结:在看源码时,如果遇到 self.x 操作时,一定要时刻注意当前这个self到底是谁
         '''
        return self.dispatch(request, *args, **kwargs)
 http_method_names = ['get', 'post', 'put', 'patch', 'delete', 'head', 'options', 'trace']

    # CBV 的 精髓 !!!
    def dispatch(self, request, *args, **kwargs):
        # Try to dispatch to the right method; if a method doesn't exist,
        # defer to the error handler. Also defer to the error handler if the
        # request method isn't on the approved list.
        # 获取当前请求的小写格式 然后比对当前请求方式是否合法
        # 以 get 请求为例
        if request.method.lower() in self.http_method_names:
            '''
            反射:通过字符串来操作对象的属性或方法
            '''
            # self 是我们自己写的类产生的对象
            # handler = getattr(自己写的类产生的对象,'get',当找不到get属性或方法时就会用到第三个参数)
            # 因为我们在自己的类里面重写了 get 方法 ,所以这里的 handler 就变成了我们自己写的 get方法
            # handler = 我们自己写的类里面的get方法
            handler = getattr(self, request.method.lower(), self.http_method_not_allowed)
        else:
            handler = self.http_method_not_allowed

        # 自动调用 get 方法
        return handler(request, *args, **kwargs)

(3)小结

path('login/', views.MyLogin.as_view()),
  • 当我们启动Django项目时
  • 会自动触发路由中的方法,调用 as_view 方法并自执行
  • 在执行后我们查看 as_view 方法的源码 发现
    • 在依次给我们的对象赋值后,最终返回了一个自执行的 dispatch 方法
  • 于是我们又去查看了 dispatch 方法
    • 在 dispatch 内部 ,先是将请求方式转换并进行校验
    • 然后开始校验需要调用的方法的调用位置,校验成功并拿到需要执行的方法执行
  • 在自己写的类中如果有相关的方法,会首先调用我们重写的类方法,并返回执行结果
    • 如果自己的类里面没有该方法 会去自己的父类中调用 父类的方法
      • 如果父类 以及 基类 都找不到则报错,抛出异常

【六】给视图加装饰器

【1】使用装饰器装饰FBV

  • FBV本身就是一个函数,所以和给普通的函数加装饰器无差:
def wrapper(func):
    def inner(*args, **kwargs):
        start_time = time.time()
        ret = func(*args, **kwargs)
        end_time = time.time()
        print("used:", end_time-start_time)
        return ret
    return inner


# FBV版添加班级
@wrapper
def add_class(request):
    if request.method == "POST":
        class_name = request.POST.get("class_name")
        models.Classes.objects.create(name=class_name)
        return redirect("/class_list/")
    return render(request, "add_class.html")

【2】使用装饰器装饰CBV

  • 类中的方法与独立函数不完全相同,因此不能直接将函数装饰器应用于类中的方法 ,我们需要先将其转换为方法装饰器。
  • Django中提供了method_decorator装饰器用于将函数装饰器转换为方法装饰器。
# CBV版添加班级
from django.views import View
from django.utils.decorators import method_decorator

def wrapper(func):
    def inner(*args, **kwargs):
        start_time = time.time()
        ret = func(*args, **kwargs)
        end_time = time.time()
        print("used:", end_time-start_time)
        return ret
    return inner
  
class AddClass(View):

    @method_decorator(wrapper)
    def get(self, request):
        return render(request, "add_class.html")

    def post(self, request):
        class_name = request.POST.get("class_name")
        models.Classes.objects.create(name=class_name)
        return redirect("/class_list/")

【3】CBV的拓展

  • 使用CBV时要注意,请求过来后会先执行dispatch()这个方法
  • 如果需要批量对具体的请求处理方法,如get,post等做一些操作的时候,这里我们可以手动改写dispatch方法,这个dispatch方法就和在FBV上加装饰器的效果一样。
class Login(View):
     
    def dispatch(self, request, *args, **kwargs):
        print('before')
        obj = super(Login,self).dispatch(request, *args, **kwargs)
        print('after')
        return obj
 
    def get(self,request):
        return render(request,'login.html')
 
    def post(self,request):
        print(request.POST.get('user'))
        return HttpResponse('Login.post')

标签:return,get,11.0,self,request,视图,Django,def,view
From: https://www.cnblogs.com/dream-ze/p/18081716

相关文章

  • Laravel11.0.3安装完后运行项目报错
    Laravel11.0.3安装完后运行项目报错:couldnotfinddriver(Connection:sqlite,SQL:PRAGMAforeign_keys=ON;)运行项目报错时提示链接sqlite错误解决方案:1.确认机器安装了sqlite,https://blog.csdn.net/centaury32/article/details/1367885202.启动sqlite......
  • 【Django开发】0到1美多商城项目md教程第2篇:展示用户注册页面,1. 创建用户模块子应用
    美多商城完整教程(附代码资料)主要内容讲述:欢迎来到美多商城!,项目准备。展示用户注册页面,创建用户模块子应用。用户注册业务实现,用户注册前端逻辑。图形验证码,图形验证码接口设计和定义。短信验证码,避免频繁发送短信验证码。账号登录,用户名登录。登录,登录开发文档。用户基本信息,查询......
  • Docker部署Django项目——基础
    1.服务器配置1.1centos7系统的安装centos-7-isos-x86_64安装包下载)VMware安装自定义配置选择对应的系统镜像一般选择内核4核、内存8g、硬盘80g相关配置1.2.网络配置1.2.1查看win电脑虚拟机VMnet8的ip使用ipconfig查看虚拟机的ip1.2.2配置虚拟机VMne......
  • Django生命周期
    Django请求的生命周期是指:当用户在浏览器上输入url到用户看到网页的这个时间段内,Django后台所发生的事情。一、生命周期流程图首先,用户在浏览器中输入url,发送一个GET/POST方法的request请求。Django中封装了socket的WSGi服务器,监听端口接受这个request请求再进行初步......
  • mysql 存储过程 视图 理解参考
    存储过程(StoredProcedure): 存储过程是一组预编译的SQL语句和控制结构的集合,类似于程序中的子例程或函数。存储过程可以接受参数,并且可以在执行过程中进行条件判断、循环和其他逻辑控制。存储过程通常用于封装和重用复杂的数据库操作,可以执行一系列的SQL语句,进行数据处理、业......
  • 基于Django高校校园二手书籍交易系统设计与实现(Pycharm+Python+Mysql)
     博主介绍:黄菊华老师《Vue.js入门与商城开发实战》《微信小程序商城开发》图书作者,CSDN博客专家,在线教育专家,CSDN钻石讲师;专注大学生毕业设计教育和辅导。所有项目都配有从入门到精通的基础知识视频课程,学习后应对毕业设计答辩。项目配有对应开发文档、开题报告、任务书、P......
  • Django基础知识点二
    Django基础知识点二【一】分页器【1】关键参数current_page:当前所在页数start_data:起始数据end_data:结束数据per_count:每一页展示的数据all_count:所有数据数量page_count:总页数:divmod(all_count,per_count)current_page(per_count=5)start_dataend_data......
  • 基于Django旅游景区景点订票系统设计与实现(Pycharm+Python+Mysql)
     博主介绍:黄菊华老师《Vue.js入门与商城开发实战》《微信小程序商城开发》图书作者,CSDN博客专家,在线教育专家,CSDN钻石讲师;专注大学生毕业设计教育和辅导。所有项目都配有从入门到精通的基础知识视频课程,学习后应对毕业设计答辩。项目配有对应开发文档、开题报告、任务书、P......
  • django重庆工商大学校园车辆管理系统(源码+mysql+论文)
    本系统(程序+源码)带文档lw万字以上 文末可获取本课题的源码和程序系统程序文件列表系统的选题背景和意义选题背景:随着科技的不断发展,信息化已经成为了现代社会的一种趋势。在校园中,车辆管理作为一项重要的工作,其效率和准确性对于保障校园安全和秩序具有重要意义。重庆工......
  • django中医共享管理系统设计(源码+mysql+论文)
    本系统(程序+源码)带文档lw万字以上 文末可获取本课题的源码和程序系统程序文件列表系统的选题背景和意义选题背景:随着科技的发展,互联网技术已经深入到各个领域,医疗行业也不例外。中医作为中国传统的医学,其独特的诊疗方式和理论体系在全世界都有一定的影响力。然而,中医的......