最近,我尝试把那些用 AI 写的小工具搬到网页上,想着能更方便地日常操作。于是,我决定从 Django 开始试试。
2 界面风格与数据库选择
2.1 界面设计
整个界面分成两部分,左边是功能菜单,右边则是展示和互动区域。整体采用浅色系,背景是白色的,尽量避免 AI 常用的紫色渐变。

在 Django 里,所有需要的图片和 CSS 文件都被称为静态资源,放在 app 目录里的 static 文件夹中。

这个小狮子 LOGO 是豆宝生成的,狮毛里有代表网络的星状拓扑,嘴巴下方有齿轮象征 devops,脑门上则有个 AI 芯片,我特别喜欢这个设计。

2.2 数据库选择
之前的 Python 代码用 JSON 数据格式(因为我实验的 Juniper 设备原生支持 JSON,同时 AI 还帮我生成了一个 HTML 用于转换 Excel 和 JSON 数据),体验相当顺畅。
这次我选择了 MySQL 作为数据库(其实我对 MySQL不太熟,正好借此机会学习一下)。Django 通过 ORM 来翻译并执行 MySQL 语句,这样操作起来比直接写 SQL 轻松多了。

数据 AI 是怎么处理旧数据的呢?它用 PyYAML 把 inventory 目录下的 hosts 和 group 两个 yaml 文件写入到数据库表中。
pip install PyYAML
Python manage.py import_h3c_switches --clear
MySQL -u root -p 密码 -e 「USE web_tool; SELECT switch_name, hostname, platform, username, device_type, port, timeout FROM h3c_switch LIMIT 10;」
MySQL -u root -p 密码 -e 「USE web_tool; SELECT COUNT(*) as total_switches FROM h3c_switch;」

同时,创建在 MySQL 中的数据还可以通过超级用户在 Django 的后台管理,这样管理起来更加方便。

3 功能与架构展示
3.1 Django 项目的结构:
web_tool/
├── app02/ # 应用 包含了所有的 py 代码
│ ├── __init__.py
│ ├── admin.py Django 默认提供了 admin 后台管理 非常好用
│ ├── apps.py app 启动类
│ ├── migrations
│ ├── models.py
│ ├── tests.py
│ └── views.py Python 函数
├── manage.py
└── web_project/
├── asgi.py 网络请求
├── settings.py 项目配置
├── urls.py url->和函数的对应关系
└── wsgi.py 网络请求
3.2 URL 设置
在 urls.py 文件中定义 HTML 与 views 函数的对应关系。

path(『config_backup/』, views.config_backup, name=『config_backup』),
3.3 视图(VIEWS)
这里是功能实现的关键代码,负责接收用户的请求(request),处理之后给用户反馈(网页、数据或重定向)。
Django 的 render 函数负责最终将「渲染」后的 HTML 页面返回给用户的浏览器。它的作用是把 views 函数中的数据(context)和模板(template)结合,生成完整的 HTML 页面,反馈给发起请求的用户。
return render(request, 『app02/config_backup.HTML』, context)
3.4 模型类(Model)
主页展示了整个维护系统的统计信息,数据从哪里来的呢?通过以下代码从 MySQL 获取。
# 获取统计数据
total_switches = h3c_switch.objects.count()
context = {
『app_name』: 『Leo』,
『total_switches』: total_switches,
}
return render(request, 『app02/index.HTML』, context)
Django 的模型类(Model)对应数据库中的一张表(比如存储交换机信息的表)。objects 可以理解为 ORM 用 Python 语言操作 MySQL 的接口。count 方法用于统计数量。
那么什么是 model 呢?Model 是 Django 中用来定义数据库结构的 Python 类,它相当于数据库的蓝图,决定了:
- 表结构:数据库里有哪些表
- 字段类型:每张表包含哪些列(如文本、数字、日期等)
- 数据关系:表与表之间是如何关联的(如一对一、一对多)
class h3c_switch(models.Model):
switch_name = models.CharField(max_length=100, verbose_name=『交换机名称』, help_text=『交换机的标识名称』)
hostname = models.CharField(max_length=100, verbose_name=『主机名/IP 地址』, help_text=『交换机的 IP 地址或主机名』)
platform = models.CharField(max_length=50, verbose_name=『平台型号』, help_text=『交换机的平台型号』)
username = models.CharField(max_length=50, verbose_name=『用户名』, help_text=『登录交换机的用户名』)
password = models.CharField(max_length=100, verbose_name=『密码』, help_text=『登录交换机的密码』)
port = models.IntegerField(default=22, verbose_name=『端口号』, help_text=『连接端口号,默认 22』)
device_type = models.CharField(max_length=50, default=『h3c』, verbose_name=『设备类型』, help_text=『设备类型标识』)
timeout = models.IntegerField(default=30, verbose_name=『超时时间』, help_text=『连接超时时间(秒)』)
Django 会根据 Model 的定义自动生成 SQL 语句来创建数据库表,不需要手动写 SQL,这点真是太棒了。
有了数据,我们就可以通过 Model.objects 来进行增删改查的操作。
3.5 功能展示
登录和退出界面


配置备份
设备信息保存在 inventory 目录,这里直接把之前 nornir 项目的数据复制过来。

生成的配置备份存放在 media 目录下,文件夹用时间戳命名:

设备巡检
inventory 和配置备份的数据一致,巡检命令直接写在代码里,输出结果存到本地
- results 保存了每台设备的 txt 格式结果
- Excel 是所有设备的巡检数据统计结果(用于巡检分析的输入)

巡检分析
导入巡检模块的 Excel 表格后生成分析结果
结果分为四个表格(CPU/内存/温度/电源与风扇状态)展示在界面上,并提供完整的 PDF 下载选项。

TCP 检测分析
输入目标 IP 和端口,进行检测并生成 TCP 握手延迟和 RTT 等参数,以此分析网络延迟。

ACL 匹配功能
这是我最初想要的功能,输入源 IP 和端口,查询源 IP 在两个 IRB 接口下的 ACL 所匹配的 filter 和 action 动作。因为之前已经写过相关的 py 代码,所以直接把成熟的代码扔给了 Qoder,写出的 Django 函数一次就成功了。

4 AI 代码解析
4.1 首页(index)
首先是我们的首页,先检查用户是否已登录,如果没有,就重定向到登录界面。
def index(request):
# 使用session来存储当前的登录状态
if not request.session.get('user_logged_in'):
return redirect('app02:user_login')
4.2 配置备份
老朋友 Nornir
# 初始化Nornir 获取到设备列表
nr = backup_tool.initialize_nornir()
host_list = list(nr.inventory.hosts.keys())
开始执行配置备份
# 执行配置备份
if is_ajax:
messages.info(request, '开始备份配置文件...')
logger.info(f"开始执行配置备份,备份目录: {backup_dir}")
backup_results = backup_tool.backup_all_devices(backup_dir)
logger.info(f"配置备份完成: 成功 {backup_results['success']}, 失败 {backup_results['failed']}")
这里 AI 调用了 backup_tool 对象的 backup_all_devices 方法。这个方法封装了与网络设备交互的逻辑,通过 SSH 登录设备并拉取配置,backup_dir 参数指定了备份文件的存放目录。

在这里有个判断,叫做if is ajax,你知道AJAX请求吗?简单来说,它是一种网络技术,能让网页在不刷新的情况下,从服务器拉取数据并更新部分内容。这种方式大大提升了用户的互动体验。
if is_ajax:
这个判断检查当前请求是否是一个AJAX请求。
messages.info(request, ' 开始备份配置文件...'):
如果是AJAX请求,Django的消息框架会悄悄地弹出一条提示,告诉用户备份已经开始了,即使页面没有刷新,也能让用户感受到良好的交互体验。

4.3 设备巡检
首先得创建一个存放结果的目录。
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
inspection_dir = os.path.join(settings.MEDIA_ROOT, 'h3c_inspe', timestamp)
os.makedirs(inspection_dir, exist_ok=True)
我们用时间戳来生成一个独一无二的巡检目录,目录路径为:MEDIA_ROOT/h3c_inspe/YYYYMMDD_HHMMSS。同时,AI还加了一行代码,确保这个目录是存在的。
inspection_tool = H3CDeviceInspection()
nr = inspection_tool.initialize_nornir()
host_list = list(nr.inventory.hosts.keys())
老朋友Nornir又来了,首先要初始化Nornir网络自动化框架,然后获取设备列表。
connection_results = inspection_tool.test_connection()
connected_devices = []
failed_devices = []
for host, result in connection_results.items():
if result["status"] == "success":
connected_devices.append(host)
# 发送成功消息
else:
failed_devices.append(host)
# 发送失败消息
我之前的代码没有提示功能,Qoder在这里发挥了创意,增加了用户交互的信息。通过test_connection来测试所有设备的连接状态,连接结果会被分类记录成功与失败,并实时发送状态消息(在AJAX模式下)。
inspection_results = inspection_tool.inspect_all_devices(inspection_dir)
接下来调用inspect_all_devices方法来执行巡检命令,并将结果存储到(inspection_dir)里。
def inspect_all_devices(self, inspection_dir: str) -> dict:
不过这里有个小问题,处理Excel数据的代码并没有直接在views主代码中,而是包含在inspect_all_devices里。
results = self.nr.run(
task=self.inspect_single_device
)
执行巡检结果的代码其实是用inspect_single_device这个函数,得继续找下一个函数。
def inspect_single_device(self, task: Task) -> Result:
# 执行所有巡检命令
commands = [
"display version",
"display cpu-usage",
"display memory",
"display environment",
"display fan",
"display power"
]
output = ""
for cmd in commands:
result = task.run(
task=netmiko_send_command,
command_string=cmd,
use_textfsm=False, # 不单独使用TextFSM解析
read_timeout=20
)
关于textfsm的模板,我们早已准备好了。
def _parse_device_output(self, filename, template_path):
这个_parse_device_output函数是用来解析数据的核心引擎,它负责把网络设备的原始命令行输出转化为结构化的数据。
with open(template_path, encoding='utf-8') as f:
fsm = textfsm.TextFSM(f)
接下来要加载模板。
raw_data = Path(filename).read_text(encoding='utf-8')
读取巡检文件的内容。
parsed = fsm.ParseText(raw_data)
最后将数据格式化成我们需要的结构。
df = pd.DataFrame(all_data) # 将数据列表转换为DataFrame
df.to_excel(writer, index=False, sheet_name='设备巡检结果') #将DataFrame写入Excel文件

4.4 巡检结果分析
首先看看巡检代码的输出结果,我们希望通过分析和处理这些结果,获取可视化图表和异常设备的数据。

页面还会提供一个窗口,让用户上传这个Excel表格。
if request.method == 'POST':
if 'excel_file' not in request.FILES:
messages.error(request, '请选择要上传的Excel文件')
return render(request, 'app02/inspection_analysis.html', context)
excel_file = request.FILES['excel_file']
接着,我们就开始处理数据,比如针对CPU进行分析:
def _generate_cpu_analysis(self, df, pdf):










