基于drf_yasg插件 生成开发文档(概要设计和详细设计)

问题

对于开发者,编写文档是非常头疼的问题。但是又是项目交付必须要的部分。

说明

  1. 此文是基于drf_yasg插件生成详细设计和概要设计文档,但只是框架性的,以及接口部分可以自动生成,个性化内容还需要自己去填充。

  2. 输出格式为markdown格式,还需要编辑后,转换为pdf格式,形成文档。

代码部分

# -*- coding: UTF-8 -*-
# Desc   : 项目输出api文档(详细设计文档和概要设计)
import time
import requests


def magic_api(markdown_path: str, swagger_url: str):
    """
    将api输出为markdown文档
    :param markdown_path: markdown输出路径
    :param swagger_url: swagger的json数据请求url
    :return:
    """
    res = requests.get(swagger_url)
    swagger_info = res.json()
    # title = swagger_info['info']['title']
    # TODO 修改项目名称
    project_name='项目名称'
    title_txt = '# %s 详细设计文档' % project_name
    base_url = swagger_info['basePath']
    # 文档前部分
    files_list=[]
    files_list.append('- 文档时间:%s'%(time.strftime('%Y-%m-%d'),))
    files_list.append('## 1 简介')
    files_list.append('### 1.1 目的')
    files_list.append(' 本文档旨在说明%s各模块的总体设计思路,为软件编程和系统维护提供依据。本说明书的预期读者为系统设计人员、软件开发人员、软件测试人员和项目评审人员。'%(project_name,))
    files_list.append('### 1.2 范围')
    # TODO 修改模块组成
    files_list.append(' 对%s中的各个模块进行详细的描述,包括%s。'%(project_name,'模块组成'))
    files_list.append('### 1.3 缩略语')
    files_list.append("|缩略语|英文全称|中文解释|")
    files_list.append("|:-:|:-:|:-:|")
    files_list.append('|%s|' % '|'.join(['','','']))

    files_list.append('## 2 系统架构')
    files_list.append('## 3 功能结构')
    files_list.append('## 4 各模块详细设计')
    # 文档结尾部分
    ends_list=[]
    ends_list.append('## 5	数据流详细设计')
    ends_list.append('### 5.1	数据源')
    ends_list.append('### 5.2	数据流转')
    ends_list.append('## 6	系统部署描述')
    ends_list.append('## 7	参考资料')

    # 文档api部分
    words_list = []
    model_tags={
    	# TODO
    	# 模块名:模块含义
        'auth':'登录模块',
    }
    # 遍历url
    for k, v in swagger_info['paths'].items():
        url = base_url + k
        # tags为模块名称占位符
        files_text = [url, 'tags']
        files_text.append("\n")
        files_text.append("#### %s" % url)

        for method, values in v.items():
            if method == 'parameters':
                continue
            files_text.append("- **请求方法:%s**" % method)
            files_text.append("接口用途:%s" % values['description'])
            # 模块名称
            files_text[1] = values['tags'][0]
            # 获取请求参数
            files_text.append('- 请求参数')
            files_text.append("|参数名称|参数含义|数据类型|是否必须|枚举数据|默认值|备注|")
            files_text.append("|-|-|:-:|:-:|:-:|:-:|-|")
            # 处理参数
            for parameter in values['parameters']:
                parm_list = []
                # 处理结构化(object类型)的参数
                if parameter['name'] == 'data':
                    schema = parameter['schema']

                    for zi_parm, zi_value in schema['properties'].items():
                        schema_list = []
                        schema_list.append(zi_parm)
                        schema_list.append(zi_value['description'])

                        schema_list.append(zi_value['type'])
                        schema_list.append('')
                        schema_list.append('')
                        schema_list.append('')
                        schema_list.append('')
                        parm_list.append(schema_list)
                        # print('参数名称:', zi_parm, '参数描述:', zi_value['description'], '参数类型:', zi_value['type'])
                else:
                    parm_list.append(parameter['name'])
                    parm_list.append(parameter['description'])
                    parm_list.append(parameter['type'])
                    parm_list.append('是' if parameter.get('required') else '否')
                    parm_list.append(str(parameter.get('enum')) if parameter.get('enum') else '')
                    parm_list.append(str(parameter.get('default')) if parameter.get('default') else '')
                    parm_list.append('')

                for i in parm_list:
                    if isinstance(i, list):
                        files_text.append('|%s|' % '|'.join(i))
                if parm_list and parm_list[0]:
                    if isinstance(parm_list[0], str):
                        files_text.append('|%s|' % '|'.join(parm_list))
            # 响应
            files_text.append('- 响应结果')
            files_text.append("|响应状态码|描述|返回值示例|备注|")
            files_text.append("|:-:|:-:|:-:|:-:|")
            for res_key, res_value in values['responses'].items():
                resp_list = []
                resp_list.append(res_key)
                resp_list.append(res_value['description'])
                examples = res_value.get('examples')
                example_txt = ''
                if examples:
                    for k, v in examples.items():
                        example_txt += k + ' : '
                        example_txt += str(v)
                resp_list.append(example_txt)
                resp_list.append('')
                files_text.append('|%s|' % '|'.join(resp_list))
        words_list.append(files_text)
    words_list.sort(key=lambda x: x[1])
    with open(markdown_path, 'w', encoding='utf-8') as fw:
        fw.write(title_txt + '\n\n')
        fw.write('\n'.join(files_list)+'\n')
        model_name = []
        for url in words_list:
            if url[1] not in model_name:
                chinese_model_name=model_tags.get(url[1])
                if not chinese_model_name:
                    chinese_model_name=url[1]
                fw.write('### %s%s' % (chinese_model_name, '\n'))
                model_name.append(url[1])
            fw.write('\n'.join(url[2:]) + '\n')
        fw.write('\n'.join(ends_list))


def outline_design(markdown_path: str, swagger_url: str):
    """
    将api输出为markdown文档,作为概要设计
    :param markdown_path: markdown输出路径
    :param swagger_url: swagger的json数据请求url
    :return:
    """
    res = requests.get(swagger_url)
    swagger_info = res.json()
    # title = swagger_info['info']['title']
    project_name = '项目名称'
    title_txt = '# %s 概要设计文档' % project_name
    base_url = swagger_info['basePath']
    # 文档前部分
    files_list = []
    files_list.append('- 文档时间:%s' % (time.strftime('%Y-%m-%d'),))
    files_list.append('## 1 简介')
    files_list.append('### 1.1 文档目标')
    files_list.append('1. 本文档旨在说明%s系统的总体设计思路,为软件编程和系统维护提供依据。'%(project_name,))
    files_list.append('2. 本文描述%s系统结构,给出模块的边界。'%(project_name,))
    files_list.append('3. 此文档从构架方面对%s系统进行综合概述,记录并表述已在构架方面对目标系统作出的重要决定。'%(project_name,))
    files_list.append('4. 此文档针对%s的需求文档进行业务架构建模,并对后续的详细设计和Coding提供指导和参照。'%(project_name,))
    files_list.append('### 1.2 适用对象')
    files_list.append('本文适合相关的产品、研发、测试人员等相关人员阅读。')
    files_list.append('1. 产品经理:了解此系统的功能架构和模块设计。')
    files_list.append('2. 开发工程师:遵循本文档进行详细设计和后续的编码工作')
    files_list.append('3. 测试人员:了解此系统的功能架构和模块设计,指导测试用例编写。')
    files_list.append('### 1.3 范围')
    files_list.append("本文档主要涉及:")
    files_list.append("1. 根据产品需求及原型设计进行功能模块划分,本系统模块主要包括大屏首页,遥感底图,图斑模块,用户模块,报表模块。")
    files_list.append("2. 对系统的各个模块进行详细的描述,包括各个功能模块间的关系描述,以及模块对外提供接口的详细描述。")
    files_list.append("本文档不涉及以下内容:")
    files_list.append("1. 不涉及各个模块内部详细功能,此部分请参考《%s系统详细设计》。"%(project_name,))

    files_list.append('### 1.4 参考资料')
    files_list.append('### 1.5 术语列表')
    files_list.append("|术语(缩写)|解释|")
    files_list.append("|:-:|:-:|")
    files_list.append('|%s|' % '|'.join(['','']))
    files_list.append('## 2. 总体技术方案')
    files_list.append('### 2.1 设计概述')
    files_list.append('1. 系统从功能实现的角度主要分为')
    files_list.append('2. 系统从页面展示角度主要分为')
    files_list.append('### 2.2 总体架构')
    files_list.append('#### 2.2.1 软件结构图')
    files_list.append('#### 2.2.2 功能结构图')
    files_list.append('#### 2.2.3 接口说明')

    # 文档结尾部分
    ends_list = []
    ends_list.append('#### 2.2.4 数据流分析')
    ends_list.append('##### 2.2.4.1 数据源')
    ends_list.append('##### 2.2.4.2 数据流转')
    ends_list.append('数据的处理分为三个阶段:数据获取、数据处理、数据入库。')
    ends_list.append('(1)数据获取')
    ends_list.append('(2)数据处理')
    ends_list.append('(3)数据及入库')
    ends_list.append('##### 2.2.4.3 流程图')

    # 文档api部分
    words_list = []
    model_tags = {
    	# TODO 
        'auth': '登录模块',
    }
    # 遍历url
    for k, v in swagger_info['paths'].items():
        url = base_url + k
        # tags为模块名称占位符
        files_text = [url, 'tags']
        files_text.append("\n")
        files_text.append("###### %s" % url)

        for method, values in v.items():
            if method == 'parameters':
                continue
            files_text.append("- **请求方法:%s**" % method)
            files_text.append("接口用途:%s" % values['description'])
            # 模块名称
            files_text[1] = values['tags'][0]
            # 获取请求参数
            files_text.append('- 请求参数')
            files_text.append("|参数名称|参数含义|数据类型|是否必须|枚举数据|默认值|备注|")
            files_text.append("|-|-|:-:|:-:|:-:|:-:|-|")
            # 处理参数
            for parameter in values['parameters']:
                parm_list = []
                # 处理结构化(object类型)的参数
                if parameter['name'] == 'data':
                    schema = parameter['schema']

                    for zi_parm, zi_value in schema['properties'].items():
                        schema_list = []
                        schema_list.append(zi_parm)
                        schema_list.append(zi_value['description'])

                        schema_list.append(zi_value['type'])
                        schema_list.append('')
                        schema_list.append('')
                        schema_list.append('')
                        schema_list.append('')
                        parm_list.append(schema_list)
                        # print('参数名称:', zi_parm, '参数描述:', zi_value['description'], '参数类型:', zi_value['type'])
                else:
                    parm_list.append(parameter['name'])
                    parm_list.append(parameter['description'])
                    parm_list.append(parameter['type'])
                    parm_list.append('是' if parameter.get('required') else '否')
                    parm_list.append(str(parameter.get('enum')) if parameter.get('enum') else '')
                    parm_list.append(str(parameter.get('default')) if parameter.get('default') else '')
                    parm_list.append('')

                for i in parm_list:
                    if isinstance(i, list):
                        files_text.append('|%s|' % '|'.join(i))
                if parm_list and parm_list[0]:
                    if isinstance(parm_list[0], str):
                        files_text.append('|%s|' % '|'.join(parm_list))
            # 响应
            files_text.append('- 响应结果')
            files_text.append("|响应状态码|描述|返回值示例|备注|")
            files_text.append("|:-:|:-:|:-:|:-:|")
            for res_key, res_value in values['responses'].items():
                resp_list = []
                resp_list.append(res_key)
                resp_list.append(res_value['description'])
                examples = res_value.get('examples')
                example_txt = ''
                if examples:
                    for k, v in examples.items():
                        example_txt += k + ' : '
                        example_txt += str(v)
                resp_list.append(example_txt)
                resp_list.append('')
                files_text.append('|%s|' % '|'.join(resp_list))
        words_list.append(files_text)
    words_list.sort(key=lambda x: x[1])
    with open(markdown_path, 'w', encoding='utf-8') as fw:
        fw.write(title_txt + '\n\n')
        fw.write('\n'.join(files_list) + '\n')
        model_name = []
        for url in words_list:
            if url[1] not in model_name:
                chinese_model_name = model_tags.get(url[1])
                if not chinese_model_name:
                    chinese_model_name = url[1]
                fw.write('##### %s%s' % (chinese_model_name, '\n'))
                model_name.append(url[1])
            fw.write('\n'.join(url[2:]) + '\n')
        fw.write('\n'.join(ends_list))

if __name__ == '__main__':
	# drf_yasg接口url
    url = 'http://172.27.11.200:8001/redoc/?format=openapi'
	# 详细设计文档
    # magic_api('./test_api.md', url)
    # 概要设计文档
    outline_design('./outline_design.md', url)
  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值