一、环境准备与依赖安装
在开始构建文件管理系统之前,我们需要准备好Python开发环境。本系统基于FastAPI框架开发,利用SQLAlchemy进行数据库管理,使用aiofiles处理异步文件IO。请确保你的操作系统已安装Python 3.8及以上版本。
在终端中执行以下命令来安装项目所需的全部依赖包。这些包涵盖了Web框架、服务器、数据库、文件处理以及表单数据解析等功能。
```bash
pip install fastapi uvicorn sqlalchemy aiofiles python-multipart
```
依赖包说明:
- fastapi:现代、高性能的Python Web框架。
- uvicorn:基于ASGI的服务器,用于运行FastAPI应用。
- sqlalchemy:强大的SQL工具包和对象关系映射(ORM)。
- aiofiles:用于异步文件读写操作。
- python-multipart:支持表单数据解析,是文件上传的必备库。
安装完成后,请在本地创建一个项目文件夹,例如命名为file_manager,并在其中创建一个名为uploads的子目录,用于存储上传的文件。
二、后端服务开发
后端是文件管理系统的核心,负责处理文件的存储、检索、下载和删除逻辑。我们将创建一个单文件应用main.py,其中包含数据库模型配置和API路由定义。
1. 数据库模型与配置
我们使用SQLite作为数据库,因为它无需配置服务器,适合快速落地。系统将自动创建一个file_management.db文件来存储文件元数据。
在main.py中写入以下代码:
```python
import os
import shutil
import uuid
from typing import List
from fastapi import FastAPI, UploadFile, File, HTTPException, Depends
from fastapi.responses import FileResponse
from fastapi.middleware.cors import CORSMiddleware
from sqlalchemy import create_engine, Column, String, Integer, DateTime
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker, Session
from datetime import datetime
配置
UPLOAD_DIR = "uploads"
if not os.path.exists(UPLOAD_DIR):
os.makedirs(UPLOAD_DIR)
DATABASE_URL = "sqlite:///./file_management.db"
engine = create_engine(DATABASE_URL, connect_args={"check_same_thread": False})
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
Base = declarative_base()
数据库模型
class FileRecord(Base):
__tablename__ = "files"
id = Column(String, primary_key=True, index=True)
filename = Column(String, index=True)
original_filename = Column(String)
file_path = Column(String)
upload_time = Column(DateTime)
file_size = Column(Integer)
创建表
Base.metadata.create_all(bind=engine)
依赖项:获取数据库会话
def get_db():
db = SessionLocal()
try:
yield db
finally:
db.close()
app = FastAPI()
添加CORS中间件,允许前端跨域访问
app.add_middleware(
CORSMiddleware,
allow_origins=[""],
allow_credentials=True,
allow_methods=[""],
allow_headers=[""],
)
```
2. 文件上传接口实现
上传接口需要接收文件对象,生成唯一的UUID作为文件名以防止冲突,将文件保存到磁盘,并将元数据写入数据库。请在main.py中继续添加以下代码:
```python
@app.post("/upload/")
async def upload_file(file: UploadFile = File(...), db: Session = Depends(get_db)):
读取文件内容
file_content = await file.read()
生成唯一文件名
file_extension = os.path.splitext(file.filename)[1]
unique_filename = f"{uuid.uuid4().hex}{file_extension}"
file_location = os.path.join(UPLOAD_DIR, unique_filename)
保存文件到磁盘
with open(file_location, "wb+") as file_object:
file_object.write(file_content)
记录到数据库
file_record = FileRecord(
id=uuid.uuid4().hex,
filename=unique_filename,
original_filename=file.filename,
file_path=file_location,
upload_time=datetime.now(),
file_size=len(file_content)
)
db.add(file_record)
db.commit()
db.refresh(file_record)
return {"message": "文件上传成功", "id": file_record.id, "filename": file_record.original_filename}
```
3. 文件列表与下载接口
我们需要提供接口来获取所有已上传文件的列表,以及根据ID下载特定文件的能力。继续添加以下代码:
```python
@app.get("/files/", response_model=List[dict])
async def list_files(db(db: Session = Depends(get_db))):
files = db.query(FileRecord).order_by(FileRecord.upload_time.desc()).all()
return [
{
"id": f.id,
"original_filename": f.original_filename,
"upload_time": f.upload_time.strftime("%Y-%m-%d %H:%M:%S"),
"file_size": f.file_size
} for f in files
]
@app.get("/download/{file_id}")
async def download_file(file_id: str, db: Session = Depends(get_db)):
file_record = db.query(FileRecord).filter(FileRecord.id == file_id).first()
if not file_record:
raise HTTPException(status_code=404, detail="文件未找到")
if not os.path.exists(file_record.file_path):
raise HTTPException(status_code=404, detail="物理文件已丢失")
return FileResponse(path=file_record.file_path, filename=file_record.original_filename)
```
4. 文件删除接口
删除操作需要同时清理磁盘上的物理文件和数据库中的记录。添加以下代码完成后端逻辑:
```python
@app.delete("/files/{file_id}")
async def delete_file(file_id: str, db: Session = Depends(get_db)):
file_record = db.query(FileRecord).filter(FileRecord.id == file_id).first()
if not file_record:
raise HTTPException(status_code=404, detail="文件未找到")
删除物理文件
if os.path.exists(file_record.file_path):
os.remove(file_record.file_path)
删除数据库记录
db.delete(file_record)
db.commit()
return {"message": "文件删除成功"}
```
三、前端页面开发

为了方便操作,我们将构建一个简单的HTML前端页面。该页面使用Vue 3(通过CDN引入)来处理交互逻辑,Axios来发送HTTP请求。请在项目根目录下创建一个名为index.html的文件,并填入以下完整代码:
```html
文件管理系统
文件管理系统
加载中...
| 文件名 |
大小 (字节) |
上传时间 |
操作 |
| {{ file.original_filename }} |
{{ file.file_size }} |
{{ file.upload_time }} |
|
```
四、启动与验证
至此,所有代码已经编写完毕。现在我们将启动后端服务,并使用浏览器访问前端页面进行功能验证。
步骤 1:启动后端服务
在终端中进入项目目录,执行以下命令启动FastAPI服务器:
```bash
uvicorn main:app --reload
```
看到终端显示Uvicorn running on http://127.0.0.1:8000即表示后端启动成功。
步骤 2:打开前端页面
直接在浏览器中双击打开之前创建的index.html文件。你将看到一个简洁的文件管理界面。
步骤 3:功能测试
- 上传测试:点击“选择文件上传”按钮,从本地选择任意文件(如图片或文档)。系统会自动上传并在列表中刷新显示。
- 列表展示:观察表格中是否正确显示了文件名、大小和上传时间。
- 下载测试:点击列表右侧的“下载”按钮,浏览器应开始下载该文件,并保存为原始文件名。
- 删除测试:点击“删除”按钮,确认弹窗后,文件应从列表中消失。此时再次尝试下载该文件ID将提示“文件未找到”。
通过以上步骤,你已经成功从零开始搭建了一个具备完整增删改查(CRUD)功能的文件管理系统。后端使用了高性能的异步框架,前端实现了无刷新交互,且所有数据均持久化存储在本地数据库中。