django-paramiko远程服务器和文件管理(五)
一、paramiko简介
1.paramiko是一个基于SSHv2协议的纯Python库。需要单独安装。
2.它提供了客户端和服务器的功能。
3.可以实现SSH2远程安全连接,支持用户名、密码连接,也支持密钥连接
4.一般用于执行远程命令、传输文件、中间SSH代理等
安装
pip3 install paramiko
在linux中安装过程报错:
Command "python setup.py egg_info" failed with error code 1 in /tmp/pip-build-obpexfgv/bcrypt/
解决:
pip3 install --upgrade pip3 setuptools
二、SSH连接
1.基于用户名和密码的连接
import paramiko
command = "cat /etc/passwd |awk -F: '{print $1}'|head"
# 要连接的主机的信息,以下是必填项
host_info = {
"hostname": "192.168.1.23",
"port": 22,
"username": "root",
"password": "服务器密码"
}
def ssh_host(hostinfo):
# 实例化一个SSHClient 对象,用于连接linux服务器使用
ssh_client = paramiko.SSHClient()
# 当使用用户名和密码首次连接linux服务器时会有连接提示,也是输入yes/no的提示。这里的设置就是会自动输入yes
ssh_client.set_missing_host_key_policy(paramiko.AutoAddPolicy)
try:
# 开始连接目标linux服务器
ssh_client.connect(**host_info)
except Exception:
print(f"连接{host_info['hostname']}失败")
else:
# 远程执行shell命令
stdin,stdout,stderr = ssh_client.exec_command(command)
# 这里decode的作用 1是解码 2是格式化
print(stdout.read().decode())
# 判断执行命令是否有报错,如果有报错就打印
if not stderr is None:
print(stderr.read().decode())
ssh_client.close()
if __name__ == "__main__":
ssh_host(host_info)
执行结果如下:
root
bin
daemon
adm
lp
sync
shutdown
halt
mail
operator
2.基于密钥的连接
import paramiko
command = "awk -F: '{print $1}' /etc/passwd"
# 读取私钥文件
private_key = paramiko.RSAKey.from_private_key_file('/root/.ssh/id_rsa')
host_info = {
"hostname": "192.168.1.106",
"port": 22,
"username": "root",
# 这里就是传递私钥文件
"pkey": private_key
}
def main(host_info):
ssh_client = paramiko.SSHClient()
ssh_client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
try:
ssh_client.connect(**host_info)
except Exception:
print(f"连接{host_info['hostname']}失败")
else:
stdin, stdout, stderr = ssh_client.exec_command(command)
# 这里decode的作用 1是解码 2是格式化
print(stdout.read().decode())
# 判断执行命令是否有报错,如果有报错就打印
if not stderr is None:
print(stderr.read().decode())
ssh_client.close()
if __name__ == '__main__':
main(host_info)
三、远程文件操作
1.STPClient类简介
SFTPClient作为一个SFTP客户端对象,根据SSH传输协议的sftp会话,实现远程操作,比如文件上传,下载,权限,状态等,端口就是SSH端口
方法 | 含义 |
---|---|
from_transport() | 创建一个已连通的SFTP客户端通道 |
put() | 上传本地文件到远程服务器 |
get() | 从远程服务器下载文件到本地 |
mkdir() | 在远程服务器上创建目录 |
remove() | 删除远程服务器中的文件 |
rmdir() | 删除远程服务器中的目录 |
rename() | 重命名远程服务器中的文件或目录 |
stat() | 获取远程服务器中文件的详细信息 |
listdir() | 列出远程服务器中指定目录下的内容 |
2.代码实例:
import paramiko
host_addr = (
'192.168.1.23',
22
)
user_info = {
"username": "root",
"password": "666666"
}
def sftp_host():
tran = paramiko.Transport(*host_addr)
tran.connect(**user_info)
sftp_client = paramiko.SFTPClient.from_transport(tran)
local_path = "D:/服务临时交付文件/zabbix_agent-6.0.3-linux-4.12-ppc64le-static.tar.gz"
remote_path = "/root/zabbix_agent-6.0.3-linux-4.12-ppc64le-static.tar.gz"
# 上传文件(下发文件)
sftp_client.put(local_path,remote_path)
# 下载文件
sftp_client.get(remote_path,local_path)
tran.close()
if __name__ == "__main__":
sftp_host()
四、django的文件上传
1.前端代码
准备工作
1.安装node
2.使用npm 安装pnpm工具
这里使用前端代码做测试的原因:
1.原生html input type=file 太丑了
2.必须在input type=file中加入enctype="multipart/form-data"属性,此属性的含义是:规定在发送到服务器之前应该如何对表单数据进行编码。如果没有这一行,django的 request.FILES的值是空的。所以在这里使用UI组件进行测试。看看是否也存在request.FILES为空的问题
1.1 配置代理地址
淘宝的地址使用vite创建项目报错,所以这里重新配置代理
npm config set registry https://registry.npmjs.org/
1.2 使用vite创建vue项目
pnpm create vite
cd 项目名称
# 安装依赖
pnpm install
# 启动项目
pnpm run dev
1.3 安装UI组件
1.3.1 安装ant-design-vue
pnpm install ant-design-vue --save
查看安装的版本
E:\code\project\前端项目\vue_test1\vue_test_project>pnpm list |findstr /i ant
ant-design-vue 4.1.2
1.3.2 安装icon组件
pnpm install --save @ant-design/icons-vue
1.4 引入UI组件
编辑main.js
import { createApp } from 'vue'
import App from './App.vue'
# 引入ant-desgin-vue组件的button按钮
import { Button } from 'ant-design-vue'
const app = createApp(App)
# 使用Button按钮组件
app.use(Button)
app.mount('#app')
1.5 测试
在浏览器中能够看到漂亮的按钮,就说明这里已经成功引用了ant-desgin-vue UI组件了.
<script setup>
</script>
<template>
<div>
<h1>app.vue</h1>
<!-- 使用引入的button按钮 -->
<a-button type="primary">按钮</a-button>
</div>
</template>
<style scoped>
</style>
1.6 上传文件完整代码
编辑App.vue文件
<template>
<div>
<a-upload v-model:file-list="fileList" list-type="picture" :max-count="10" multiple="true"
action="/upload" name='file' @change="handleChange">
<a-button type="primary">
<upload-outlined></upload-outlined>
上传文件
</a-button>
</a-upload>
<a-button type="primary" danger class="ClearBt" @click="clearfileList">
<DeleteOutlined />
清空列表
</a-button>
</div>
</template>
<script lang="js">
export default {
name: "App"
}
</script>
<script lang="js" setup>
import { ref } from 'vue';
import { UploadOutlined,DeleteOutlined } from '@ant-design/icons-vue'
import { message } from 'ant-design-vue';
const fileList = ref([
]);
function clearfileList(){
fileList.value = [];
}
function handleChange(info){
if (info.file.status == "done"){
message.success(`${info.file.name} 上传成功!`)
}
if (info.file.status == "error"){
message.error(`${info.file.name} 上传失败`)
}
}
</script>
<style scoped>
div {
position: relative;
margin: 0px auto;
width: 30%;
height: 800px;
background: #f5f5f5;
border-radius: 20px;
}
.ClearBt {
position: absolute;
top: 0px;
left: 111px;
}
</style>
参数解释:
list-type: 显示图片
max-count: 限制文件上传的数量
multiple:允许一次上传多个文件,而不是一次只允许上传单个文件
name: 这个参数必须要定义,否则后端无法获取前端提交的数据
main.js代码如下
import { createApp } from 'vue'
import App from './App.vue'
import { Button,Upload } from 'ant-design-vue'
const app = createApp(App)
app.use(Button)
app.use(Upload)
app.mount('#app')
1.7 编译前端代码
pnpm run build
编译成功后在 项目目录下生成dist目录,此目录下就是编译成功后的代码
2.部署前端代码
搭建nginx,过程省略
2.1 nginx server配置
server {
listen 16666;
server_name localhost;
root /data/wwwroot;
location / {
index index.html;
try_files $uri $uri/ /index.html;
}
location /upload {
proxy_pass http://127.0.0.1:18888/files/upload/;
}
}
nginx -s reload
2.2 上传前端代码
将编译好的所有的代码上传到/data/wwwroot目录下。访问:
http://IP地址:16666
3.部署后端代码
基础环境安装就不在说了
3.1 创建应用
django-admin startapp files
3.2 主路由
编辑项目目录下的urls.py文件
from django.urls import path,include
urlpatterns = [
path('files/',include('files.urls'))
]
3.3 子路由
在files应用下新建urls.py文件
from django.urls import path,include
from .views import *
urlpatterns = [
path('upload/', file_view.as_view()),
]
3.4 视图类
from rest_framework.views import APIView
from rest_framework.response import Response
import os
save_url = '/data/pic/'
class file_view(APIView):
def post(self,request):
# 获取前端上传的文件,注意这里get的 'file' 一定和前端upload 的name的值对应
pic_data = request.FILES.get('file')
# 判断是否能够获取到前端传输的数据,主要是看前端upload的name值是不是file
if not pic_data is None:
pic_name = pic_data.name
picFullUrl = save_url + pic_name
# 判断上传的文件是否重名
if not os.path.exists(picFullUrl):
with open(save_url + pic_name,'wb+') as fp:
# 这里使用chunks函数,是为分块处理,为了避免如果文件很大,一次性读取文件所有,而造成的内存不足现象
for chunk in pic_data.chunks():
fp.write(chunk)
return Response({"message":"文件上传成功"},status=200)
else:
# 这里之所有没有使用键值对的形式进行返回,是因为这个异常结果会显示在图片的悬浮提示上。
return Response("文件已经存在",status=409)
else:
# 这里之所有没有使用键值对的形式进行返回,是因为这个异常结果会显示在图片的悬浮提示上。
return Response("文件上传失败",status=505)
3.5 启动项目
python3 manage.py runserver 0.0.0.0:18888
4.访问测试
访问页面,查看图片是否能够上传成功