本系统旨在将纸质基建档案(如项目批复、设计图纸、施工记录、验收文件)转化为结构化、可检索的电子数据。核心架构分为三层:数据存储层、业务逻辑层和用户访问层。数据存储层使用关系型数据库管理元数据和索引,文件本身以二进制形式存储在服务器目录或对象存储中。业务逻辑层负责文件上传、元数据提取、检索和权限控制。用户访问层为Web界面,供用户进行操作。
你需要准备以下软件环境,所有工具均为开源免费。
在Ubuntu服务器上执行以下命令:
``` sudo apt update sudo apt install -y python3-pip python3-venv nginx postgresql postgresql-contrib libpq-dev sudo -u postgres psql -c "CREATE DATABASE infrastructure_archive;" sudo -u postgres psql -c "CREATE USER archive_user WITH PASSWORD 'YourSecurePassword123!';" sudo -u postgres psql -c "GRANT ALL PRIVILEGES ON DATABASE infrastructure_archive TO archive_user;" ```创建项目目录并进入:
``` mkdir -p /opt/archive_system cd /opt/archive_system ```创建Python虚拟环境并激活:
``` python3 -m venv venv source venv/bin/activate ```安装Django及相关依赖:
``` pip install django==4.2 psycopg2-binary django-filter django-crispy-forms crispy-bootstrap5 ```创建Django项目和应用:
``` django-admin startproject archive_project . python manage.py startapp archive ```编辑/opt/archive_system/archive_project/settings.py文件,找到DATABASES配置部分,修改为:
``` DATABASES = { 'default': { 'ENGINE': 'django.db.backends.postgresql', 'NAME': 'infrastructure_archive', 'USER': 'archive_user', 'PASSWORD': 'YourSecurePassword123!', 'HOST': 'localhost', 'PORT': '5432', } } ```同时在INSTALLED_APPS列表中添加'archive'和'crispy_forms', 'crispy_bootstrap5',并设置CRISPY_TEMPLATE_PACK = 'bootstrap5'。
编辑/opt/archive_system/archive/models.py文件,定义档案模型:
``` from django.db import models from django.contrib.auth.models import User class Project(models.Model): """基建项目""" project_code = models.CharField(max_length=50, unique=True, verbose_name="项目编号") project_name = models.CharField(max_length=200, verbose_name="项目名称") location = models.CharField(max_length=200, verbose_name="建设地点") start_date = models.DateField(null=True, blank=True, verbose_name="开工日期") completion_date = models.DateField(null=True, blank=True, verbose_name="竣工日期") class ArchiveCategory(models.Model): """档案分类(如:前期文件、设计文件、施工文件、竣工文件)""" name = models.CharField(max_length=100, verbose_name="分类名称") code = models.CharField(max_length=20, unique=True, verbose_name="分类代码") class ArchiveDocument(models.Model): """档案文件核心表""" project = models.ForeignKey(Project, on_delete=models.CASCADE, verbose_name="所属项目") category = models.ForeignKey(ArchiveCategory, on_delete=models.PROTECT, verbose_name="档案分类") doc_number = models.CharField(max_length=100, verbose_name="档案编号") title = models.CharField(max_length=500, verbose_name="文件标题") description = models.TextField(blank=True, verbose_name="内容摘要") keywords = models.CharField(max_length=300, blank=True, verbose_name="关键词") original_filename = models.CharField(max_length=255, verbose_name="原始文件名") stored_file = models.FileField(upload_to='archive_docs/%Y/%m/%d/', verbose_name="存储文件") upload_date = models.DateTimeField(auto_now_add=True, verbose_name="上传日期") uploader = models.ForeignKey(User, on_delete=models.SET_NULL, null=True, verbose_name="上传人") file_size = models.BigIntegerField(verbose_name="文件大小(字节)") file_type = models.CharField(max_length=50, verbose_name="文件类型") ```执行数据库迁移命令:
``` python manage.py makemigrations archive python manage.py migrate ```编辑/opt/archive_system/archive/views.py文件,创建文档上传视图:
``` from django.shortcuts import render, redirect, get_object_or_404 from django.contrib.auth.decorators import login_required from django.core.paginator import Paginator from django.http import JsonResponse from django.db.models import Q import os from .models import Project, ArchiveCategory, ArchiveDocument from .forms import ArchiveDocumentForm @login_required def upload_document(request): if request.method == 'POST': form = ArchiveDocumentForm(request.POST, request.FILES) if form.is_valid(): doc = form.save(commit=False) doc.uploader = request.user doc.original_filename = request.FILES['stored_file'].name doc.file_size = request.FILES['stored_file'].size doc.file_type = os.path.splitext(doc.original_filename)[1].lower() doc.save() return redirect('document_list') else: form = ArchiveDocumentForm() return render(request, 'archive/upload.html', {'form': form}) def document_list(request): query = request.GET.get('q', '') category_id = request.GET.get('category', '') project_id = request.GET.get('project', '') documents = ArchiveDocument.objects.all().select_related('project', 'category') if query: documents = documents.filter( Q(title__icontains=query) | Q(description__icontains=query) | Q(keywords__icontains=query) | Q(doc_number__icontains=query) ) if category_id: documents = documents.filter(category_id=category_id) if project_id: documents = documents.filter(project_id=project_id) paginator = Paginator(documents.order_by('-upload_date'), 20) page_number = request.GET.get('page') page_obj = paginator.get_page(page_number) return render(request, 'archive/list.html', { 'page_obj': page_obj, 'categories': ArchiveCategory.objects.all(), 'projects': Project.objects.all() }) ```创建/opt/archive_system/archive/forms.py文件:
``` from django import forms from .models import ArchiveDocument class ArchiveDocumentForm(forms.ModelForm): class Meta: model = ArchiveDocument fields = ['project', 'category', 'doc_number', 'title', 'description', 'keywords', 'stored_file'] widgets = { 'description': forms.Textarea(attrs={'rows': 4}), } ```
创建模板目录和文件。首先创建/opt/archive_system/archive/templates/archive/upload.html:
``` {% extends 'base.html' %} {% load crispy_forms_tags %} {% block content %}创建/opt/archive_system/archive/templates/archive/list.html用于展示和搜索档案列表。
在settings.py末尾添加:
``` import os STATIC_URL = '/static/' STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles') MEDIA_URL = '/media/' MEDIA_ROOT = os.path.join(BASE_DIR, 'media') ```然后运行python manage.py collectstatic收集静态文件。
创建Nginx配置文件/etc/nginx/sites-available/archive:
``` server { listen 80; server_name your_domain_or_ip; location /static/ { alias /opt/archive_system/staticfiles/; } location /media/ { alias /opt/archive_system/media/; 限制可访问的文件类型,增强安全 location ~ \.(pdf|docx?|xlsx?|pptx?|dwg|jpg|jpeg|png|tiff)$ { 允许内网访问,根据实际情况调整 allow 192.168.0.0/16; allow 10.0.0.0/8; deny all; } } location / { proxy_pass http://127.0.0.1:8000; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; } } ```启用站点并重启Nginx:
``` sudo ln -s /etc/nginx/sites-available/archive /etc/nginx/sites-enabled/ sudo nginx -t sudo systemctl restart nginx ```安装Gunicorn:pip install gunicorn
创建系统服务文件/etc/systemd/system/archive.service:
``` [Unit] Description=Gunicorn instance for Archive System After=network.target [Service] User=www-data Group=www-data WorkingDirectory=/opt/archive_system Environment="PATH=/opt/archive_system/venv/bin" ExecStart=/opt/archive_system/venv/bin/gunicorn --workers 3 --bind 127.0.0.1:8000 archive_project.wsgi:application [Install] WantedBy=multi-user.target ```启动服务:
``` sudo systemctl start archive sudo systemctl enable archive ```在settings.py中设置:
``` 生产环境务必设置 DEBUG = False ALLOWED_HOSTS = ['your_domain_or_ip', 'localhost'] SECRET_KEY = '你的强随机密钥,不要使用默认值' 强制HTTPS(如果配置了SSL) SECURE_SSL_REDIRECT = True SESSION_COOKIE_SECURE = True CSRF_COOKIE_SECURE = True 文件上传限制 DATA_UPLOAD_MAX_MEMORY_SIZE = 52428800 50MB FILE_UPLOAD_MAX_MEMORY_SIZE = 52428800 50MB ```通过Django管理后台或自定义脚本初始化基础数据:
按照提示输入用户名、邮箱和密码。
登录管理后台(http://your_domain_or_ip/admin),在ArchiveCategory模型中添加:
在Project模型中录入现有的基建项目信息,确保项目编号唯一。