1
0
forked from erp-dev/erp
Files
erpnew/docs/upload.md

9.1 KiB
Raw Permalink Blame History

文件上传接口文档

概述

通用文件上传接口,用于上传无法归类到具体业务的文件。

基础路径: /api/v1/upload/

认证要求: 所有接口都需要 JWT Token 认证

内容格式: multipart/form-data (上传时) / application/json (响应)

注意事项:

  • 不支持列表查询list
  • 不支持修改操作PUT/PATCH
  • 仅支持单个文件查询、上传、删除操作

数据模型

UploadedFile

字段 类型 说明
id integer 文件ID
path string 文件存储路径(随机文件名)
file_url string 文件访问URL
owner integer 上传者用户ID
owner_username string 上传者用户名
is_deleted boolean 是否已删除(软删除标记)
original_filename string 原始文件名
file_size integer 文件大小(字节)
content_type string MIME类型如 image/jpeg
created_at datetime 创建时间
updated_at datetime 更新时间

接口列表

1. 上传文件

请求

POST /api/v1/upload/
Content-Type: multipart/form-data
Authorization: Bearer <token>

请求参数

参数 类型 必填 说明
file file 要上传的文件最大100MB

请求示例

curl -X POST http://localhost:8000/api/v1/upload/ \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -F "file=@/path/to/your/file.pdf"

成功响应 (201 Created)

{
  "id": 1,
  "path": "uploads/2025/11/17/a1b2c3d4e5f6...hex.pdf",
  "file_url": "/media/uploads/2025/11/17/a1b2c3d4e5f6...hex.pdf",
  "owner": 1,
  "owner_username": "admin",
  "is_deleted": false,
  "original_filename": "document.pdf",
  "file_size": 1048576,
  "content_type": "application/pdf",
  "created_at": "2025-11-17T10:30:00Z",
  "updated_at": "2025-11-17T10:30:00Z"
}

错误响应 (400 Bad Request)

{
  "file": ["未上传文件"]
}
{
  "file": ["文件大小不能超过100MB"]
}

安全特性:

  • 文件名使用 UUID 随机化,防止文件名冲突和路径遍历攻击
  • 原始文件名保存在数据库中,不影响存储安全
  • 自动记录上传者信息

2. 获取文件信息

请求

GET /api/v1/upload/{id}/
Authorization: Bearer <token>

路径参数

参数 类型 必填 说明
id integer 文件ID

请求示例

curl -X GET http://localhost:8000/api/v1/upload/1/ \
  -H "Authorization: Bearer YOUR_TOKEN"

成功响应 (200 OK)

{
  "id": 1,
  "path": "uploads/2025/11/17/a1b2c3d4e5f6...hex.pdf",
  "file_url": "/media/uploads/2025/11/17/a1b2c3d4e5f6...hex.pdf",
  "owner": 1,
  "owner_username": "admin",
  "is_deleted": false,
  "original_filename": "document.pdf",
  "file_size": 1048576,
  "content_type": "application/pdf",
  "created_at": "2025-11-17T10:30:00Z",
  "updated_at": "2025-11-17T10:30:00Z"
}

错误响应 (404 Not Found)

{
  "detail": "未找到"
}

注意: 已软删除的文件无法通过此接口查询


3. 软删除文件

请求

DELETE /api/v1/upload/{id}/
Authorization: Bearer <token>

路径参数

参数 类型 必填 说明
id integer 文件ID

请求示例

curl -X DELETE http://localhost:8000/api/v1/upload/1/ \
  -H "Authorization: Bearer YOUR_TOKEN"

成功响应 (200 OK)

{
  "detail": "文件已标记为删除"
}

说明:

  • 软删除不会物理删除文件,只是标记为已删除
  • 软删除后的文件无法通过常规接口查询
  • 可以通过恢复接口恢复文件

4. 恢复已删除文件

请求

POST /api/v1/upload/{id}/restore/
Authorization: Bearer <token>

路径参数

参数 类型 必填 说明
id integer 文件ID

请求示例

curl -X POST http://localhost:8000/api/v1/upload/1/restore/ \
  -H "Authorization: Bearer YOUR_TOKEN"

成功响应 (200 OK)

{
  "detail": "文件已恢复",
  "data": {
    "id": 1,
    "path": "uploads/2025/11/17/a1b2c3d4e5f6...hex.pdf",
    "file_url": "/media/uploads/2025/11/17/a1b2c3d4e5f6...hex.pdf",
    "owner": 1,
    "owner_username": "admin",
    "is_deleted": false,
    "original_filename": "document.pdf",
    "file_size": 1048576,
    "content_type": "application/pdf",
    "created_at": "2025-11-17T10:30:00Z",
    "updated_at": "2025-11-17T10:30:00Z"
  }
}

错误响应 (400 Bad Request)

{
  "detail": "文件未被删除,无需恢复"
}

5. 永久删除文件

请求

DELETE /api/v1/upload/{id}/permanent_delete/
Authorization: Bearer <token>

路径参数

参数 类型 必填 说明
id integer 文件ID

请求示例

curl -X DELETE http://localhost:8000/api/v1/upload/1/permanent_delete/ \
  -H "Authorization: Bearer YOUR_TOKEN"

成功响应 (204 No Content)

{
  "detail": "文件已永久删除"
}

说明:

  • 永久删除会物理删除文件和数据库记录
  • 此操作不可恢复,请谨慎使用
  • 建议仅在确认不需要时使用

使用示例

Python (requests)

import requests

# 配置
BASE_URL = "http://localhost:8000/api/v1"
TOKEN = "your_jwt_token"
headers = {"Authorization": f"Bearer {TOKEN}"}

# 1. 上传文件
with open('document.pdf', 'rb') as f:
    files = {'file': f}
    response = requests.post(
        f"{BASE_URL}/upload/",
        headers=headers,
        files=files
    )
    file_data = response.json()
    file_id = file_data['id']
    print(f"上传成功文件ID: {file_id}")

# 2. 获取文件信息
response = requests.get(
    f"{BASE_URL}/upload/{file_id}/",
    headers=headers
)
print(f"文件信息: {response.json()}")

# 3. 软删除文件
response = requests.delete(
    f"{BASE_URL}/upload/{file_id}/",
    headers=headers
)
print(f"软删除: {response.json()}")

# 4. 恢复文件
response = requests.post(
    f"{BASE_URL}/upload/{file_id}/restore/",
    headers=headers
)
print(f"恢复文件: {response.json()}")

# 5. 永久删除
response = requests.delete(
    f"{BASE_URL}/upload/{file_id}/permanent_delete/",
    headers=headers
)
print(f"永久删除完成")

JavaScript (Axios)

const axios = require('axios');
const FormData = require('form-data');
const fs = require('fs');

const BASE_URL = 'http://localhost:8000/api/v1';
const TOKEN = 'your_jwt_token';
const headers = { Authorization: `Bearer ${TOKEN}` };

// 1. 上传文件
async function uploadFile() {
  const formData = new FormData();
  formData.append('file', fs.createReadStream('document.pdf'));
  
  const response = await axios.post(
    `${BASE_URL}/upload/`,
    formData,
    { headers: { ...headers, ...formData.getHeaders() } }
  );
  
  console.log('上传成功:', response.data);
  return response.data.id;
}

// 2. 获取文件信息
async function getFileInfo(fileId) {
  const response = await axios.get(
    `${BASE_URL}/upload/${fileId}/`,
    { headers }
  );
  console.log('文件信息:', response.data);
}

// 3. 软删除
async function softDelete(fileId) {
  const response = await axios.delete(
    `${BASE_URL}/upload/${fileId}/`,
    { headers }
  );
  console.log('软删除:', response.data);
}

// 4. 恢复文件
async function restore(fileId) {
  const response = await axios.post(
    `${BASE_URL}/upload/${fileId}/restore/`,
    {},
    { headers }
  );
  console.log('恢复:', response.data);
}

// 5. 永久删除
async function permanentDelete(fileId) {
  const response = await axios.delete(
    `${BASE_URL}/upload/${fileId}/permanent_delete/`,
    { headers }
  );
  console.log('永久删除完成');
}

错误码说明

HTTP状态码 说明
200 成功
201 创建成功
204 删除成功(无内容)
400 请求参数错误
401 未认证或认证失败
403 无权限
404 资源不存在
413 文件过大
500 服务器内部错误

最佳实践

  1. 文件大小限制: 单文件最大100MB超过此限制会返回400错误
  2. 文件命名: 系统自动使用UUID生成随机文件名原始文件名保存在original_filename字段
  3. 软删除策略: 建议先使用软删除,确认不需要后再使用永久删除
  4. 文件访问: 使用返回的file_url字段访问文件
  5. 权限控制: 所有接口都需要认证,上传的文件自动关联当前用户

注意事项

  1. 不支持的操作:

    • 列表查询 (GET /api/v1/upload/)
    • 批量上传
    • 修改文件 (PUT/PATCH /api/v1/upload/{id}/)
  2. 文件存储:

    • 文件按日期组织:uploads/YYYY/MM/DD/
    • 文件名使用32位十六进制UUID
    • 保留原始文件扩展名
  3. 查询限制:

    • 默认查询会过滤掉已软删除的文件
    • 要访问已删除文件需要通过Django Admin或直接数据库查询
  4. 安全考虑:

    • 所有文件名随机化,防止路径遍历攻击
    • 需要JWT认证
    • 自动记录上传者信息