django.test.client的一些用法

news2025/1/20 5:52:11

对于文件(文本文件,或图片文件等等文件)从客户端上传到服务端,对于常规情况,也就是真实服务端和客户端,我们往往是需要给files这个参数的。

具体来说,就像这样:

import requests

header = { 
    "Accept": "application/json, text/plain, */*",
    "Content-Type": "multipart/form-data",
    "Cookie": "ssssss"
}

url = "http://test.quasar.oa.com:8082/assess/api/AssessObject/ImportStaff"

# 接下来注意,上传文件需要一个files的参数,同时上传文件时,传入的是一个文件句柄。
path = (os.path.join(os.path.dirname(os.path.abspath(__file__)), 'test.xlsx'))
files = {'file': open(path, 'rb')}  # 这里key为file,绑定的对象就是一个文件句柄。这里注意此处字典的key,不一定非得叫 ‘file’, 也可以是其他的名称。

# 也有人选择给key绑定一个元组对象,性质是一样的,效果也是一样的,就是换了个写法,如:
files = {
    'file': ('test.png',  # 文件名称
             open('../file/test.png', 'rb'),  # 文件句柄
             'image/png',  # 文件类型
             {'Expires': '0'}  # 其他参数,非必传
             )
}

data= {'user_name': 'aa', 'page_num': 15} # 这里可以给一些其他的请求数据。

# 然后就可以发送请求了
res = requests.post(url=url, headers=headers, files=files,data=data)

这里还有一些关于 request 的参数介绍,也可以了解下:接口测试——requests 的基本了解 - 知乎

ok,但是,对于django工程而言,在进行一些测试的时候,往往我们并不需要这么麻烦的去构建一个真实的client,去访问服务,然后进行测试。往往我们都是选择使用django自带的test体系,去完成相关测试,这样往往会方便很多。对于发get,post请求,以及上传文件等操作,我们都可以使用 django.test.client 来弄,会特别方便,且快捷,因为这就相当于,在要测试的django工程里,基于django框架,在其内部做测试,就是从工程自己内部去访问工程的各个接口,去检测工程内部的接口是否正常,以及,接口对应的功能模块,函数等,是否能够按照预期处理数据,并按照预期返回我们想要的结果。

比如:

>>> from django.test.client import Client
>>> c = Client()
>>> response = c.post('/login/', {'username': 'john', 'password': 'smith'})
>>> response.status_code
200
>>> response = c.get('/customer/details/')
>>> response.content
'<!DOCTYPE html...'

这就是个非常典型的用法,当然,实际操作中,我们基本不会直接的这么用。

先进一步了解相关用法:

from django.test.client import Client

# Client(是可以填入参数的) enforce_csrf_checks,默认值是 False,会忽略CSRF检查。改成 True 会强制进行CSRF检查。
csrf_client = Client(enforce_csrf_checks=True)

# 也可以使用关键字参数来指定默认的请求报头
c = Client(HTTP_USER_AGENT='Mozilla/5.0')

# 另外,在发get, post 等请求的时候,get, post,等本身是可以带参数的,如:
c.get(path, data={}, follow=False, **extra)

path : 就是请求的url,注意用django.test.client.Client()时发请求给url时,是不需要给http://...,而是直接给路由即可, 比如 '/login',就是从工程的根路由开始提供路由路径即可。

data :需要传入的参数数据

follow :这个参数是追踪的意思,主要用于重定向的场景,当值为True的时候,client会追踪任何重定向,返回的response有redirect_chain属性,包括所有重定向过程中的url和状态码组成的元祖列表。

extra : 关键字参数可用作请求报头

关于重定向追踪的演示 eg: 

>>> response = c.get('/redirect_me/', follow=True)
>>> response.redirect_chain
[(u'http://testserver/next/', 302), (u'http://testserver/final/', 302)]

post 请求的解构: 

post(path, data={}, content_type=MULTIPART_CONTENT, follow=False, **extra)

和 get请求的参数大同小异,这里看下 content_type 参数,如果提供content_type参数(例如 text/xml),数据会被作为报头中Content-Type的类型进行POST上传。如果不提供content_type参数,数据会被作为multipart/form-data类型上传。

options(path, data='', content_type='application/octet-stream', follow=False, extra)**

做OPTIONS请求,对测试REST接口很有用。data被用作请求的主体。

put(path, data='', content_type='application/octet-stream', follow=False, extra)**

做PUT请求,测试RESTful接口。

patch(path, data='', content_type='application/octet-stream', follow=False, extra)**

做PATCH请求,测试RESTful接口。

delete(path, data='', content_type='application/octet-stream', follow=False, extra)**

做DELETE请求,测试RESTful接口

相关内容也可参考:Django单元测试工具test client使用详解_cecellialiu的博客-CSDN博客

 用 client 验证登录:

在验证登录前通常需要前创建一个用户,最好用django的内建模块创建:

from django.contrib.auth.models import User
from django.test.client import Client

user_test = User.objects.create_user('test', 'test@example.com')

然后,就是用 client 绑定这个用户:

client = Client(user=user_test)

然后,还记得上面的 extra 参数么。

extra.setdefault('content_type', 'application/json')
extra.setdefault('HTTP_AUTHORIZATION', 'apikey %s:%s' % (user_test.username, user_test.api_key.key))

接下来,就是发请求了。

client.get(path, data, **extra)

client.post(path, data, **extra)

client.put(path, data, **extra)

client.delete(path, data, **extra)

到这client的客户端就可以了,至于服务端的具体验证.....其实,大体就是,从request里获取到user的信息,然后,在和数据库里user的信息做对比,如果信息无误,那就是登录成功,或者就是确认是该用户,然后该干嘛干嘛就是了。

 用 client 上传文件:

这个时候,就跟正常真实客户端上传文件,有所不同了。client在上传文件的过程中,是不需要提供files这个关键字的。

看个例子:

def test_upload_file_success():
    """ Test generic_uploader Upload file API success """
    data = {
                'filename': 'log.log',
                'script_name': 'scriptname'
           }
    # prepare a dummy package to upload
    flength = 45272  # .045MB
    with tempfile.NamedTemporaryFile() as f:
        f.write(b"\0" * flength)
        # reset seek position to 0 to read full content
        f.seek(0)
        # 这里的关键字可以不叫files,叫什么都行,只是需要跟代码的处理逻辑保持一致即可
        data['files'] = f
        res = client.post(url, data=data)

相同的是,都是传入了一个句柄。

然后就是具体的post请求处理过程:

@csrf_exempt
@require_POST
def generic_uploader(request):
    res = {'status': False}
    try:
        request_data = request.POST.dict()
        # 这里的files就是刚才data里给出的key,所以说,files关键字可以是其他的名字,只要用例侧和post请求的处理侧保持一致即可。
        if 'files' in request.FILES:
            error = upload_file(request, request_data, build_obj.logs_path())
            if error:
                return error
        res['status'] = True

    except Exception as err:
        err_msg = (
            'Exception when calling the generic uploader service: %s' % err)
        log.exception(err_msg)
        res['error'] = (err_msg)
    return JsonResponse(res)

然后,看下文件的保存过程:

def upload_file(request, request_data, log_path):
    """
    Store the file to the correct storage location. Fail the API
    call if a file with the same name already exists.
    """

    filename = request_data['filename']
    dst = os.path.join(log_path, filename)
    if os.path.exists(dst):
        res = {'status': False, 'error': 'Error, %s already exists' % dst}
        return JsonResponse(res, status=409)
    with open(dst, 'wb') as f:
        for chunk in request.FILES['files'].chunks():
            f.write(chunk)
        request.FILES['files'].close()

这里注意:从request.FILES中获得的真实的文件。这个字典的每个输入都是一个UploadedFile对象——一个上传之后的文件的简单的包装。

看个日志呗:

 request.FILES对象,就是<MultiValueDict:{}>对象,这是一个特殊的字典对象。字典中的key,取决于post请求中绑定句柄的那个key,值当然对应的就是句柄对象了。

至此,关于client的内容先扯到这。看下,这个过程中涉及的,两个东西,一个是tempfile,一个是chunks()。

先说说chunks(),这东西,有点迭代器与生成器的意思。当文件本身特别大的时候,往往不适合用read()去操作文件,这样有可能会很占内存,这时候,chunks()就是个比较好的选择,它就像是生成器与迭代器,你调用一次,它就拿一次文件里的内容,默认的这个值是2.5M,当然这个值是可以调节的。然后就一直 for 下去,慢慢搬运文件内容呗。这样就等于保证效率的同时,也不影响内存的使用。

再就是tempfile临时文件系统。他的作用,就是造一个临时文件,通常这个临时文件,在关闭以后,就会自动被销毁。当然可以添加参数让其不自动销毁。

tempfile.NamedTemporaryFile(delete=False)

在有些场景下对于临时文件的存储有一定的格式要求,比如后缀等,这里我们将临时文件的后缀设置为常用的txt格式,同样的,只需要在NamedTemporaryFile的参数中进行配置即可:

import tempfile

file = tempfile.NamedTemporaryFile(delete=False, suffix='.txt')

这里也可参考:善用tempfile库创建python进程中的临时文件 - DECHIN - 博客园

它的应用场景是:

临时文件在python项目中时常会被使用到,其作用在于随机化的创建不重名的文件,路径一般都是放在Linux系统下的/tmp目录。如果项目中并不需要持久化的存储一个文件,就可以采用临时文件的形式进行存储和读取,在使用之后可以自行决定是删除还是保留。

要想安全的创建名字唯一的临时文件,以防止被试图破坏应用或窃取数据的人猜出,这很有难度。tempfile模块提供了多个函数来安全的创建临时文件系统资源。TemporaryFile()打开并返回一个未命名的文件,NamedTemporaryFile()打开并返回一个命名文件,SpooledTemporaryFile在将内容写入磁盘之前先将其保存在内存中,TemporaryDirectory是一个上下文管理器,上下文关闭时会删除这个目录。

如果应用需要临时文件来存储数据,而不需要与其他程序共享这些文件,则应当使用TemporaryFile()函数创建文件。这个函数会创建一个文件,而且如果平台支持,它会立即断开这个新文件的链接。这样一来,其他程序就不可能找到或打开这个文件,因为文件系统表中根本没有这个文件的引用。对于TemporaryFile()创建的文件,无论通过调用close()还是结合使用上下文管理器API和with语句,关闭文件时都会自动删除这个文件。

有些情况下,可能非常需要一个命名的临时文件。对于跨多个进程甚至主机的应用来说,为文件命名是在应用不同部分之间传递文件的最简单的方法。NamedTemporaryFile()函数会创建一个文件,但不会断开它的链接,所以会保留它的文件名(用name属性访问)。

关于tempfile的更多用法可以参考:Python3标准库:tempfile临时文件系统对象 - 走看看

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/106015.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

万字总结Bootloader到内核的启动流程

Bootloader启动流程分析 Bootloader的启动过程可以分为单阶段、多阶段两种。通常多阶段的 Bootloader能提供更为复杂的功能以及更好的可移植性。从固态存储设备上启动的 Bootloader大多都是两阶段的启动过程。第一阶段使用汇编来实现&#xff0c;它完成一些依赖于CPU体系结构的…

【ML实验5】SVM(手写数字识别、核方法)

实验代码获取 github repo 山东大学机器学习课程资源索引 实验目的 实验内容 这里并不是通过 KTT 条件转化&#xff0c;而是对偶问题和原问题为强对偶关系&#xff0c;可以通过 KTT 条件进行化简。 令 xα[α1,α2,...,αn]Tx\alpha[\alpha_1,\alpha_2,...,\alpha_n]^Txα[α1…

极狐阿尔法S 全新HI版在上海率先推送城区NCA

继深圳之后&#xff0c;12月19日&#xff0c;极狐阿尔法S 全新HI版城区NCA&#xff08;即城区智驾导航辅助功能&#xff09;交付上海车主&#xff0c;将胜任城区复杂环境的“点到点”智驾融入更多用户的生活中。 此前&#xff0c;极狐阿尔法S 全新HI版已面向全国车主推送第二次…

Unreal Engine项目目录结构

目录 Engine 引擎源码文件 Games 项目工程文件 Visualizer VS编辑器配置文件 之前说的是工程目录结构&#xff0c;这次来说项目目录结构。 这里只是举了个例子&#xff0c;实际请根据不同的UE版本自行分析。 Engine 引擎源码文件 虚幻是开源的&#xff0c;我们可以直接在工…

05-Golang的基本数据类型

Golang的基本数据类型变量数据类型整型类型基本使用及细节基本介绍整数类型演示案例整型的使用细节浮点类型基本使用及细节基本介绍浮点型的分类案例演示使用细节字符类型基本使用及细节基本介绍案例演示字符类型本质探讨布尔类型的使用基本介绍字符串类型基本使用及细节基本介…

复变函数的积分

复变函数的积分化解成曲线积分的问题。 那化成第一类曲线积分还是第二类曲线积分&#xff1f;&#xff08;高等数学 中有讲第一类曲线积分和第二类曲线积分&#xff09;。 路径是有方向的&#xff0c;由起点和终点不同&#xff0c;路径有正向和负向。 复变函数的积分归结起来…

「学习方法」Scratch、Python、C++如何学才能融会贯通?

前言 相信很多家长朋友都发现一个问题&#xff1a;“编程教育正在以飞快的速度渗透于孩子们的培养体系中&#xff0c;这是为什么呢&#xff1f;原因很简单&#xff0c;这是因为通过专业的编程教育可以全面提升孩子的逻辑思维、创造力、动手能力等&#xff0c;让孩子们拥有更全…

线程池的使用

线程池 3大方法、7大参数、4种拒绝策略 好处&#xff1a;降低资源的消耗、提高响应的速度、方便管理、 线程池可以理解为银行业务 三大方法 第1大方法&#xff1a;单个线程 ExecutorService threadExecutor Executors.newSingleThreadExecutor(); 第2大方法&a…

c语言 操作符详解例题 数据存储 指针初阶 水仙花数 杨辉三角 逆序字符串 喝汽水问题 打印图形 猜凶手

【题目名称】 下面代码的结果是&#xff1a;a #include <stdio.h> int i; int main() {i--; sizeof的返回值是无符号整型if (i > sizeof(i)) i四个字节所以是4。算出的结果类型是unsigned int无符号和有符号比较大小 会先把有符号整型转化为无符号。 -1放到内…

浏览器底部导航栏遮盖问题

欧吼&#xff0c;算是遇到两次了这种问题。每次解决完都觉得很无语&#x1f92e; 先看问题如图&#xff08;怕公司说我泄露他们啥信息&#xff0c;于是打了非常离谱且难看的马赛克&#x1f60a;&#xff09;&#xff1a; 本来要在底部导航栏上方展示底部信息。 电脑上看倒是好…

怎样设计产品帮助中心?以下几点不可忽视

在日常产品的使用过程中&#xff0c;我们经常会遇到一些关于产品的使用相关问题&#xff0c;此时我们会去翻阅产品的说明书&#xff0c;而对于线上的产品来说&#xff0c;一般都会搭配对应的帮助文档&#xff0c;帮助文档可以提供关于用户在使用过程中遇到的各种问题的解答&…

【再学Tensorflow2】TensorFlow2的建模流程:Titanic生存预测

TensorFlow2的建模流程1. 使用Tensorflow实现神经网络模型的一般流程2. Titanic生存预测问题2.1 数据准备2.2 定义模型2.3 训练模型2.4 模型评估2.5 使用模型2.6 保存模型参考资料在机器学习和深度学习领域&#xff0c;通常使用TensorFlow来实现机器学习模型&#xff0c;尤其常…

03Python算数运算符及变量基本使用

算数运算符 算数运算符 是完成基本的算术运算使用的符号&#xff0c;用来处理四则运算 运算符描述实例加10 20 30-减10 - 20 -10*乘10 * 20 200/除10 / 20 0.5//取整除返回除法的整数部分&#xff08;商&#xff09; 9 // 2 输出结果 4%取余数返回除法的余数 9 % 2 1*…

干货 | 云原生时代的灰度发布有几种“姿势”?

随着企业数字化转型进程不断发展&#xff0c;云原生时代的来临&#xff0c;企业应用越来越多&#xff0c;不得不面对应用程序升级的巨大挑战。传统的停机发布方式&#xff0c;新旧版本应用切换少则停机30分钟&#xff0c;多则停机10小时以上&#xff0c;愈发无法满足业务端的需…

java入门及环境配置

java三大版本 JavaSE: 标准版&#xff08;桌面程序&#xff0c;控制台开发........) JavaEE: 嵌入式开发&#xff08;手机&#xff0c;小家电.....&#xff09; JavaEE: E企业级开发&#xff08;web端&#xff0c;服务器开发...&#xff09; JDK、JRE、JVM: Java安装开发环境&a…

信息化时代企业数据防泄露工作该怎么做

场景描述 信息化时代发展迅速&#xff0c;数据防泄露一词也频繁的出现在我们身边。无论企业或政府单位&#xff0c;无纸化办公场景越来越多&#xff0c;数据泄露的时间也层出不穷。例如&#xff1a;世界最大职业中介网站Monster遭到黑客大规模攻击&#xff0c;黑客窃取在网站注…

计算机毕设Python+Vue药品销售平台(程序+LW+部署)

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

模板二(基础算法)

目录 快速排序 归并排序 二分 整数二分 浮点数二分 前缀和 一维前缀和 二维前缀和 差分 一维差分 二维差分 双指针 位运算 离散化 区间合并 快速排序 方法一&#xff1a;定义两个新数组&#xff0c;a[ ],b[ ],每次将大于x的放到a中&#xff0c;小于x的放到b中&…

【矩阵论】6.范数理论——范数估计——许尔估计谱估计

6.3 许尔估计 任意方阵 A(aij)nnA(a_{ij})_{n\times n}A(aij​)nn​ &#xff0c;全体根 λ(A){λ1,⋯,λn}\lambda(A)\{\lambda_1,\cdots,\lambda_n\}λ(A){λ1​,⋯,λn​} &#xff0c;满足 ∣λ1∣2⋯∣λn∣2≤∑∣aij∣2\vert \lambda_1\vert^2\cdots\vert \lambda_n\ve…

数据存储格式

文章目录数据存储格式1 行列存储比较2 ORC文件格式2.1 文件级2.1.1 Post scripts2.1.2 File Footer2.1.3 File MetaData2.2 Stripe级2.2.1 Stripe Footer2.2.2 Row Data2.2.3 Index Data3 Parquet文件格式3.1 Header3.2 Data3.2.1 Row Group3.2.2 Column Chunk3.2.3 Page3.3 Fo…