电力行业办公减负利器:电力档案管理系统实测避坑指南
各位电力圈管档案的兄弟姐妹们,我今天真的是掏心窝子给你们唠点干货,没有啥虚头巴脑的广告词,全是我自己在市供电公司综合部摸爬滚打8年踩坑踩出来的经验,信我你就往下看,不信你就当看个乐呵,反正吃亏的也不是...
2026年06月26日 02:25:26
选择开源解决方案是控制成本的核心。我们推荐使用Django作为后端框架,它内置了强大的管理后台和权限系统,能大幅减少开发时间。
安装Python 3.8+和必要依赖:
```bash Ubuntu/Debian系统 sudo apt update sudo apt install python3.8 python3-pip postgresql postgresql-contrib 创建虚拟环境 python3 -m venv env source env/bin/activate 安装Django和相关包 pip install django==4.2.6 pip install django-extensions pip install psycopg2-binary pip install django-crispy-forms pip install django-filter ```创建PostgreSQL数据库:
```bash sudo -u postgres psql CREATE DATABASE archive_db; CREATE USER archive_user WITH PASSWORD 'YourSecurePassword123'; GRANT ALL PRIVILEGES ON DATABASE archive_db TO archive_user; \q ```执行以下命令创建项目:
```bash django-admin startproject archive_system cd archive_system python manage.py startapp archive ```在archive/models.py中定义模型:
```python from django.db import models from django.contrib.auth.models import User class ArchiveCategory(models.Model): """档案分类""" name = models.CharField(max_length=100, verbose_name="分类名称") code = models.CharField(max_length=20, unique=True, verbose_name="分类代码") parent = models.ForeignKey('self', on_delete=models.CASCADE, null=True, blank=True, verbose_name="父分类") class Meta: verbose_name = "档案分类" verbose_name_plural = verbose_name def __str__(self): return self.name class ArchiveFile(models.Model): """档案文件""" FILE_STATUS = [ ('draft', '草稿'), ('active', '有效'), ('archived', '已归档'), ('destroyed', '已销毁'), ] file_number = models.CharField(max_length=50, unique=True, verbose_name="档案编号") title = models.CharField(max_length=200, verbose_name="档案标题") category = models.ForeignKey(ArchiveCategory, on_delete=models.PROTECT, verbose_name="所属分类") content = models.TextField(verbose_name="档案内容") status = models.CharField(max_length=20, choices=FILE_STATUS, default='draft', verbose_name="状态") create_time = models.DateTimeField(auto_now_add=True, verbose_name="创建时间") update_time = models.DateTimeField(auto_now=True, verbose_name="更新时间") creator = models.ForeignKey(User, on_delete=models.PROTECT, related_name='created_files', verbose_name="创建人") 文件存储字段 original_file = models.FileField(upload_to='archives/original/%Y/%m/', verbose_name="原始文件") thumbnail = models.ImageField(upload_to='archives/thumbnails/%Y/%m/', null=True, blank=True, verbose_name="缩略图") class Meta: verbose_name = "档案文件" verbose_name_plural = verbose_name indexes = [ models.Index(fields=['file_number']), models.Index(fields=['status', 'create_time']), ] def __str__(self): return f"{self.file_number} - {self.title}" class FileAccessLog(models.Model): """档案访问日志""" file = models.ForeignKey(ArchiveFile, on_delete=models.CASCADE, verbose_name="档案文件") user = models.ForeignKey(User, on_delete=models.CASCADE, verbose_name="访问用户") access_time = models.DateTimeField(auto_now_add=True, verbose_name="访问时间") action = models.CharField(max_length=50, verbose_name="操作类型") ip_address = models.GenericIPAddressField(verbose_name="IP地址") class Meta: verbose_name = "访问日志" verbose_name_plural = verbose_name ```修改archive_system/settings.py:
```python DATABASES = { 'default': { 'ENGINE': 'django.db.backends.postgresql', 'NAME': 'archive_db', 'USER': 'archive_user', 'PASSWORD': 'YourSecurePassword123', 'HOST': 'localhost', 'PORT': '5432', } } 文件存储配置 MEDIA_URL = '/media/' MEDIA_ROOT = os.path.join(BASE_DIR, 'media') 静态文件配置 STATIC_URL = 'static/' STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles') 添加应用 INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'archive', 我们的档案应用 'django_extensions', 'crispy_forms', 'crispy_bootstrap5', ] CRISPY_ALLOWED_TEMPLATE_PACKS = "bootstrap5" CRISPY_TEMPLATE_PACK = "bootstrap5" ```在archive/admin.py中注册模型:
```python from django.contrib import admin from .models import ArchiveCategory, ArchiveFile, FileAccessLog @admin.register(ArchiveCategory) class ArchiveCategoryAdmin(admin.ModelAdmin): list_display = ['code', 'name', 'parent'] list_filter = ['parent'] search_fields = ['name', 'code'] ordering = ['code'] @admin.register(ArchiveFile) class ArchiveFileAdmin(admin.ModelAdmin): list_display = ['file_number', 'title', 'category', 'status', 'create_time'] list_filter = ['status', 'category', 'create_time'] search_fields = ['file_number', 'title', 'content'] readonly_fields = ['create_time', 'update_time'] date_hierarchy = 'create_time' fieldsets = ( ('基本信息', { 'fields': ('file_number', 'title', 'category', 'status') }), ('档案内容', { 'fields': ('content', 'original_file', 'thumbnail') }), ('系统信息', { 'fields': ('creator', 'create_time', 'update_time'), 'classes': ('collapse',) }), ) @admin.register(FileAccessLog) class FileAccessLogAdmin(admin.ModelAdmin): list_display = ['file', 'user', 'action', 'access_time', 'ip_address'] list_filter = ['action', 'access_time'] readonly_fields = ['access_time'] ```创建archive/views.py:
```python from django.shortcuts import render from django.db.models import Q from .models import ArchiveFile from django.contrib.auth.decorators import login_required @login_required def search_archive(request): query = request.GET.get('q', '') category = request.GET.get('category', '') status = request.GET.get('status', '') archives = ArchiveFile.objects.all() if query: archives = archives.filter( Q(file_number__icontains=query) | Q(title__icontains=query) | Q(content__icontains=query) ) if category: archives = archives.filter(category_id=category) if status: archives = archives.filter(status=status) 记录搜索日志 if query or category or status: FileAccessLog.objects.create( file=None, user=request.user, action='search', ip_address=get_client_ip(request) ) return render(request, 'archive/search.html', { 'archives': archives, 'query': query }) def get_client_ip(request): x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR') if x_forwarded_for: ip = x_forwarded_for.split(',')[0] else: ip = request.META.get('REMOTE_ADDR') return ip ```在archive/urls.py中配置:
```python from django.urls import path from . import views urlpatterns = [ path('search/', views.search_archive, name='archive_search'), ] ```在项目主urls.py中包含应用路由:
```python from django.contrib import admin from django.urls import path, include from django.conf import settings from django.conf.urls.static import static urlpatterns = [ path('admin/', admin.site.urls), path('archive/', include('archive.urls')), ] if settings.DEBUG: urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT) ```
在templates/base.html中:
```html在templates/archive/search.html中:
```html {% extends 'base.html' %} {% block title %}档案检索 - 综合档案管理系统{% endblock %} {% block content %}编号:{{ archive.file_number }}
{{ archive.content|truncatechars:100 }}
未找到相关档案记录
执行数据库迁移命令:
```bash 生成迁移文件 python manage.py makemigrations archive 应用迁移 python manage.py migrate 创建超级用户 python manage.py createsuperuser 按照提示输入用户名、邮箱和密码 ```创建生产环境配置文件settings_prod.py:
```python from .settings import DEBUG = False ALLOWED_HOSTS = ['your-domain.com', 'www.your-domain.com'] 数据库配置(根据实际情况修改) DATABASES = { 'default': { 'ENGINE': 'django.db.backends.postgresql', 'NAME': 'archive_db_prod', 'USER': 'archive_user_prod', 'PASSWORD': 'StrongProductionPassword456', 'HOST': 'localhost', 'PORT': '5432', } } 安全配置 SECURE_SSL_REDIRECT = True SESSION_COOKIE_SECURE = True CSRF_COOKIE_SECURE = True SECURE_BROWSER_XSS_FILTER = True SECURE_CONTENT_TYPE_NOSNIFF = True 静态文件配置 STATIC_ROOT = '/var/www/archive_system/static' MEDIA_ROOT = '/var/www/archive_system/media' ```安装Gunicorn并创建服务:
```bash pip install gunicorn 创建systemd服务文件 sudo nano /etc/systemd/system/archive_system.service ```在服务文件中添加以下内容:
```ini [Unit] Description=Archive System Gunicorn Service After=network.target [Service] User=www-data Group=www-data WorkingDirectory=/path/to/archive_system Environment="PATH=/path/to/archive_system/env/bin" ExecStart=/path/to/archive_system/env/bin/gunicorn \ --workers 3 \ --bind unix:/path/to/archive_system/archive_system.sock \ archive_system.wsgi:application [Install] WantedBy=multi-user.target ```创建Nginx站点配置:
```nginx server { listen 80; server_name your-domain.com; location = /favicon.ico { access_log off; log_not_found off; } location /static/ { root /var/www/archive_system; } location /media/ { root /var/www/archive_system; } location / { include proxy_params; proxy_pass http://unix:/path/to/archive_system/archive_system.sock; } } ```创建备份脚本backup.sh:
```bash !/bin/bash BACKUP_DIR="/backup/archive_system" DATE=$(date +%Y%m%d_%H%M%S) 备份数据库 pg_dump -U archive_user_prod archive_db_prod > \