Pytest+Allure+Jenkins接口自动化项目实战(一)

       经过一周多时间,基于python+pytest+excel+allure框架的接口自动化测试初版已基本实现,包括基本配置读取、用例读取、用例执行、sql读取执行、前置数据准备、后置数据清理以及测试报告生成等,环境独立运行、项目独立运行、用例独立运行、jenkins集成、邮件发送暂未实现,再后期版本会再次推出,现在把整个框架设计思路和想法分享给大家来参考和借鉴。希望大家也能提供更好的思路和方法帮助我进行优化改进。

       实战项目是三端交互的项目,所以在设计思路上要考虑多项目如何交互,目前只写了1个项目的,其它2个项目都预留了位置,后期直接添加就可以,思路一样。

一、整个代码目录及介绍

common

request.py  封装post、get请求方法,供所有地方调用

login.py 封装各项目、各种方式的登录方法,供所有地方调用

readFile.py 封装读取yaml中配置文件、excel中测试用例方法,供所有地方调用

execSql.py 封装sql操作增、删、改、查方法,供所有地方调用

prefixSqlData.py 封装前置、后置公共sql,供所有地方调用

assertion.py 封装断言方法,供所有用例中调用

logs.py 封装日志方法,供所有地方调用

config

sql.yaml  前置数据sql语句、后置清理sql语句等

test.yaml  test环境数据库配置、接口域名、测试账号、登录接口数据等

uat.yaml  uat环境数据库配置、接口域名、测试账号、登录接口数据等

testcase.xls  测试用例等

testcase

项目1

    用例1、用例2

项目2

    用例1、用例2

testcase.xls  接口测试用例等

conftest.py  放置了登录获取token供所有用例调用

run_all_case.py 执行所有测试用例并生成测试报告

logs

每天的日志数据

report

html  测试报告index.html

二、yaml文件基本配置

项目一:url: 'https://www.baidu.com/'headers:Content-Type: 'application/json'Authorization: 'token'account:a_account: '17900000000'b_account: '18000000000'c_account: '19900000000'c_account1: '19900000001'c_login:method: posturl: '/user/login'param:type: "7"login_from: 7mobile: "18888888888"code: "123456"c_sms_code:method: posturl: '/1.0/users/login'mysql:host: 127.0.0.1user: testpwd: testtest_db: user项目二:url: 'https://www.baidu.com/'

三、yaml文件sql配置

项目一:查id:- select_list- select id from A.B where create_mobile={}查用户id:- select_list- select id from A.B where mobile={}查团队id:- select_list- select id from A.B where company_user_id=(select id from A.B where mobile={})查C端用户id:- select_list- select user_id from A.B where mobile in({})解除用户:- update- update A.B set status=2 where mobile={}项目二:查id:- select_list- select id from A.B where create_mobile={}查用户id:- select_list- select id from A.B where mobile={}查团队id:- select_list- select id from A.B where company_user_id=(select id from A.B where mobile={})查C端用户id:- select_list- select user_id from A.B where mobile in({})解除用户:- update- update A.B set status=2 where mobile={}

四、读取yaml文件、excel用例文件

#!/usr/bin/env python
# _*_coding:utf-8_*_
import yaml,os,sys,xlwt,xlrd
from common.logs import Logclass ReadFile(object):log = Log()_instance=Nonedef __new__(cls,*args,**kwargs):if cls._instance is None:cls._instance=super().__new__(cls)return cls._instancedef __init__(self):self.excel_path = os.path.join(os.path.dirname(os.path.dirname(__file__)), 'config/testcase.xls')self.yaml_path = os.path.join(os.path.dirname(os.path.dirname(__file__)), 'config/test.yaml')self.sql_yaml_path = os.path.join(os.path.dirname(os.path.dirname(__file__)), 'config/sql.yaml')def read_yaml(self,path_type):"""读yaml文件:return:"""try:if path_type=='yaml_path':file_path=self.yaml_pathelif path_type=='sql_yaml_path':file_path=self.sql_yaml_pathwith open(file_path,'r',encoding='utf-8') as f:return yaml.load(f.read())except Exception as e:self.log.error("读yaml文件报错{}".format(e))def read_excel(self,sheet_name,function,casename=None):"""读取excel:param sheet_name::param function::return:"""try:book=xlrd.open_workbook(self.excel_path)sheet=book.sheet_by_name(sheet_name)param=[]for i in range(0,sheet.nrows):if casename==None:if sheet.row_values(i)[0]==function and sheet.row_values(i)[3]==1:param.append(sheet.row_values(i))else:if sheet.row_values(i)[0]==function and sheet.row_values(i)[1]==casename and sheet.row_values(i)[3]==1:param.append(sheet.row_values(i))return paramexcept Exception as e:self.log.error("读取excel报错{}".format(e))if __name__ == '__main__':test=ReadFile()print(test.read_excel('lxk','我的','全部页面'))

五、用例模板如下

根据每个sheet存放不同项目的测试用例,然后根据再根据sheet去读取对应项目模块的测试用例

Function模块、CaseName测试用例名、Type请求类型、Run是否执行、URL接口地址、Headers请求头、Param请求参数、SQL1、SQL2、SQL3测试中需用到的前置数据或后置数据、AssertType断言类型,因为接口返回的响应数据可能会多种多样,所以这里断言分了几种情况、Expect1预期结果1、Expect2预期结果2、Expect3预期结果3

六、request方法

#!/usr/bin/env python
# _*_coding:utf-8_*_
import requests,urllib3
from urllib3 import encode_multipart_formdata
from common.logs import Logclass RunMethod(object):"""request"""log = Log()urllib3.disable_warnings()def post_main(self,url,data,header,file=None):"""post请求:param url::param data::param header::param file::return:"""res=Noneif file!=None:res=requests.post(url=url,json=data,headers=header,verify=False)else:res = requests.post(url=url, json=data,headers=header, files=file, verify=False)return res.json()def get_main(self,url,header,param=None):"""get请求:param url::param header::param param::return:"""res=Noneif param!=None:res=requests.get(url=url,headers=header,verify=False)else:res = requests.get(url=url, headers=header, json=param,verify=False)return res.json()def run_main(self,method,url,header,data=None,file=None):"""被调用主request:param method::param url::param header::param data::param file::return:"""try:res=Noneif method=='post' or method=='POST' or method=='Post':res=self.post_main(url,data,header,file=None)elif method=='get' or method=='GET' or method=='Get':res=self.get_main(url,header,param=None)else:return "request传参错误"return resexcept Exception as e:self.log.error("请求方法报错{}".farmat(e))
if __name__ == '__main__':print(111)

七、登录方法

#!/usr/bin/env python
# _*_coding:utf-8_*_
from common import request
from common.readFile import ReadFile
from common.logs import Logclass Login(object):"""登录"""log = Log()request = request.RunMethod()def __init__(self):self.yaml_data = ReadFile().read_yaml('yaml_path')['lxk']self.header = self.yaml_data['headers']self.url = self.yaml_data['url']self.lxk_c_url = self.yaml_data['c_login']['url']self.lxk_c_method = self.yaml_data['c_login']['method']self.lxk_c_param = self.yaml_data['c_login']['param']def lxk_c_login(self,project,mobile):"""蓝薪卡C端登录:param project::param mobile::return:"""try:if project=='lxk_c':self.lxk_c_param['mobile']=mobileresult=self.request.run_main(self.lxk_c_method, self.url+self.lxk_c_url, self.header, self.lxk_c_param)elif project=='lxk_a':passelif project=='lxk_b':passreturn resultexcept Exception as e:self.log.error('登录报错{}'.format(e))if __name__ == '__main__':test=Login()print(test.lxk_c_login('lxk_c','18221124104'))

八、操作sql方法

#!/usr/bin/env python
# _*_coding:utf-8_*_
from common.readFile import ReadFile
import pymysql
import sys
from common.logs import Logclass ExecSql(object):"""执行sql语句类"""log = Log()_instance=Nonedef __new__(cls,*args,**kwargs):if cls._instance is None:cls._instance=super().__new__(cls)return cls._instancedef __init__(self):"""初始化mysql配置:param platform_name:"""#self.sql_conf = self._get_sql_conf(platform_name)self.sql_conf=Nonedef _get_sql_conf(self, project):"""获取mysql配置:param platform_name::return:"""try:return ReadFile().read_yaml('yaml_path')[project]['mysql']except:self.log.error("找不到对应项目:{0}".format(project))def connect_db(self):"""连接mysql:return:"""host = self.sql_conf['host']user = self.sql_conf['user']pwd = self.sql_conf['pwd']test_db = self.sql_conf['test_db']try:self.conn = pymysql.connect(host=host, user=user, password=pwd, db=test_db, port=3306, charset="utf8")except Exception as e:self.log.error("连接mysql失败:{0}".format(e))def get_cursor(self):"""获取游标:return:"""self.cursor=self.conn.cursor()return self.cursordef exec_sql(self,project,sql_type,sql):"""执行sql语句:param sql_type::param sql::return:"""self.sql_conf = self._get_sql_conf(project)try:if sql_type == 'select_one':self.connect_db()cursor = self.get_cursor()cursor.execute(sql)result = cursor.fetchone()elif sql_type == 'select_list':self.connect_db()cursor = self.get_cursor()cursor.execute(sql)result = cursor.fetchall()elif sql_type == 'update' or sql_type == 'del' or sql_type == 'insert':self.connect_db()result = self.get_cursor().execute(sql)self.conn.commit()self.cursor.close()self.conn.close()return resultexcept Exception as e:self.log.error("执行sql语句报错:{0}".format(e))if __name__ == '__main__':test = ExecSql()a=test.exec_sql('lxk',"select_list","sql)print(aaa)

九、日志方法

#!/usr/bin/env python
# _*_coding:utf-8 _*_
import os, time, logging
log_path=os.path.join(os.path.dirname(os.path.dirname(os.path.realpath(__file__))), 'logs')
if not os.path.exists(log_path): os.mkdir(log_path)class Log(object):"""log日志类"""def __init__(self):self.logname = os.path.join(log_path, '%s.log' % time.strftime('%Y_%m_%d'))self.logger = logging.getLogger()self.logger.setLevel(logging.DEBUG)self.formatter = logging.Formatter('[%(asctime)s]-%(filename)s]-%(levelname)s:%(message)s')def __console(self, level, message):fh=logging.FileHandler(self.logname, 'a', 'utf-8')fh.setLevel(logging.DEBUG)fh.setFormatter(self.formatter)self.logger.addHandler(fh)ch = logging.StreamHandler()ch.setLevel(logging.INFO)ch.setFormatter(self.formatter)self.logger.addHandler(ch)if level == 'info':self.logger.info(message)elif level == 'debug':self.logger.debug(message)elif level == 'warning':self.logger.warning(message)elif level == 'error':self.logger.error(message)self.logger.removeHandler(ch)self.logger.removeHandler(fh)fh.close()def debug(self, message):self.__console('debug', message)def info(self, message):self.__console('info', message)def warning(self, message):self.__console('warning', message)def error(self, message):self.__console('error', message)if __name__ == '__main__':log = Log()log.info("---测试---")

十、断言方法

#!/usr/bin/env python
# _*_coding:utf-8_*_
from common.execSql import ExecSql
from common.logs import Logclass Assertion(object):log=Log()sql_values_list = []response_values = []def __init__(self):self.test=ExecSql().exec_sqldef get_sql_data(self,project,sql_type,sql):'''查询sql数据组合list:param project::param sql_type::param sql::return:'''try:sql_values=self.test(project,sql_type,sql)for i in sql_values:for j in i:self.sql_values_list.append(j)except Exception as e:self.log.error("查询sql数据组合list报错{}".format(e))def get_response_data(self,response_data, keys=[]):'''获取接口响应数据组合list:param response_data::param keys::return:'''try:if isinstance(response_data, list):for value in response_data:if isinstance(value, list) or isinstance(value, dict):self.get_response_data(value, keys)elif isinstance(response_data, dict):for i, j in sorted(response_data.items()):if i in keys:self.response_values.append(j)else:self.get_response_data(j, keys)else:passexcept Exception as e:self.log.error("获取接口响应数据组合list报错{}".format(e))def asser(self,function,casename,expect,response_data,assert_type=None):'''断言:param assert_type::param expect::param response_data::return:'''try:if assert_type=='type1':assert self.sql_values_list==self.response_valuesself.log.info("查询sql数据组合list为{}".format(self.sql_values_list))self.log.info("接口响应数据组合list为{}".format(self.response_values))assert eval(expect)['code'] == response_data['code']assert eval(expect)['msg'] == response_data['msg']self.log.info("{}——{}【PASS】".format(function,casename))except Exception as e:self.log.error("{}——{}【PASS】{}".format(function,casename,e))if __name__ == '__main__':# sql="sql"# test=Assertion()# test.get_sql_data(self,project,sql_type,sql)self.log.error("查询sql数据组合list报错{}".format(e))

十一、conftest登录获取token

#!/usr/bin/env python
# _*_coding:utf-8_*_
import pytest,os,yaml,requests
from common.readFile import ReadFile
from common.login import Loginyaml_data=ReadFile().read_yaml('yaml_path')@pytest.fixture(scope='session')
def get_lxk_c_headers():"""登录获取token更新headers:return:"""headers=yaml_data['lxk']['headers']token=Login().lxk_c_login('lxk_c',yaml_data['lxk']['account']['c_account'])['data']['token']headers['Authorization']=tokenreturn headers

十二、测试用例方法

#!/usr/bin/env python
# _*_coding:utf-8_*_import pytest
from common.readFile import ReadFile
from common.request import RunMethod
from common.assertion import Assertion
from common.execSql import ExecSql
from common.prefixSqlData import MakeSqlData
import alluredata = ReadFile().read_excel('lxk', '我的报名')@pytest.mark.parametrize('function,casename,type,run,url,hearders,param,sql1,sql2,sql3,asserttype,expect1,expect2,expect3',data)
class Test(object):'''我的报名'''request = RunMethod().run_mainassertion = Assertion()exec_sql = ExecSql().exec_sqlyaml_data = ReadFile().read_yaml('yaml_path')['lxk']sql_yaml_data = ReadFile().read_yaml('sql_yaml_path')['lxk']prefix_sql_data = MakeSqlData('lxk').make_sql_datadef setup_class(self):'''数据初始化:return:'''prefix_data=self.prefix_sql_data(self.yaml_data['account']['b_account'], self.yaml_data['account']['c_account'])company_id = self.exec_sql('lxk', self.sql_yaml_data['查企业id'][0], self.sql_yaml_data['查企业id'][1].format(self.yaml_data['account']['b_account']))[0][0]task_id = self.exec_sql('lxk', self.sql_yaml_data['查任务id'][0], self.sql_yaml_data['查任务id'][1].format(self.yaml_data['account']['b_account']))[0][0]self.exec_sql('lxk', self.sql_yaml_data['报名任务'][0], self.sql_yaml_data['报名任务'][1].format(prefix_data['user_id'], task_id, company_id,self.yaml_data['account']['c_account'],1))self.exec_sql('lxk', self.sql_yaml_data['报名任务'][0], self.sql_yaml_data['报名任务'][1].format(prefix_data['user_id'], task_id, company_id,self.yaml_data['account']['c_account'],2))self.exec_sql('lxk', self.sql_yaml_data['报名任务'][0], self.sql_yaml_data['报名任务'][1].format(prefix_data['user_id'], task_id, company_id,self.yaml_data['account']['c_account'],3))self.exec_sql('lxk', self.sql_yaml_data['报名任务'][0], self.sql_yaml_data['报名任务'][1].format(prefix_data['user_id'], task_id, company_id,self.yaml_data['account']['c_account'],4))self.exec_sql('lxk', self.sql_yaml_data['报名任务'][0], self.sql_yaml_data['报名任务'][1].format(prefix_data['user_id'], task_id, company_id,self.yaml_data['account']['c_account'],5))self.exec_sql('lxk', self.sql_yaml_data['报名任务'][0], self.sql_yaml_data['报名任务'][1].format(prefix_data['user_id'], task_id, company_id,self.yaml_data['account']['c_account'],7))self.exec_sql('lxk', self.sql_yaml_data['报名任务'][0], self.sql_yaml_data['报名任务'][1].format(prefix_data['user_id'], task_id, company_id,self.yaml_data['account']['c_account'], 8))def teardown_class(self):'''数据清理:return:'''self.exec_sql('lxk', self.sql_yaml_data['删除已报名任务'][0], self.sql_yaml_data['删除已报名任务'][1].format(self.yaml_data['account']['c_account']))self.exec_sql('lxk', self.sql_yaml_data['解除用户团队'][0], self.sql_yaml_data['解除用户团队'][1].format(self.yaml_data['account']['c_account']))#@allure.feature('蓝薪卡')@allure.story('lxk_我的报名')def test_apply_task(self,get_lxk_c_headers,function,casename,type,run,url,hearders,param,sql1,sql2,sql3,asserttype,expect1,expect2,expect3):'''我的报名:param get_lxk_c_headers::param function::param casename::param type::param run::param url::param hearders::param param::param sql1::param sql2::param sql3::param asserttype::param expect1::param expect2::param expect3::return:'''response_data = self.request(type,self.yaml_data['url']+url,get_lxk_c_headers,eval(param))self.assertion.get_sql_data('lxk',eval(sql1)[0],eval(sql1)[1].format(self.yaml_data['account']['c_account']))self.assertion.get_response_data(response_data,eval(expect2))self.assertion.asser(function,casename,expect1,response_data,asserttype)if __name__ == "__main__":pytest.main(["-s", "test_001_applyTask.py"])

十三、run_all_case主程序执行入口

#!/usr/bin/env python
# _*_coding:utf-8_*_
import pytest,os,allure
if __name__ == "__main__":pytest.main(['-s',''])#生成测试报告jsonpytest.main(["-s", "-q", '--alluredir', 'C:/Users/wangli/PycharmProjects/PytestAutomation/report/result'])#将测试报告转为html格式split='allure '+'generate '+'C:/Users/wangli/PycharmProjects/PytestAutomation/report/result '+'-o '+'C:/Users/wangli/PycharmProjects/PytestAutomation/report/html '+'--clean'os.system('cd C:/Users/wangli/PycharmProjects/PytestAutomation/report')os.system(split)print(split)

十四、测试报告如下

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

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

相关文章

Jmeter BeanShell取样器操作变量(一)

vars: 引用Jmeter线程的局部变量,将 局部变量 改为 全局变量 亦可达到引用全局变量的效果, 连通Jmeter 和 beanshell string user vars.get("user")//获取变量,保存变量 vars.put(String key, String value&#xf…

Jmeter Beanshell采样器调用JAVA方法(二)

BeanShell Sampler调用添加的java方法 1、BeanShell Sampler里添加java方法 public static String test() {vars.put("jmeter1","111");vars.put("jmeter2","222");vars.put("jmeter3","333");vars.put("j…

Jmeter BeanShell采样器提取接口响应并传递(三)

1、将fastjson-1.2.68.jar放置C:\jmeter\apache-jmeter-5.0\lib路径下 2、CSV 数据文件设置多个手机号 3、添加登录接口,${mobile}调用2种的mobile值 4、登录接口响应数据 5、BeanShell 取样器提取登录接口响应数据 //导入json包 import com.alibaba.fastjson.JSON…

Jmeter BeanShell采样器提取接口响应写入csv文件(四)

1、调用登录接口获取response数据 {"code":0,"msg":"成功","data":{"token":"bearereyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJodHRwOlwvXC9tZW1iZXItYXBpLnN0MS50ZXN0LmxhbnhpbmthLmNvbVwvMi4wXC91c2Vyc1wvb…

Jmeter JDBC Request执行多条SQL语句

之前写过Jmeter操作mysql的文章https://blog.csdn.net/qq_36502272/article/details/88891873今天我们再看下如何操作多条sql语句 1、添加JDBC Connection Configuration并配置 Database URL为MySQL的连接串,如果要执行多条SQL语句,后面还要添加“?al…

Pytest之pytest-assume同用例多断言,断言1失败会执行后续代码及断言2

一般我们做自动化测试时,一个用例会写多个断言,当第一个断言失败后,后面的代码就不会执行了,于是我们引进了pytest-assume插件可以解决断言失败后继续断言的问题。一、安装依赖包pip install pytest-assume二、使用assert进行断言…

无法打开包括文件: “corecrt.h”: No such file or directory

刚开始安装qt,测试是否安装成功就出现此问题,让人很头大 参考:https://blog.csdn.net/x356982611/article/details/51140807的播客 编译时候使用的是最新的sdk版本10.0.10586.0版本但是它里面没有ucrt目录,问题找到了。 看了下v…

Pytest参数选项在脚本中和命令行用法详解

运行pytest可以指定目录和文件,如果不指定,pytest会搜索当前目录及其子目录中以test_开头或以_test结尾得测试函数。我们把pytest搜索测试文件和测试用例的过程称为测试搜索(test discovery)。只要遵循pytest的命名规则&#xff0…

Win7下OpenCV3.2.0+VS2015配置

参考自:https://blog.csdn.net/qq_22812319/article/details/78335880 一、预备知识 1、下载opencv时,opencv与vs版本是有固定关系的。 2、vs一般使用release版本。 3、首先在下载的openCV解压目录opencv/build/x64/下查看文件夹名,如下图…

win7 vs2015配置qt5.11

1、下载vs,和qt。 qt百度网盘下载链接:https://pan.baidu.com/s/12bUt31_mXGvgc3tdJRkkkw 提取码:2swk 下载完成之后,直接进行安装,下一步。 安装的时候要根据自己的VS版本选择相应的msvc(VC运行库&…

原创 | 开源AI测试专题、Jmeter测试专题

开源 AI 测试专题震惊!AI成功落地自动化测试AI 软件测试工具 Mabl 快速概览AI测试工具 Mabl - 测试用例自动自愈Sauce Labs 的持续 UI 自动化测试云疫情中诞生的 AI 测试工具:ai-webdriverAI 测试又多新花招?ai-webdriver-1.0.1 独家更新一眼…

Python深层解析json数据之JsonPath

我们在做接口自动化时,一般接口响应的都是json数据体,对响应数据进行提取使用或断言,当数据量很大或层级很深时,就会变得很麻烦,于是就可以用到jsonpath模块,解决json路径深取值难的问题。一、 jsonpath介绍…

VS2015+qt5.11入门(实现计算机的加法和登录操作)

1、在vs中新建qt项目 2、打开Form Files中的.ui文件。即打开qt creator界面 3、在界面中添加两个label,两个LineEdit,一个计算按钮。点击保存 控件右击-->改变对象名称可以直接改变控件名。(会映射显示在vs中的ui_projectname.h中&…

抓包工具mitmproxy环境配置使用(一)

一、mitmproxy介绍mitmproxy是一款开源的抓包工具,支持SSL的HTTP代理,它可以用于调试HTTP通信,发起中间人攻击等,还可以配合自定义python脚本使用,不同于 fiddler 或 wireshark 等抓包工具,mitmproxy 不仅可…

Pytest fixture参数化params

unittest使用ddt来实现测试用例参数化、或parameterized实现测试用例参数化,pytest测试用例里面对应的参数可以用 parametrize 实现参数化,今天我们来了解下fixture参数化paramsfixture的参数可以解决大量重复代码工作,比如数据库的连接、查询、关闭等.同…

python3中选择文件对话框的格式打开和保存图片

tkinter.filedialog.asksaveasfilename() # 选择以什么文件名保存,返回文件名 tkinter.filedialog.askopenfilename() # 选择打开什么文件,返回文件名有时候我们想要以选择文件对话框的格式打开一张图片或者保存图片,我在尝试之后把我的…

Python测试开发django1.简介

Django是一种基于Python开发的开源的高级Web应用框架,使用Django,使你能够以最小的代价构建和维护高质量的Web应用。Django 本身基于 MVC 模型,即 Model(模型) View(视图) Controller&#xff0…

Python测试开发django2.环境部署项目创建

Django是由Python编写的Web框架,依赖Python环境,所以需要提前安装好Python环境。建议安装最新版本的Python3,Python 下载地址:https://www.python.org/downloads/1、Django官网https://www.djangoproject.com/2、Django版本Django…

excel如何输入毫秒级时间

1、选择单元格或单元格区域; 2、右击-设置单元格格式(或按ctrl1); 3、数字选项卡-自定义-h:mm:ss.000 4、单元格就可以输入精度为千分之一秒的时间,如:20:15:21.451 参考自https://zhidao.baidu.com/questi…

Python测试开发django3.视图和URL配置

1、Django path()方法Django路由系统中最重要的path()方法可以接收4个参数,其中2个是必须的:route和view,以及2个可选的参数:kwargs和namedef path(route, view, kwargsNone, nameNone):return re_path(rou…