作者: 李镇伟

jira-api使用gevent,快速批量修改数据

需求

因为我们本地数据库中经常会产生大量的数据,这些数据需要同步至jira.覆盖掉jira上的老数据。
因为jira服务器部署在国外,连接巨慢。每次修改一个,至少需要花费10秒左右的时间。
而jira-api没有提供批量或者异步同步的方法,所以需要自己使用一个异步的方式来实现一次性把所有的请求发送出去。
jira服务端有时候吃不消,会关闭掉我的一些连接,所以还需要在被关闭之后,记录下这些同步至jira失败的,重新继续修改操作

用到的库

gevent  库

gevent是一个基于libev的并发库。它为各种并发和网络相关的任务提供了整洁的API。

jira库。
里面有jira登录,修改,新增issue的方法

代码实现

# -*- coding: UTF-8 -*-
import datetime
import random
import gevent
from gevent import monkey
from jira import JIRA
from model import addDefectDAO
monkey.patch_all()
issue_list = []
def update(issue_key):
    # 产生一点小小的间隔,避免一瞬间发出去100多个请求
    gevent.sleep(random.randint(1, 5) * 0.001)
    global issue_list
    starttime = datetime.datetime.now()
    print(starttime)
    print("start:" + issue_key)
    print("start:" + issue_key)
    issue = jira.issue(issue_key)
    issue_dict = {
        'summary': issue_key
    }
    try:
        issue.update(fields=issue_dict)
        issue_list.remove(issue_key)
    except Exception:
        pass
    print("end:" + issue_key)
# 从一个本地数据库取出一堆issue的信息,602是本地的project信息编号
all = addDefectDAO.defect_select_not_draft_by_project_id(602)
for item in all:
    issue_list.append(item["issue_key"])
url = "https://www.jira.com"
username = "username"
password = "password"
jira = JIRA(server=url, basic_auth=(username, password), max_retries=0, timeout=400, async_=True, async_workers=5)
# jira2 = Jira(url=url, username=username, password=password)
print("登录成功")
starttime = datetime.datetime.now()
api_list = []
while issue_list != []:
    for i in issue_list:
        api_list.append(gevent.spawn(update, i))
    gevent.joinall(api_list)
endtime = datetime.datetime.now()
print('总耗时')
print((endtime - starttime).seconds)
print('*******')

注意事项

1.需要引用monkey.patch_all()
2.引用monkey.patch_all()之后会有错误信息:

UserWarning: libuv only supports millisecond timer resolution; all times less will be set to 1 ms

这个是已知bug,在11月29日有人在github上已经提过了,作者会在之后的版本修改。目前不影响使用。请忽略
3.通过这样的方法修改之后,经过我的测试,速度大概快了5倍以上

需求池,开发池,交付池,避免发布混乱

最近公司开始搞sprint,2周一个sprint,这导致了一些问题,有一些存在相互依赖的功能,因为2周的时间线规定,被强行划成了两个sprint,老板要求测试人员必须跟着sprint,这导致环境问题频出,因为功能都不完整啊!所以我提出了建议,引入版本的概念。开发人员可以继续按照他们的sprint走,测试人员和项目经理,开发经理打成一致,把一个完整的功能做成一个版本,测试人员关注的是版本,而不是sprint。项目经理可以决定每次版本里包含哪些功能,但是版本里要求的功能一定是完整,且没有与另一个sprint或者版本存在相互依赖关系,版本可大可小。不可以再为了赶时间点,上一些不完整的功能呢。
目标是“稳定且完整”,而不是“依赖下个版本”

通过python-docx给word文档中的指定位置添加表格

需求

1.读取一个已有的word文档。docx格式。
2.在该word文档中,通过一个给定的文字。找到该位置。在该位置的下方添加一个表格。例如在图中“BUG情况表”的下方插入一个表格

3.表格内容如下。要求添加完该表格后,如果表格内容发生变更。还能再次通过该程序,修改表格里的数据。

设计

通过python-docx读取word文档。通过document.paragraphs定位指定文字的位置。
通过xlwings读取excel的内容,存成list[list[]]。
通过docx的add_table增加一个表格,并且更改表头颜色,合并表格等操作
通过识别表头的第一行,判断是否是已经存在这个表格,来决定是否要删除原表格

代码

# -*- coding: UTF-8 -*-
import sys
from copy import deepcopy
import xlwings
from docx import Document
from docx.oxml.ns import nsdecls
from docx.oxml import parse_xml
def copy_table_after(table, paragraph):
    tbl, p = table._tbl, paragraph._p
    new_tbl = deepcopy(tbl)
    p.addnext(new_tbl)
def move_table_after(table, paragraph):
    tbl, p = table._tbl, paragraph._p
    p.addnext(tbl)
def get_excel_date(filename):
    '''
    获得excel里的所有内容,返回list
    :param filename:  excel路径
    :return: list[list[]]
    '''
    app = xlwings.App(visible=False, add_book=True)
    app.display_alerts = False
    app.screen_updating = False
    wb = app.books.open(filename)
    sht = wb.sheets[0]
    rng = sht.range('A1')
    # 把excel里的数据读取成 年-月-日 时:分:秒的格式
    my_date_handler = lambda year, month, day, hour, minute, second, **kwargs: "%04i-%02i-%02i %02i:%02i:%02i" % (
        year, month, day, hour, minute, second)
    # 取出所有内容,这里用ig这个变量,是为了庆祝I.G获得LOL S8赛季总冠军
    ig = rng.current_region.options(index=False, numbers=int, empty='N/A', dates=my_date_handler)
    result = ig.value
    wb.close()
    app.quit()
    return result
def delete_table_with_title(document,expect_text):
    allTables = document.tables
    for activeTable in allTables:
        if activeTable.cell(0, 0).paragraphs[0].text == expect_text:
            print('删除成功')
            activeTable._element.getparent().remove(activeTable._element)
def insert_table_after_text(file_name,excel_name,expect_text):
    document = Document(file_name)
    # 因为docx读出来的都是unicode类型的,所以我们要用unicode类型的进行查找
    expect_text=expect_text.decode('utf-8')
    delete_table_with_title(document,expect_text)
    target = None
    for paragraph in document.paragraphs:
        paragraph_text = paragraph.text
        if paragraph_text.endswith(expect_text):
            target = paragraph
            break
    if target is not None:
        records = get_excel_date(excel_name)
        # 获得excel数据的栏数,初始化一个空的table
        col = len(records[0])
        table = document.add_table(rows=1, cols=col)
        table.style = 'Table Grid'
        # 给table加一个表头,并且合并第一栏
        shading_elm_1 = parse_xml(r'<w:shd {} w:fill="D9E2F3"/>'.format(nsdecls('w')))
        table.rows[0].cells[0]._tc.get_or_add_tcPr().append(shading_elm_1)
        table.rows[0].cells[0].text=expect_text
        table_row=table.rows[0]
        first=table_row.cells[0]
        end=table_row.cells[-1]
        first.merge(end)
        # 合并结束,开始把excel里的内容添加到table里
        for tr_list in records:
            row_cells = table.add_row().cells
            index = 0
            for td_list in tr_list:
                row_cells[index].text = td_list
                index = index + 1
        # 把添加的table移动到指定的位置
        move_table_after(table, target)
        # 保存
    document.save(file_name)
if __name__ == '__main__':
    insert_table_after_text('demo2.docx', 'demo.xlsx',"BUG情况表")

最终效果

API测试:通过faker生成测试数据,通过schema检查返回结果

需求

假定有如主图相同的http请求。我们一般的做法是,用postman去抓取http请求,然后修改request的body或者header里的数据,点击send按钮,检查返回的response的body是否正确。
对于输入。一般来说,我们会纯手工,或者半自动的,设计测试用例。例如使用边界值分析,等价类划分等方法,用在我们的输入参数中。比如我参数中的configname最多200个参数,我测试输入201个参数。
对于输出。一般来说,我们大部分时候是肉眼检查,或者写代码,通过jsonpath取参数,然后判断是否存在来检查。
这里我打算用一个新的方法来降低测试的手工特性,让他更自动化一点。以下想法还处于调试阶段,用于大规模使用,暂时不行。

设计

输入修改方案:引入faker库和jsonschema库。通过这两个库,我们可以产生随机的json串
faker是我无意之间发现的,能按照规律产生随机字的库,例如

fake.name()

是产生一个随机的名字,只要加入适当的providers,就能按照需要的规则产生随机字
jsonschema这个用的人很多,这里就不介绍了,下面推荐一个网站,能把json请求转换为schema格式
https://jsonschema.net/
schema中会注明每个字段的规则,例如是string类型还是integer。
输出修改方案:使用jsonschma的validate方法来检查(这种检查方法目前有一些检查不充分,但是已经可以让测试人员减少一些工作量了)

jsonschema.validate(response, schema)

使用方案

1.去postman抓取http请求,并且记录下所需要的输入json和输出json

2.打开https://jsonschema.net/ 把输入json和输入json 转换成jsonschema

3.把输入jsonschema文件,输出文件jsonschema放入相应的目录,自己写一个用于生成随机requestbody的provider和一个测试用的主函数

4.运行测试主入口文件,打印一下发送的json文件,看是不是随机化了,结果是确实随机化了。

代码

测试主入口test_json_from_schema.py

#!/usr/bin/env python
# -*- coding: UTF-8 -*-
import json
import faker
import jsonschema
import requests
from jsonschema.exceptions import ValidationError
import jsonprovider
def generate_request(request_json_schema):
    '''
    通过schema生成随机测试数据
    :param request_json_schema:
    :return:
    '''
    fake = faker.Faker()
    fake.add_provider(jsonprovider.JSONProvider)
    request_body = fake.json(json.load(open(request_json_schema)))
    print(request_body)
    return request_body
def check_json_schema(response, schema):
    '''
    通过json_schema检查返回的json串
    :param response:
    :param schema:
    :return:
    '''
    result = True
    try:
        jsonschema.validate(response, schema)
    except ValidationError, e:
        print("fail")
        result = False
    return result
if __name__ == '__main__':
    # 生成request body
    body = generate_request("schema_file/create_config_request_schemas.json")
    # 使用request库发送post请求
    url = "https://dev.honcloud.honeywell.com.cn:8080/dashboard/clustercentre/configmng/newconfig/addconfig"
    headers = {"Content-Type": "application/json", "authorization": "48a5eb61-914e-4b3a-a7a3-0b25f72d06d7"}
    response = requests.post(url, data=body, headers=headers)
    print(response.json())
    response_json=response.json()
    response_schema="schema_file/create_config_response_schemas.json"
    # 用生成的response的schema来检查
    result=check_json_schema(response_json,response_schema)
    print(result)

jsonprovider.py可以自行百度一个faker的provider的方案,我这里做的也不好,随机出来的值只遵循了字符类型,后面会考虑融合我们的边界值分析,等价类划分的方案进来,完善这个jsonprovider.py之后再放出来

python读取excel内容再转变成html添加到outlook中

需求

读取excel里的表格里的内容,然后打开本机的outlook。把excel里的内容添加到正文里,注意。这里是要添加到正文!正文!正文!而不是添加到附件里

设计思路

1.excel处理

打开excel的方法有很多,但是在不知道excel里,行和列的大小的情况下,就能获得excel里的非空值行列的办法不多。我这边采用的是xlwings这个库,用的方法是range.current_region这个方法。这个方法会选择当前range下,有值的区域(非空区域)
通过配置options选项,可以指定excel获得的值的格式,int或者string,或者空值返回N/A

2.打开outlook

打开outlook在windows上只能用win32模块了,通过下面方法可以打开outlook并且创建一个空的email

olook = win32com.client.Dispatch("Outlook.Application")
mail = olook.CreateItem(0)

然后配置邮件的htmlbody和outlook邮件悬停(可以手动更改邮件内容,手动发送),可以用以下方法

mail.HTMLBody = body_html
mail.Display(True)

完整代码

下面是完整代码,读者修改一下excel的路径,就可以自己去试试啦

# -*- coding: UTF-8 -*-
import sys
reload(sys)
sys.setdefaultencoding('utf-8')
import win32com.client
import xlwings
def get_excel_date(filename):
    '''
    获得excel里的所有内容,返回list
    :param filename:  excel路径
    :return: list[list[]]
    '''
    app = xlwings.App(visible=False, add_book=True)
    app.display_alerts = False
    app.screen_updating = False
    wb = app.books.open(filename)
    sht = wb.sheets[0]
    rng = sht.range('A1')
    # 把excel里的数据读取成 年-月-日 时:分:秒的格式
    my_date_handler = lambda year, month, day, hour, minute, second, **kwargs: "%04i-%02i-%02i %02i:%02i:%02i" % (
    year, month, day, hour, minute, second)
    # 取出所有内容,这里用ig这个变量,是为了庆祝I.G获得LOL S8赛季总冠军
    ig = rng.current_region.options(index=False, numbers=int, empty='N/A', dates=my_date_handler)
    result = ig.value
    wb.close()
    app.quit()
    return result
if __name__ == '__main__':
    olook = win32com.client.Dispatch("Outlook.Application")
    mail = olook.CreateItem(0)
    mail.Recipients.Add("357244849@qq.com")
    mail.Subject = "test report"
    body_html = ""
    body_html = body_html + '<body>Hi all:<br/>以下是XXXXX项目今天的测试情况:<br/><br/>明天的测试计划:<br/><br/>目前的bug:'
    body_html = body_html + '<table width="1" border="1" cellspacing="1" cellpadding="1" height="100">'
    # 这里用rng 是因为这一次rng止步8强!
    rng_list = get_excel_date("C:\lzw_programming\resource\reports\CurrentVersionAllDefectTable.xlsx")
    # 表头
    for tr_list in rng_list[:1]:
        body_html = body_html + "<tr>"
        for td_list in tr_list:
            # 这里也是奇葩需求,因为要求表头不能换行,所以用了nowrap
            body_html = body_html + '<th bgcolor="#C3C3C3" nowrap="nowrap">' + td_list + '</th>'
        body_html = body_html + "</tr>"
    # 表内容
    for tr_list in rng_list[1:]:
        body_html = body_html + "<tr>"
        for td_list in tr_list:
            body_html = body_html + "<td>" + td_list + "</td>"
        body_html = body_html + "</tr>"
    body_html = body_html + '</table>'
    body_html = body_html + "</body>"
    mail.HTMLBody = body_html
    mail.Display(True)

解决pyinstaller不兼容python-docx的方法

需求

python-docx是一个python的读写word的库,可以用来读写word文档,向word文档里插入表格。例如如下的操作docx的代码:

from docx import Document
document = Document()
document.add_heading('Document Title', 0)
p = document.add_paragraph('A plain paragraph having some ')
p.add_run('bold').bold = True
p.add_run(' and some ')
p.add_run('italic.').italic = True
document.add_heading('Heading, level 1', level=1)
document.add_paragraph('Intense quote', style='Intense Quote')
document.add_paragraph(
    'first item in unordered list', style='List Bullet'
)
document.add_paragraph(
    'first item in ordered list', style='List Number'
)
records = (
    (3, '101', 'Spam'),
    (7, '422', 'Eggs'),
    (4, '631', 'Spam, spam, eggs, and spam')
)
table = document.add_table(rows=1, cols=3,style='Light Grid Accent 1')
hdr_cells = table.rows[0].cells
hdr_cells[0].text = 'Qty'
hdr_cells[1].text = 'Id'
hdr_cells[2].text = 'Desc'
for qty, id, desc in records:
    row_cells = table.add_row().cells
    row_cells[0].text = str(qty)
    row_cells[1].text = id
    row_cells[2].text = desc
document.add_page_break()
document.save('demo.docx')

 
pyinstaller是python打包成exe的工具。
当我们要把编写好的使用了python-docx的程序打包时,问题来了。
首先,命令行打包

pyinstaller -D word_generate.py

这个没问题,word_generate.py是我的主程序文件。这里打包也不报错。但是下一步,运行的时候,duang~报错了,报错如下:

C:lzw_programmingjira_testdistword_generate>word_generate.exe
Traceback (most recent call last):
  File "word_generate.py", line 4, in <module>
  File "site-packagesdocxapi.py", line 25, in Document
  File "site-packagesdocxopcpackage.py", line 116, in open
  File "site-packagesdocxopcpkgreader.py", line 32, in from_file
  File "site-packagesdocxopcphys_pkg.py", line 31, in __new__
docx.opc.exceptions.PackageNotFoundError: Package not found at 'C:LZW_PR~1JIRA_T~1distWORD_G~1docxtemplatesdefault.docx'
[4232] Failed to execute script word_generate

解决方法

在翻了很多地方之后,终于找到了解决方法。很简单。增加一个hook-docx.py文件在PyInstallerhooks目录下就可以了。下面是文件内容以及路径

#-----------------------------------------------------------------------------
# Copyright (c) 2018-2018, PyInstaller Development Team.
#
# Distributed under the terms of the GNU General Public License with exception
# for distributing bootloader.
#
# The full license is in the file COPYING.txt, distributed with this software.
#-----------------------------------------------------------------------------
from PyInstaller.utils.hooks import collect_data_files
datas = collect_data_files("docx")

路径:

python根据excel的一列数据产生加权随机数

需求

最近遇到一个奇葩的事,行政那边说,让估算一下明年的这些杂七杂八费,然后给了我一个excel,里面有200多个这样的费用。我没做过行政,也搞不清这个到底咋来,为什么要弄这玩意。一番交流,原来是上头要的,不一定看,但是东西得有,让我弄个数字和去年差不多的就行。于是变有了下面的故事

设计

1.需要读取excel. 用的库是xlwing。可以根据sheet名称定位sheet,然后用range()方法定位一行,一列,或者指定几个单元格。
例如:定位 A1到A3 ,range1=sheet.range("A1:A3")
具体用法很多,在xlwing的官网上有介绍。http://docs.xlwings.org/en/stable/api.html
2.需要产生随机数,用的库是numpy,产生一个加权的随机数,然后我用的加权随机数规则为:
【-10%,概率10%】【不变,概率30%】【+2%,概率30%】【+5%,概率20%】【+10%,概率10%】

代码实现

代码中分为两个function,一个是读取excel,一个是根据一个值,产生一个加权随机数。观众老爷可以参考,对有疑问的地方,可以再来与我沟通O(∩_∩)O

# -*- coding: UTF-8 -*-
import xlwings
import numpy as np
def import_excel(filename, sheet_name, source,target):
    '''
    导入一个excel,根据某一列的值,产生一个加权随机数,覆盖掉另一列的值
    :param filename: excel路径
    :param sheet_name: sheet的名字
    :param source: 源列的第一个值 如:A1,C1
    :param target: 目标列的第一个值,如B1,D2
    :return:
    '''
    app = xlwings.App(visible=False, add_book=True)
    app.display_alerts = False
    app.screen_updating = False
    wb = app.books.open(filename)
    sht = wb.sheets[sheet_name]
    rng1 = sht.range(source)
    rng2 = sht.range(source).end('down')
    rng3 = sht.range(rng1, rng2)
    all_rng = rng3.value
    list_dest = []
    for item in all_rng:
        dest_item = arithmetic(item)
        # 这里要把结果变成[[1],[2]]这样的形式,才是一列的数据
        # 如果是[1,2]这样,是一行的数据
        list_temp = []
        list_temp.append(dest_item)
        list_dest.append(list_temp)
    sht.range(target).value = list_dest
    wb.save(filename)
    wb.close()
    app.quit()
def arithmetic(source):
    '''
    加权随机算法
    :param source: 输入一个原值
    :return: 返回浮动后的值
    '''
    power = np.array([0.1, 0.3, 0.3, 0.2, 0.1])
    index = np.random.choice([-0.1, 0, 2, 5, 10], p=power.ravel())
    rand = source * index / 100
    dest = int(source + rand)
    return dest
if __name__ == '__main__':
    import_excel("Book1.xlsx", 'Sheet1','C2','D2')

运行结果

vue框架html中的script内容转换成.vue文件的script内容

问题:
1.因为前段时间学习vue,都是在一个index.html中添加<html>和<script>
2.如果使用.vue文件,<template>对应index.html<html>作为展示层,<script>作为逻辑层对应index.html的<script>
html中用的是new vue。而.vue文件中用的是export default。下面是对比

  • index.html
<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width,initial-scale=1.0">
  <title>vueapp01</title>
  <script src="https://cdn.staticfile.org/vue/2.4.2/vue.min.js"></script>
</head>
<style>
  .class1{
    background: #444;
    color: #eee;
  }
</style>
<body>
  <div id="app"></div>
  <div id='example-3'>
    <input type="checkbox" id="jack" value="白金会员" v-model="checkedNames">
    <label for="jack">白金会员</label>
    <input type="checkbox" id="john" value="黄金会员" v-model="checkedNames">
    <label for="john">黄金会员</label>
    <input type="checkbox" id="mike" value="王者会员" v-model="checkedNames">
    <label for="mike">王者会员</label>
    <br>
    <span>选择会员种类: {{ checkedNames }}</span>
  </div>
  <div id="app2">
    <input v-model="username" placeholder="用户名">
    <p>用户名是: {{ username }}</p>
    <input  type="password" v-model="password" placeholder="密码">
    <p>密码是: {{ password }}</p>
    <button v-on:click="login">登录</button>
  </div>
</body>
<script type="text/javascript">
  var chenames=new Vue({
    el: '#example-3',
    data: {
      checkedNames: []
    }
  })
  var user=new Vue({
    el :'#app2',
    data: {
      username:'',
      password:''
    },
    methods :{
      login:function(event){
        alert('用户名是:'+this.username+',密码是:'+this.password+',选择的是:'+chenames.checkedNames)
      }
    }
  })
</script>
</html>
  • .vue文件
<template>
  <div class="hello">
    <h1>{{ msg }}</h1>
    <div id='example-3'>
    <input type="checkbox" id="jack" value="白金会员" v-model="checkedNames">
    <label for="jack">白金会员</label>
    <input type="checkbox" id="john" value="黄金会员" v-model="checkedNames">
    <label for="john">黄金会员</label>
    <input type="checkbox" id="mike" value="王者会员" v-model="checkedNames">
    <label for="mike">王者会员</label>
    <br>
    <span>选择会员种类: {{ checkedNames }}</span>
  </div>
  <div id="app2">
    <input v-model="username" placeholder="用户名">
    <p>用户名是: {{ username }}</p>
    <input  type="password" v-model="password" placeholder="密码">
    <p>密码是: {{ password }}</p>
    <button class="btn btn-large btn-primary" v-on:click="login">登录</button>
  </div>
  </div>
</template>
<script>
export default {
  name: "hello",
  data() {
    return {
      msg: "欢迎来到测试开发笔记!",
      checkedNames:[],
      username: "",
      password: "",
    };
  },
  methods:{
    login(){
       alert('用户名是:'+this.username+',密码是:'+this.password+',选择的是:'+this.checkedNames)
    }
  }
};
</script>

python使用request库发送上传zip文件的post请求

使用工具:

  • python(2.7)
  • requests(2.18.4)
  • zip文件一个
  • chrome浏览器

第一步,通过chrome浏览器的开发者工具,获得发送的参数。


第二步,编写python代码

使用request库的post方法。注意的是要添加files参数,例如:

files ={'app_filename':open('portal-1.0-SNAPSHOT-fat.jar.zip','rb')}

zip压缩包用的后缀是application/x-zip-compressed,其他的文件是application/octet-stream
其中,’app_filename’是F12工具里抓出来的from data里的标有{binary}这一行的参数名。
portal-1.0-SNAPSHOT-fat.jar.zip是我自己电脑本地的一个zip文件。
rb是读二进制文件。因为这个form data是以二进制形式上传文件的
其余的常规参数,放到data参数里。例如上图的image_name:fff就是常规参数。
在header里注意添加cookies值或者Authorization值,这里我测试的网站用的是Authorization。如果没有该参数,会返回401
完整python request体参数如下:

path = os.path.split(os.path.realpath(__file__))[0]
url = host + '/dashboard/cicd/images'
headers = {
    'Authorization':'6bae7b70-8dae-4f74-9631-680b9501b52',
    'cookie': "_ga=GA1.3.733851079.1534745675; Hm_lvt_dde6ba2851f3db0ddc415ce0f895822e=1537859803; _ga=GA1.3.733851079.1534745675; Hm_lvt_dde6ba2851f3db0ddc415ce0f895822e=1537859803",
}
datat = {'image_name': 'abcd',
         'image_description': 'ccccvcc',
         'image_label': '1cc1fcc',
         'basic_image': 'openjdk:10',
         'store_path': '/opt/app/lzw/'}
files = {'app_filename': (
    'portal-1.0-SNAPSHOT-fat.jar.zip', open(os.path.join(path, 'portal-1.0-SNAPSHOT-fat.jar.zip'), 'rb'),
    'application/x-zip-compressed')}
# files ={'app_filename':open('portal-1.0-SNAPSHOT-fat.jar.zip','rb')} 和上面的功能一样
result = requests.post(url, files=files, data=datat, headers=headers)
r1 = result.text
print(result.text)

注意:千万不要在head里加入 ‘Content-Type’:’multipart/form-data;参数。

如何使用Vue获得多个input和多选框的值,以及双向绑定

需求分析

1.有三个多选框选项。当选择不同的按钮时,界面上会实时展示所选的参数
2.有用户名和密码,当输入用户名和密码时,界面上会实时展示所输入的参数
3.当点击登录按钮的时候,会弹出alert,展示当前所选的所有参数

实现代码

通过v-model实时获得input的输入值。通过v-on监听login事件。完整代码如下

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width,initial-scale=1.0">
  <title>vueapp01</title>
  <script src="https://cdn.staticfile.org/vue/2.4.2/vue.min.js"></script>
</head>
<style>
  .class1{
    background: #444;
    color: #eee;
  }
</style>
<body>
  <!-- <div id="app"></div> -->
  <div id='example-3'>
    <input type="checkbox" id="jack" value="白金会员" v-model="checkedNames">
    <label for="jack">白金会员</label>
    <input type="checkbox" id="john" value="黄金会员" v-model="checkedNames">
    <label for="john">黄金会员</label>
    <input type="checkbox" id="mike" value="王者会员" v-model="checkedNames">
    <label for="mike">王者会员</label>
    <br>
    <span>选择会员种类: {{ checkedNames }}</span>
  </div>
  <div id="app2">
    <input v-model="username" placeholder="用户名">
    <p>用户名是: {{ username }}</p>
    <input  type="password" v-model="password" placeholder="密码">
    <p>密码是: {{ password }}</p>
    <button v-on:click="login">登录</button>
  </div>
</body>
<script type="text/javascript">
  var chenames=new Vue({
    el: '#example-3',
    data: {
      checkedNames: []
    }
  })
  var user=new Vue({
    el :'#app2',
    data: {
      username:'',
      password:''
    },
    methods :{
      login:function(event){
        alert('用户名是:'+this.username+',密码是:'+this.password+',选择的是:'+chenames.checkedNames)
      }
    }
  })
</script>
</html>

苏ICP备18047533号-1