feat: add project source code

This commit is contained in:
yujj128
2025-10-22 10:31:01 +08:00
commit cdeb8b66ed
13 changed files with 477 additions and 0 deletions

30
.gitignore vendored Normal file
View File

@@ -0,0 +1,30 @@
# Python
__pycache__/
*.py[cod]
*$py.class
*.so
.Python
# Virtual environments
env/
venv/
.venv/
.env
# IDE
.idea/
.vscode/
# Database
*.sqlite3
*.db
# Logs
*.log
logs/
# Uploaded files
files/
# Environment variables
.env

0
fileflow/__init__.py Normal file
View File

16
fileflow/asgi.py Normal file
View File

@@ -0,0 +1,16 @@
"""
ASGI config for fileflow project.
It exposes the ASGI callable as a module-level variable named ``application``.
For more information on this file, see
https://docs.djangoproject.com/en/4.2/howto/deployment/asgi/
"""
import os
from django.core.asgi import get_asgi_application
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "fileflow.settings")
application = get_asgi_application()

View File

@@ -0,0 +1,25 @@
# Generated by Django 4.2.23 on 2025-10-21 08:12
from django.db import migrations, models
class Migration(migrations.Migration):
initial = True
dependencies = []
operations = [
migrations.CreateModel(
name="FilesModel",
fields=[
("id", models.BigAutoField(primary_key=True, serialize=False)),
("create_time", models.DateTimeField(auto_now_add=True)),
("file_path", models.TextField()),
("file_name", models.TextField()),
],
options={
"db_table": "files",
},
),
]

View File

14
fileflow/models.py Normal file
View File

@@ -0,0 +1,14 @@
from django.db import models
class FilesModel(models.Model):
objects = None
id = models.BigAutoField(primary_key=True)
create_time = models.DateTimeField(auto_now_add=True)
file_path = models.TextField(null=False)
file_name = models.TextField(null=False)
class Meta:
db_table = 'files'
def __str__(self):
return self.file_name

View File

@@ -0,0 +1,68 @@
import logging
import os
import time
from decouple import config
from django.forms import model_to_dict
from fileflow.models import FilesModel
logger = logging.getLogger('django')
class FilesService:
'''
处理文件上传下载等业务
'''
@staticmethod
def get_files():
logger.info("Start to get files service")
try:
dir_path = config('FILE_DIR')
files = []
files_objs = FilesModel.objects.all()
for obj in files_objs:
file_info = {"id": obj.id,"file_name":obj.file_name, "file_path": obj.file_path}
if os.path.exists(obj.file_path):
files.append(file_info)
return files
except Exception as e:
logger.error("get vendor files service error={0}".format(e))
raise e
@staticmethod
def upload_files(upload_files):
logger.info("Start to upload files service")
try:
files_list = []
for file in upload_files:
dir_path = config('FILE_DIR')
id = generate_timestamp_id()
dir_path = os.path.join(dir_path,str(id))
os.makedirs(dir_path, exist_ok=True)
file_path = os.path.join(dir_path, file.name)
filemd = FilesModel()
filemd.id = id
filemd.file_name = file.name
filemd.file_path = file_path
logger.info("absolute path is: %s", os.path.abspath(file_path))
logger.info("file path is {0}".format(file_path))
with open(file_path, 'wb+') as destination:
for chunk in file.chunks():
destination.write(chunk)
filemd_dict = model_to_dict(filemd)
logger.info("filemd_dict is {0}".format(filemd_dict))
files_list.append(filemd_dict)
filemd.save()
return files_list
except Exception as e:
logger.error("upload files service error={0}".format(e))
raise e
def generate_timestamp_id():
"""生成基于时间戳的ID"""
return int(time.time() * 1000)

165
fileflow/settings.py Normal file
View File

@@ -0,0 +1,165 @@
"""
Django settings for fileflow project.
Generated by 'django-admin startproject' using Django 4.2.23.
For more information on this file, see
https://docs.djangoproject.com/en/4.2/topics/settings/
For the full list of settings and their values, see
https://docs.djangoproject.com/en/4.2/ref/settings/
"""
import os
from pathlib import Path
from decouple import config
# Build paths inside the project like this: BASE_DIR / 'subdir'.
BASE_DIR = Path(__file__).resolve().parent.parent
# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/4.2/howto/deployment/checklist/
# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = "django-insecure--m1a@uwg(0zyveppn9$#qw7ccg=o%z=-$a_li)dvhq(c1(e3or"
# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True
# ALLOWED_HOSTS = []
ALLOWED_HOSTS = [i for i in config('DJANGO_ALLOWED_HOSTS', cast=str).split(',')]
# Application definition
INSTALLED_APPS = [
"django.contrib.admin",
"django.contrib.auth",
"django.contrib.contenttypes",
"django.contrib.sessions",
"django.contrib.messages",
"django.contrib.staticfiles",
"fileflow",
]
MIDDLEWARE = [
"django.middleware.security.SecurityMiddleware",
"django.contrib.sessions.middleware.SessionMiddleware",
"django.middleware.common.CommonMiddleware",
"django.middleware.csrf.CsrfViewMiddleware",
"django.contrib.auth.middleware.AuthenticationMiddleware",
"django.contrib.messages.middleware.MessageMiddleware",
"django.middleware.clickjacking.XFrameOptionsMiddleware",
]
ROOT_URLCONF = "fileflow.urls"
TEMPLATES = [
{
"BACKEND": "django.template.backends.django.DjangoTemplates",
"DIRS": [],
"APP_DIRS": True,
"OPTIONS": {
"context_processors": [
"django.template.context_processors.debug",
"django.template.context_processors.request",
"django.contrib.auth.context_processors.auth",
"django.contrib.messages.context_processors.messages",
],
},
},
]
WSGI_APPLICATION = "fileflow.wsgi.application"
# Database
# https://docs.djangoproject.com/en/4.2/ref/settings/#databases
DATABASES = {
"default": {
"ENGINE": "django.db.backends.sqlite3",
"NAME": BASE_DIR / "db.sqlite3",
}
}
# Password validation
# https://docs.djangoproject.com/en/4.2/ref/settings/#auth-password-validators
AUTH_PASSWORD_VALIDATORS = [
{
"NAME": "django.contrib.auth.password_validation.UserAttributeSimilarityValidator",
},
{
"NAME": "django.contrib.auth.password_validation.MinimumLengthValidator",
},
{
"NAME": "django.contrib.auth.password_validation.CommonPasswordValidator",
},
{
"NAME": "django.contrib.auth.password_validation.NumericPasswordValidator",
},
]
# Internationalization
# https://docs.djangoproject.com/en/4.2/topics/i18n/
LANGUAGE_CODE = "en-us"
TIME_ZONE = "UTC"
USE_I18N = True
USE_TZ = True
# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/4.2/howto/static-files/
STATIC_URL = "static/"
# Default primary key field type
# https://docs.djangoproject.com/en/4.2/ref/settings/#default-auto-field
DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField"
LOGGING = {
'version': 1, # 配置版本,固定为 1
'disable_existing_loggers': False, # 禁用默认日志器
'formatters': {
'verbose': {
'format':'%(asctime)s [%(threadName)s] [%(module)s:%(lineno)d] [%(module)s:%(funcName)s] [%(levelname)s]- %(message)s'
}
},
'handlers': {
'console': { # 控制台日志处理器
'level': config('DJANGO_LOG_LEVEL',default='INFO',cast=str), # 日志级别设置为 DEBUG
'class': 'logging.StreamHandler', # 使用 StreamHandler 输出到控制台
'formatter': 'verbose'
},
'file': { # 文件日志处理器
'level': config('DJANGO_LOG_LEVEL',default='INFO',cast=str), # 日志级别设置为 DEBUG
'class': 'logging.handlers.RotatingFileHandler', # 使用 FileHandler 输出到文件
'filename': os.path.join(BASE_DIR,"logs/fileflow.log"), # 日志文件名
'maxBytes': 1024 * 1024 * 50,
'backupCount': 5, # 最多保留5个备份文件,
'encoding': 'utf-8',
'formatter': 'verbose'
},
},
'loggers': {
'django': { # 默认的 Django 日志器
'handlers': ["console", "file"], # 输出到控制台
'level': config('DJANGO_LOG_LEVEL',default='INFO',cast=str), # 日志级别设置为 DEBUG
'propagate': True, # 传播日志给父日志记录器
},
'myapp': { # 自定义的应用日志器
"handlers": ['console', 'file'], # 输出到文件
'level': config('DJANGO_LOG_LEVEL',default='INFO',cast=str), # 日志级别设置为 DEBUG
'propagate': True, # 传播日志给父日志记录器
},
},
}

26
fileflow/urls.py Normal file
View File

@@ -0,0 +1,26 @@
"""
URL configuration for fileflow project.
The `urlpatterns` list routes URLs to views. For more information please see:
https://docs.djangoproject.com/en/4.2/topics/http/urls/
Examples:
Function views
1. Add an import: from my_app import views
2. Add a URL to urlpatterns: path('', views.home, name='home')
Class-based views
1. Add an import: from other_app.views import Home
2. Add a URL to urlpatterns: path('', Home.as_view(), name='home')
Including another URLconf
1. Import the include() function: from django.urls import include, path
2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
"""
from django.contrib import admin
from django.urls import path
from fileflow import views
urlpatterns = [
path("admin/", admin.site.urls),
path("fileflow/uploadFiles", views.upload_files),
path("fileflow/getFiles", views.get_files),
path("fileflow/viewFile", views.view_file),
]

95
fileflow/views.py Normal file
View File

@@ -0,0 +1,95 @@
import json
import logging
import os
import traceback, base64
from decouple import config
from django.http import JsonResponse, HttpResponse, FileResponse
from django.views.decorators.http import require_POST
from rest_framework.decorators import api_view
from .service.file_service import FilesService
logger = logging.getLogger('django')
@api_view(['POST'])
def upload_files(request):
logger.info("Start to upload files in views")
if 'files' not in request.FILES:
return JsonResponse(data={'message': '没有文件上传'}, status=400)
upload_files = request.FILES.getlist('files')
try:
files = FilesService.upload_files(upload_files)
return JsonResponse(data={'result': files}, status=200)
except Exception as ex:
logger.error(traceback.format_exc())
return JsonResponse(data={'error': '文件上传失败'}, status=500)
@api_view(['GET'])
def get_files(request):
logger.info("Start to get files in views")
try:
files = FilesService.get_files()
return JsonResponse(data={'result': files}, status=200)
except Exception as ex:
logger.error(traceback.format_exc())
return JsonResponse(data={'error': '获取文件列表失败'}, status=500)
@api_view(['POST'])
def download_file(request):
'''
body:
filename
vendor_id 供应商id,(仅管理员传,下载,普通用户调用该接口不用传,直接取上下文)
return:
'''
logger.info('Start to download file in views')
data = json.loads(request.body)
filename = data.get('filename', None)
if not filename:
return JsonResponse(data={'message': 'filename不能为空'}, status=400)
try:
dir_path = config('FILE_DIR')
file_path = os.path.join(dir_path, filename)
if not os.path.exists(file_path) or not os.path.isfile(file_path):
return JsonResponse(data={'error': '文件不存在'}, status=500)
with open(file_path, 'rb') as f:
response = HttpResponse(f.read(), content_type='application/octet-stream')
# 告诉浏览器:这是要下载的文件
response['Content-Disposition'] = f'attachment; filename="{filename}"'
# 可选:添加文件大小
response['Content-Length'] = os.path.getsize(file_path)
return response
except Exception as ex:
logger.error(traceback.format_exc())
return JsonResponse(data={'error': '下载文件失败'}, status=500)
@api_view(['GET'])
def view_file(request):
logger.info('Start to view file in views')
filename = request.GET.get('filename', None)
file_path = request.GET.get('file_path', None)
if not file_path:
return JsonResponse(data={'message': 'filepath cannot be empty'}, status=400)
try:
# 安全检查
if not os.path.exists(file_path) or not os.path.isfile(file_path):
return JsonResponse(data={'message': 'file is not exist'}, status=400)
response = FileResponse(open(file_path, 'rb'))
response['Content-Disposition'] = f'inline; filename="{filename}"'
return response
except Exception as ex:
logger.error(traceback.format_exc())
return JsonResponse(data={'error': '文件展示失败'}, status=500)

16
fileflow/wsgi.py Normal file
View File

@@ -0,0 +1,16 @@
"""
WSGI config for fileflow project.
It exposes the WSGI callable as a module-level variable named ``application``.
For more information on this file, see
https://docs.djangoproject.com/en/4.2/howto/deployment/wsgi/
"""
import os
from django.core.wsgi import get_wsgi_application
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "fileflow.settings")
application = get_wsgi_application()

22
manage.py Normal file
View File

@@ -0,0 +1,22 @@
#!/usr/bin/env python
"""Django's command-line utility for administrative tasks."""
import os
import sys
def main():
"""Run administrative tasks."""
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "fileflow.settings")
try:
from django.core.management import execute_from_command_line
except ImportError as exc:
raise ImportError(
"Couldn't import Django. Are you sure it's installed and "
"available on your PYTHONPATH environment variable? Did you "
"forget to activate a virtual environment?"
) from exc
execute_from_command_line(sys.argv)
if __name__ == "__main__":
main()

0
migrations/__init__.py Normal file
View File