Corp/backend/documents/models.py
igor_nadein 499fcb1e78 refactor(documents): Consolidate filer-based models as primary
- Replaced models.py with filer version (FilerFileField)
- Replaced admin.py with full filer admin (thumbnails, previews, file info)
- Replaced rules.py with updated django-rules predicates
- Replaced tests.py with comprehensive test suite (298 lines, 16 tests)
- Deleted duplicate V2 files: models_v2.py, admin_v2.py, rules_v2.py, tests_v2.py
- Deleted management/commands/migrate_to_filer.py (no longer needed)
- Created migration 0005_migrate_to_filer.py with data migration:
  * Migrated 23 existing documents from FileField to FilerFileField
  * Dropped DocumentV2 and DocumentAcknowledgementV2 models

Breaking changes: None (V2 models removed, primary models enhanced)
Migration applied: All 23 documents successfully migrated to django-filer
2026-02-28 01:05:20 +03:00

151 lines
5.4 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# documents/models.py
"""
Модели для управления документами с использованием django-filer.
Основные модели:
- Document: Документ с поддержкой filer для профессионального управления файлами
- DocumentAcknowledgement: Запись об ознакомлении сотрудника с документом
"""
from django.db import models
from django.utils.translation import gettext_lazy as _
from django.conf import settings
from django.utils import timezone
from filer.fields.file import FilerFileField
import reversion
User = settings.AUTH_USER_MODEL # 'employees.Employee'
@reversion.register() # Включаем версионирование для документов
class Document(models.Model):
"""
Документ с использованием django-filer для управления файлами.
Преимущества:
- Поддержка папок и вложенной структуры
- Автоматическая генерация thumbnails для изображений и PDF
- Полнотекстовый поиск по содержимому файлов
- Информация о размере, MIME-типе, метаданные
- История версий через django-reversion
"""
title = models.CharField(_('Название'), max_length=255)
# Используем FilerFileField вместо FileField
file = FilerFileField(
verbose_name=_('Файл'),
null=True,
blank=True,
on_delete=models.SET_NULL,
related_name='documents',
help_text=_('Файл, загруженный через django-filer')
)
description = models.TextField(_('Описание'), blank=True)
uploaded_by = models.ForeignKey(
User,
verbose_name=_('Загрузил'),
on_delete=models.SET_NULL,
null=True,
blank=True,
related_name='uploaded_documents'
)
uploaded_at = models.DateTimeField(_('Дата загрузки'), auto_now_add=True)
# Логика распространения документов
sent_to_all = models.BooleanField(
_('Разослать всем'),
default=True,
help_text=_('Если включено — уведомление получат все активные сотрудники')
)
departments = models.ManyToManyField(
'employees.Department',
verbose_name=_('Отделы-получатели'),
blank=True,
help_text=_('Документ будет доступен всем сотрудникам выбранных отделов (включая будущих)'),
related_name='documents'
)
recipients = models.ManyToManyField(
User,
verbose_name=_('Получатели'),
blank=True,
help_text=_('Если `Разослать всем` отключено, документ пойдет только этим'),
related_name='document_recipients'
)
class Meta:
verbose_name = _('Документ')
verbose_name_plural = _('Документы')
ordering = ['-uploaded_at']
def __str__(self):
return self.title
@property
def file_size(self):
"""Размер файла в байтах (берется из filer)"""
if self.file:
return self.file.size
return 0
@property
def file_extension(self):
"""Расширение файла"""
if self.file:
return self.file.extension
return ''
def get_thumbnail(self, size='medium'):
"""
Получить thumbnail для файла (работает для изображений и PDF).
Args:
size: 'small' (200x200), 'medium' (400x400), 'large' (800x800)
Returns:
URL thumbnail или None
"""
if not self.file:
return None
try:
from easy_thumbnails.files import get_thumbnailer
thumbnailer = get_thumbnailer(self.file)
thumbnail = thumbnailer[size]
return thumbnail.url
except Exception:
# Если thumbnail не удалось создать (не изображение), возвращаем иконку по типу
return self.file.url
@reversion.register()
class DocumentAcknowledgement(models.Model):
"""
Фиксация, что сотрудник ознакомился с документом.
"""
document = models.ForeignKey(
Document,
verbose_name=_('Документ'),
on_delete=models.CASCADE,
related_name='acknowledgements'
)
user = models.ForeignKey(
User,
verbose_name=_('Сотрудник'),
on_delete=models.CASCADE,
related_name='document_acknowledgements'
)
acknowledged_at = models.DateTimeField(_('Время ознакомления'), auto_now_add=True)
class Meta:
verbose_name = _('Ознакомление с документом')
verbose_name_plural = _('Ознакомления с документами')
unique_together = ('document', 'user')
ordering = ['-acknowledged_at']
def __str__(self):
return f'{self.user} — {self.document} @ {self.acknowledged_at:%d.%m.%Y %H:%M}'