0
点赞
收藏
分享

微信扫一扫

低代码开发与数据可视化

东方小不点 1天前 阅读 1

【一】Django框架之生命周期流程图

在这里插入图片描述

【二】三板斧

【1】HttpEesponse

(1)介绍

  • HttpResponse是Django中用于创建HTTP响应的类
  • 当直接要返回纯文本数据(如Json格式数据)或者HTML页面时,都可以使用HttpResponse

(2)属性方法

  • HttpResponse.set_cookie(name, value…):设置响应中的cookie
  • .delete_cookie(name…):删除响应中的cookie
  • .get(value, default=None):获取响应头中指定的值
  • .set_header(key, value):设置响应头中的键值对

(3)示例

from django.http import HttpResponse

def my_view(request):
    content = "Hello, world!"  # 响应内容
    response = HttpResponse(content, status=200, content_type="text/plain")
    return response
  • content:响应的内容,可以是字符串、字节流或可迭代对象。
  • status:响应的状态码,默认为 200(OK)。
  • content_type:响应的内容类型,默认为 “text/html”。
from django.http import HttpResponse

def my_view(request):
    content = "<html><body><h1>Hello, world!</h1></body></html>"
    response = HttpResponse(content, content_type="text/html")
    return response

【2】render

(1)介绍

  • render是Django框架中用于渲染模板并生成最终的响应
  • 当需要返回带有动态信息的HTML页面时,可以使用render函数将请求的数据与定义的模板HTML文件结合起来
  • 看源码可以发现render函数的底层还是HttpResponse

(2)基本语法

from django.shortcuts import render

def my_view(request):
    # 处理逻辑
    return render(request, 'template_name.html', context)
  • request:请求对象,用于获取客户端发送的请求信息
  • template_name:模板文件的名称,可以是字符转或包含多个模板文件的列表
  • context:上下文变量,是一个字典,用于将数据传递给模板

(3)示例

  • 视图函数
from django.shortcuts import render

def index(request):
    context = {'name': "bruce", 'age': 18}
    return render(request, 'index.html', context)
  • 前端模板文件
<p>name: {{ name }}</p>
<p>age: {{ age }}</p>

【3】redict

(1)介绍

  • redict函数用于实现网页间的重定向
    • 将用户当前的URL引导至另一个URL
  • 这个函数没有返回值,而是发送一个HTTP Redirection错误,迫使客户端发送一个新的请求地址
  • 查看源码发现底层还是用的HttpResponse

(2)示例

  • 视图函数
    • 触发这个函数自动跳转至index
from django.shortcuts import redirect

def index(request):
    return HttpRespinse("index")

def my_view(request):
    # 处理逻辑
    return redirect('index')

【三】JsonResponse

【1】回顾Json模块

(1)序列化

  • 使用.dumps函数可以将Python格式转换为Json格式的字符串
    • 其中有个参数ensure_ascii=False
    • 可以取消自动转码
user_dict = {user_dict = {"username": "秦始皇", "age": 100}
with open("01.json", "w", encoding="utf8") as fp:
    json.dump(user_dict, fp=fp)
# {"username": "\u79e6\u59cb\u7687", "age": 100}
}

【2】JsonResponse

(1)序列化

  • 和json一样
    • 可以序列化python格式为json字符串格式并发送到浏览器上
def index(request):
    data = {'name': '秦始皇', 'age': 100}
    return JsonResponse(data)

(2)取消转义

  • 中文可能发生转移,那么接下来研究怎么取消转义

  • 查看源码

    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().__init__(content=data, **kwargs)
  • 分析源码发现使用的还是jason

  • 那么只要想办法把ensure_ascii传入即可

  • 最终发现参数json_dumps_param可以将ensure_ascii=false传进去

  • 所以修改语句

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

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

  • 列表序列化
def index(request):
    user_list = [11, 212, 32]
    return JsonResponse(user_list)
  • 报错
In order to allow non-dict objects to be serialized set the safe parameter to False.
  • 意思为:为了允许序列化非dict对象,请将safe参数设置为False。
  • 那么按照要求改
def index(request):
    user_list = [11, 212, 32]
    return JsonResponse(user_list, safe=False)

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

【1】数据准备

  • 前端登录界面
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <meta name="viewport" content="width=device-width,initial-scale=1.0">
    {% load static %}
    <script src="{% static 'js/jquery-3.5.1.min.js' %}"></script>
    <link rel="stylesheet" href="{% static 'bootstrap-3.4.1-dist/css/bootstrap.min.css' %}">
    <script src="{% static 'bootstrap-3.4.1-dist/js/bootstrap.min.js' %}"></script>

</head>
<body>
<div class="container">
    <div class="row">
        <h1 class="text-center">注册界面</h1>
        <div class="col-md-6 col-md-offset-3">

            <form action="" method="post">
                <p>用户名:<input class="form-control" type="text" name="username" placeholder="username"></p>
                <p>密码:<input class="form-control" type="password" name="password" placeholder="password"></p>
                <p>头像:<input type="file" name="head_jpg"></p>
                <p><input type="submit" class="btn btn-block btn-success"></p>
            </form>
        </div>
    </div>
</div>
</body>
</html>

【2】获取数据

(1)尝试POST直接获取

  • 视图函数
def register(request):
    if request.method == "POST":
        data = request.POST
        print(data)
        username = data.get("username")
        password = data.get("password")
        head_image = data.get("head_image")
        print(head_image, type(head_image))
    return render(request, 'register.html')
  • 结果为图片名称字符串,没有图片数据
<QueryDict: {'username': [''], 'password': [''], 'head_image': ['53efb9d8079c6e4f904ed602f5c1e4e.png']}>
53efb9d8079c6e4f904ed602f5c1e4e.png <class 'str'>

(2)requset.FILES

  • 视图函数
def register(request):
    if request.method == "POST":
        files_data = request.FILES
        print(files_data)
        head_image = files_data.get("head_image")
        print(head_image, type(head_image))
    return render(request, 'register.html')
  • 结果为空
<MultiValueDict: {}>
None <class 'NoneType'>

(3)修改form表单

  • 想要获取文件还需要将表单进行修改
<form action="" method="post" enctype="multipart/form-data">

</form>
  • 刷新再次运行视图函数
<MultiValueDict: {'head_image': [<InMemoryUploadedFile: 53efb9d8079c6e4f904ed602f5c1e4e.png (image/png)>]}>
53efb9d8079c6e4f904ed602f5c1e4e.png <class 'django.core.files.uploadedfile.InMemoryUploadedFile'>
  • 成功拿到了数据

(4)保存数据

  • 获取文件名

    • 直接.name就可以拿到文件名
  • 获取文件数据

    • 如果只是

    • with open(保存文件名, mode="wb") as fp:
      	fp.write(head_image)
      
    • 将会报错

    • a bytes-like object is required, not 'InMemoryUploadedFile'
      
    • 我们需要逐行读取,并且推荐保存文件写法如下

def register(request):
    if request.method == "POST":
        files_data = request.FILES
        # print(files_data)
        head_image = files_data.get("head_image")
        # print(head_image, type(head_image))
        head_image_name = head_image.name
        print(head_image_name)
        with open(head_image_name, mode="wb") as fp:
            for line in head_image.chunks():
                fp.write(line)

    return render(request, 'register.html')

【五】request对象方法

【1】.method

  • 返回客户端发起请求的HTTP方法
  • 例如:GET、POST
  • 注意,返回的值是大写的字符串

【2】.POST

  • 获得页面通过POST请求发送的数据
  • 类似于字典的对象,可以通过键值对获取值
  • 通常由前端的form表单发送的

【3】.GET

  • 获得通过GET请求发送的数据
  • 也是类似于字典的对象,通过键值对取值
  • get请求的参数通常是附加在URL的后买你,以?分割URL和数据,数据和数据之间通过&符号链接

【4】.FILES

  • 获得上传的文件
  • 也是类似于字典的对象
  • 读取保存文件要通过一行一行的读取加上chunck()

【5】.path

  • 只能获取路由地址,无法获取到参数
    • 不包含域名和查询参数
  • 例如:http://example.com/foo/bar/
    • 将得到/foo/bar/

【6】.path_info

  • 和path基本一样,相比于path
    • 他保留了URL路径中的任何编码、特殊字符、斜杠等信息
  • 通常情况下,可以使用 request.path 来获取丢弃域名后的路径,而使用 request.path_info 来获取原始的、未解析的路径。这在某些情况下非常有用,例如当需要对URL进行一些自定义操作或路由处理时。

【7】.get_full_path

  • 该方法返回请求URL的完整路径,包括路径部分和任何查询参数。
  • 例如,如果请求的URL是http://example.com/foo/bar/?page=2
    • 将返回/foo/bar/?page=2

【六】FBV和CBV

  • 视图层不仅可以写成函数,还可以写成类

【1】FBV

(1)介绍

  • 前面写的视图层,用的全是FBV
  • FBV(Function Based Views)是Django最早支持的一种视图编写方式
  • 简单直观,适合编写简单逻辑代码

(2)示例

  • 视图层
from django.http import render

def login(request, *args, **kwargs):
    if request.method = "POST":
        # 处理post请求逻辑代码
        return render(request, 'login.html')
    # 处理get请求逻辑代码
    return render(request, 'login.html')
  • 路由层
from django.urls import path
from . import views

urlpatterns = [
    path('login/', views.login, name='login'),
]

【2】CBV

(1)介绍

  • CBV(Class Based Views)是Django提供的另一种视图编写方式,通过面向对象编写
  • 通过继承和重写类实现代码复用和可扩展性
  • 适用于复杂的试图处理场景

(2)示例

  • 视图层
from django.http import render
from django.views import View  
class Login(View):
	def get(self, request, *args, **kwargs):
        # 处理get请求逻辑代码
        return render(request, 'login.html')
    
    def post(self, request, *args, **kwargs):
        # 处理post请求逻辑代码
        return render(request, 'login.html')
  • 路由层
from django.urls import path
from . import views

urlpatterns = [
    path('login/', views.login.as_view(), name='login'),
]

【3】CBV源码分析

  • class View:
    
    	# 定义支持的HTTP方法名
        http_method_names = ['get', 'post', 'put', 'patch', 'delete', 'head', 'options', 'trace']
    
        # 类View的初始化方法
        def __init__(self, **kwargs):
            for key, value in kwargs.items():
                setattr(self, key, value)
    
    	# 理解为类方法
        @classonlymethod
        def as_view(cls, **initkwargs):
            # cls是我们自己创建的类
            # as_view如果有参数对其进行检验方法名或者属性名书否冲突
            # 如果有前面定义的HTTP列表中的键值那就抛出异常
            for key in initkwargs:
                if key in cls.http_method_names:
                    raise TypeError(
                        'The method name %s is not accepted as a keyword argument '
                        'to %s().' % (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))
    		
            # 这是一个闭包函数,对外部的cls有引用
            def view(request, *args, **kwargs):
                # cls是自己创建的类,实例化了一个对象self
                self = cls(**initkwargs)
      			# 调用setup方法进行
                self.setup(request, *args, **kwargs)
                # 检查对象是否有request,没有会报错
                if not hasattr(self, 'request'):
                    raise AttributeError(
                        "%s instance has no 'request' attribute. Did you override "
                        "setup() and forget to call super()?" % cls.__name__
                    )
                return self.dispatch(request, *args, **kwargs)
            
            # 对View类的一些属性修改
            view.view_class = cls
            view.view_initkwargs = initkwargs
            update_wrapper(view, cls, updated=())
            update_wrapper(view, cls.dispatch, assigned=())
            # 返回闭包函数的地址
            return view
    
        # 初始化类试图的属性
        def setup(self, request, *args, **kwargs):
    		# 如果定义了类方法且没有定义head方法,那么将head方法复制为get方法
            if hasattr(self, 'get') and not hasattr(self, 'head'):
                self.head = self.get
            self.request = request
            self.args = args
            self.kwargs = kwargs
    	 
        # 检查对象实例此时的method是不是HTTP支持的方法名
        def dispatch(self, request, *args, **kwargs):
            # 因为method获取的方法名是大写的,所以需要转换为小去列表中比较
    		# 支持的方法名,就将方法取出复制给handler
            # 不支持就触发第三个参数这是HTTP不支持的请求
            if request.method.lower() in self.http_method_names:
                handler = getattr(self, request.method.lower(), self.http_method_not_allowed)
            else:
                handler = self.http_method_not_allowed
            return handler(request, *args, **kwargs)
    	
        # 返回警告内容为405状态码和HTTP允许的列表
        def http_method_not_allowed(self, request, *args, **kwargs):
            logger.warning(
                'Method Not Allowed (%s): %s', request.method, request.path,
                extra={'status_code': 405, 'request': request}
            )
            return HttpResponseNotAllowed(self._allowed_methods())
    	
        # 处理OPtions请求
        def options(self, request, *args, **kwargs):
            """Handle responding to requests for the OPTIONS HTTP verb."""
            response = HttpResponse()
            response.headers['Allow'] = ', '.join(self._allowed_methods())
            response.headers['Content-Length'] = '0'
            return response
        
    	# HTTP支持的列表转大写返回
        def _allowed_methods(self):
            return [m.upper() for m in self.http_method_names if hasattr(self, m)]
    
    

【七】视图装饰器

【1】FBV装饰器

  • FBV本身是一个函数,那就直接用以前学习的知识就可以

  • 视图层

from django.shortcuts import render

# 装饰器
def outer(func):
    def inner(*args, **kwargs):
        # 函数执行前逻辑处理
        res = func(*args, **kwargs)
		# 函数执行后逻辑处理
        return res
    return inner

@outer
def index(request, *args, **kwargs):
    # 逻辑处理
    return render(request, 'index.html')

【2】CBV装饰器

(1)函数方法直接加

  • 和FBV的添加方式一样
  • 不在展示

(2)使用method_decorator

  • Django提供了method_decorator装饰器
  • 也可以用在FBV上应用
  • CBV的应用有两种方法
    1. 直接用来类里面对应的方法上
    2. 类外使用,需要指定方法名
from django.shortcuts import render, HttpResponse, redirect
from django.utils.decorators import method_decorator

# 装饰器
def outer(func):
    def inner(*args, **kwargs):
        # 函数执行前逻辑处理
        start = time.time()
        res = func(*args, **kwargs)
        # 函数执行后逻辑处理
        print(f"用时:{time.time() - start}")
        return res

    return inner
@method_decorator(outer, 'post')
@method_decorator(outer, 'get')
class Login(View):
    # @method_decorator(outer)
    def get(self, request):
        time.sleep(2)
        return render(request, 'login.html')

    # @method_decorator(outer)
    def post(self, request):
        time.sleep(2)
        return render(request, 'login.html')

(3)重写dispatch方法

  • 此方法将所有的类方法都加上了装饰器
  • 当然装饰器也可以写在dispath方法外面
    • dispatch直接加上装饰器
from django.shortcuts import render, HttpResponse, redirect
from django.utils.decorators import method_decorator

class Login(View):
    def get(self, request):
        time.sleep(2)
        return render(request, 'login.html')

    def post(self, request):
        time.sleep(2)
        return render(request, 'login.html')
	
    # @method_decorator(outer)
    def dispatch(self, request, *args, **kwargs):
        # 函数执行前逻辑处理
        start = time.time()
        obj = super().dispatch(request, *args, **kwargs)
        # 函数执行后逻辑处理
        print(f"用时:{time.time() - start}")
        return obj
举报

相关推荐

0 条评论