鞍山本地单位档案管理救星:选对鞍山档案管理系统少走十年弯路
说真的,我前两年在鞍山铁西一家制造业工厂管行政的时候,被档案那点事搞的头都大了三圈,踩过的坑能绕二一九公园三圈,今天掏心窝子给你们唠唠怎么选靠谱的鞍山档案管理系统,纯个人踩坑经验,半毛钱广告费没收,都...
2026年08月28日 13:20:28
本系统采用Django作为后端框架,PostgreSQL作为数据库,前端使用Bootstrap 5。这种组合能快速搭建稳定、可扩展的归档系统。Django自带强大的Admin管理后台和ORM,能极大简化数据模型和权限管理开发。
在Ubuntu 20.04或Windows 10+ WSL2环境下执行以下命令:
安装Python 3.9和必要依赖:
``` sudo apt update sudo apt install python3.9 python3.9-venv python3.9-dev postgresql postgresql-contrib ```创建并激活虚拟环境:
``` python3.9 -m venv ezhou_env source ezhou_env/bin/activate Windows: ezhou_env\Scripts\activate ```安装Django和相关包:
``` pip install django==4.2 psycopg2-binary django-crispy-forms crispy-bootstrap5 ```创建Django项目和应用:
``` django-admin startproject ezhou_archive cd ezhou_archive python manage.py startapp archive ```配置PostgreSQL数据库,首先登录PostgreSQL:
``` sudo -u postgres psql ```在PostgreSQL命令行中执行:
``` CREATE DATABASE ezhou_archive_db; CREATE USER archive_user WITH PASSWORD 'YourSecurePassword123!'; ALTER ROLE archive_user SET client_encoding TO 'utf8'; ALTER ROLE archive_user SET default_transaction_isolation TO 'read committed'; ALTER ROLE archive_user SET timezone TO 'Asia/Shanghai'; GRANT ALL PRIVILEGES ON DATABASE ezhou_archive_db TO archive_user; \q ```修改ezhou_archive/settings.py中的数据库配置:
``` DATABASES = { 'default': { 'ENGINE': 'django.db.backends.postgresql', 'NAME': 'ezhou_archive_db', 'USER': 'archive_user', 'PASSWORD': 'YourSecurePassword123!', 'HOST': 'localhost', 'PORT': '5432', } } ```在INSTALLED_APPS中添加应用:
``` INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'archive', 'crispy_forms', 'crispy_bootstrap5', ] CRISPY_ALLOWED_TEMPLATE_PACKS = "bootstrap5" CRISPY_TEMPLATE_PACK = "bootstrap5" ```编辑archive/models.py,定义档案管理核心模型:
``` 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="分类代码") description = models.TextField(blank=True, verbose_name="分类描述") parent = models.ForeignKey('self', on_delete=models.CASCADE, null=True, blank=True, verbose_name="上级分类") class Meta: verbose_name = "档案分类" verbose_name_plural = "档案分类" def __str__(self): return self.name class ArchiveFile(models.Model): """档案文件""" STATUS_CHOICES = [ ('draft', '草稿'), ('review', '审核中'), ('approved', '已归档'), ('borrowed', '借阅中'), ('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="档案内容") keywords = models.CharField(max_length=200, verbose_name="关键词") secret_level = models.CharField(max_length=20, choices=[ ('public', '公开'), ('internal', '内部'), ('secret', '秘密'), ('confidential', '机密') ], default='internal', verbose_name="密级") create_date = models.DateField(verbose_name="形成日期") archive_date = models.DateField(auto_now_add=True, verbose_name="归档日期") storage_location = models.CharField(max_length=100, verbose_name="存放位置") storage_period = models.IntegerField(verbose_name="保管期限(年)") status = models.CharField(max_length=20, choices=STATUS_CHOICES, default='draft', verbose_name="状态") creator = models.ForeignKey(User, on_delete=models.PROTECT, related_name='created_files', verbose_name="创建人") reviewer = models.ForeignKey(User, on_delete=models.SET_NULL, null=True, blank=True, related_name='reviewed_files', verbose_name="审核人") attachment = models.FileField(upload_to='archive_attachments/%Y/%m/', blank=True, verbose_name="附件") class Meta: verbose_name = "档案文件" verbose_name_plural = "档案文件" indexes = [ models.Index(fields=['file_number']), models.Index(fields=['title']), models.Index(fields=['category']), models.Index(fields=['create_date']), ] def __str__(self): return f"{self.file_number} - {self.title}" class BorrowRecord(models.Model): """借阅记录""" archive_file = models.ForeignKey(ArchiveFile, on_delete=models.CASCADE, verbose_name="档案文件") borrower = models.ForeignKey(User, on_delete=models.PROTECT, verbose_name="借阅人") borrow_date = models.DateTimeField(auto_now_add=True, verbose_name="借阅日期") expected_return = models.DateField(verbose_name="应还日期") actual_return = models.DateField(null=True, blank=True, verbose_name="实际归还日期") purpose = models.TextField(verbose_name="借阅用途") class Meta: verbose_name = "借阅记录" verbose_name_plural = "借阅记录" ```创建数据库迁移文件:
``` python manage.py makemigrations archive python manage.py migrate ```
创建超级用户用于管理后台:
``` python manage.py createsuperuser ```按照提示输入用户名、邮箱和密码。
编辑archive/admin.py,配置管理后台:
``` from django.contrib import admin from .models import ArchiveCategory, ArchiveFile, BorrowRecord @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', 'secret_level', 'status', 'create_date'] list_filter = ['category', 'secret_level', 'status', 'create_date'] search_fields = ['file_number', 'title', 'keywords'] readonly_fields = ['archive_date'] fieldsets = ( ('基本信息', { 'fields': ('file_number', 'title', 'category', 'content') }), ('档案属性', { 'fields': ('keywords', 'secret_level', 'create_date', 'storage_location', 'storage_period') }), ('流程状态', { 'fields': ('status', 'creator', 'reviewer', 'attachment') }), ) def save_model(self, request, obj, form, change): if not change: 新建时自动设置创建人 obj.creator = request.user super().save_model(request, obj, form, change) @admin.register(BorrowRecord) class BorrowRecordAdmin(admin.ModelAdmin): list_display = ['archive_file', 'borrower', 'borrow_date', 'expected_return', 'actual_return'] list_filter = ['borrow_date', 'expected_return'] search_fields = ['archive_file__file_number', 'archive_file__title', 'borrower__username'] ```在archive/templates目录下创建基础模板base.html:
```创建archive/templates/archive/list.html:
``` {% extends 'base.html' %} {% load crispy_forms_tags %} {% block title %}档案查询{% endblock %} {% block content %}| 档案编号 | 标题 | 分类 | 密级 | 形成日期 | 状态 |
|---|---|---|---|---|---|
| {{ file.file_number }} | {{ file.title }} | {{ file.category.name }} | {{ file.get_secret_level_display }} | {{ file.create_date }} | {{ file.get_status_display }} |
| 未找到相关档案 | |||||
编辑archive/views.py:
``` from django.shortcuts import render, get_object_or_404 from django.contrib.auth.decorators import login_required from django.core.paginator import Paginator from .models import ArchiveFile, ArchiveCategory, BorrowRecord from .forms import BorrowForm def archive_list(request): """档案列表""" files = ArchiveFile.objects.filter(status='approved').order_by('-archive_date') 搜索过滤 query = request.GET.get('q', '') if query: files = files.filter(file_number__icontains=query) | files.filter(title__icontains=query) category_id = request.GET.get('category') if category_id: files = files.filter(category_id=category_id) 分页 paginator = Paginator(files, 20) page_number = request.GET.get('page') page_obj = paginator.get_page(page_number) categories = ArchiveCategory.objects.all() return render(request, 'archive/list.html', { 'files': page_obj, 'categories': categories, }) @login_required def archive_detail(request, pk): """档案详情""" file = get_object_or_404(ArchiveFile, pk=pk, status='approved') if request.method == 'POST': form = BorrowForm(request.POST) if form.is_valid(): borrow = form.save(commit=False) borrow.archive_file = file borrow.borrower = request.user borrow.save() 更新档案状态 file.status = 'borrowed' file.save() else: form = BorrowForm() return render(request, 'archive/detail.html', { 'file': file, 'form': form, }) @login_required def my_borrow(request): """我的借阅记录""" borrows = BorrowRecord.objects.filter(borrower=request.user).order_by('-borrow_date') return render(request, 'archive/my_borrow.html', {'borrows': borrows}) ```创建archive/urls.py:
``` from django.urls import path from . import views urlpatterns = [ path('', views.archive_list, name='archive_list'), path('file/修改项目主ezhou_archive/urls.py:
``` from django.contrib import admin from django.urls import path, include from django.contrib.auth import views as auth_views urlpatterns = [ path('admin/', admin.site.urls), path('', include('archive.urls')), path('login/', auth_views.LoginView.as_view(template_name='registration/login.html'), name='login'), path('logout/', auth_views.LogoutView.as_view(next_page='/'), name='logout'), ] ```创建archive/forms.py:
``` from django import forms from django.core.exceptions import ValidationError from datetime import date, timedelta from .models import BorrowRecord class BorrowForm(forms.ModelForm): class Meta: model = BorrowRecord fields = ['expected_return', 'purpose'] widgets = { 'expected_return': forms.DateInput(attrs={'type': 'date'}), 'purpose': forms.Textarea(attrs={'rows': 3}), } def clean_expected_return(self): expected_return = self.cleaned_data['expected_return'] today = date.today() if expected_return <= today: raise ValidationError("应还日期必须晚于今天") if expected_return > today + timedelta(days=30): raise ValidationError("借阅期限不能超过30天") return expected_return ```在settings.py中添加:
``` STATIC_URL = 'static/' STATIC_ROOT = BASE_DIR / 'staticfiles' MEDIA_URL = 'media/' MEDIA_ROOT = BASE_DIR / 'media' ```收集静态文件:
``` python manage.py collectstatic ```安装Gunicorn和Nginx:
``` pip install gunicorn sudo apt install nginx ```创建Gunicorn服务文件/etc/systemd/system/ezhou-archive.service:
``` [Unit] Description=Gunicorn daemon for Ezhou Archive After=network.target [Service] User=www-data Group=www-data WorkingDirectory=/path/to/your/ezhou_archive ExecStart=/path/to/your/ezhou_env/bin/gunicorn --workers 3 --bind unix:/tmp/ezhou_archive.sock ezhou_archive.wsgi:application [Install] WantedBy=multi-user.target ```配置Nginx站点/etc/nginx