# documents/admin.py
"""
Django admin для моделей Document и DocumentAcknowledgement.
Основные возможности:
- Использование django-filer для управления файлами
- Поддержка drag & drop загрузки файлов
- Превью thumbnails в списке и форме редактирования
- Полнотекстовый поиск по содержимому файлов
- Версионирование через django-reversion
- Workflow управление через django-fsm
"""
from django.contrib import admin
from django.utils.translation import gettext_lazy as _
from django.utils.html import format_html, mark_safe
from django.urls import reverse
from .models import Document, DocumentAcknowledgement
from django.contrib.auth import get_user_model
User = get_user_model()
class AcknowledgementInline(admin.TabularInline):
"""Inline для отображения ознакомлений с документом."""
model = DocumentAcknowledgement
extra = 0
can_delete = False
verbose_name = _("Ознакомление")
verbose_name_plural = _("Ознакомления")
fields = ("user_link", "acknowledged_at")
readonly_fields = ("user_link", "acknowledged_at")
def user_link(self, obj):
"""Ссылка на профиль сотрудника."""
if not obj.user:
return "—"
url = reverse(
"admin:{}_{}_change".format(
User._meta.app_label, User._meta.model_name
),
args=[obj.user.pk],
)
return format_html(
'{}', url, obj.user.get_full_name() or obj.user
)
user_link.short_description = _("Сотрудник")
@admin.register(Document)
class DocumentAdmin(admin.ModelAdmin):
"""
Admin для Document с поддержкой django-filer и django-fsm.
Возможности:
- Drag & drop загрузка файлов через filer
- Превью thumbnails для изображений и PDF
- Поиск по содержимому файлов
- Версионирование через django-reversion
- Workflow управление через django-fsm
"""
inlines = [AcknowledgementInline]
list_display = (
"title",
"file_thumbnail",
"file_info",
"uploaded_at",
"sent_to_all",
"is_regulation",
"acknowledgement_status",
)
list_filter = ("sent_to_all", "is_regulation", "uploaded_at", "departments")
search_fields = ("title", "description", "file__name", "file__description")
filter_horizontal = ("recipients", "departments")
actions = ["send_document"]
# Для django-reversion
history_latest_first = True
fieldsets = (
(
None,
{
"fields": (
"title",
"file", # FilerFileField с drag & drop
"file_preview", # Превью файла
"description",
"is_regulation",
"sent_to_all",
"departments",
"recipients",
),
},
),
(
_("Meta"),
{
"fields": (
"uploaded_by",
"uploaded_at",
"file_size",
"file_extension",
),
"classes": ("collapse",),
},
),
(
_("Ознакомление"),
{
"fields": ("recipients_summary", "pending_list"),
},
),
)
readonly_fields = (
"uploaded_by",
"uploaded_at",
"file_preview",
"file_size",
"file_extension",
"recipients_summary",
"pending_list",
)
def save_model(self, request, obj, form, change):
"""Автоматически устанавливаем uploaded_by при создании."""
if not obj.pk:
obj.uploaded_by = request.user
super().save_model(request, obj, form, change)
def file_thumbnail(self, obj):
"""Превью файла в списке документов."""
if not obj.file:
return "—"
# Для изображений показываем thumbnail
if obj.file.file_type == "Image":
thumbnail_url = obj.get_thumbnail("small")
if thumbnail_url:
return format_html(
''
''
"",
obj.file.url,
thumbnail_url,
)
# Для других файлов показываем иконку
icon_url = obj.file.icons.get("48", "")
if icon_url:
return format_html(
''
'
'
"",
obj.file.url,
icon_url,
)
return format_html('📎', obj.file.url)
file_thumbnail.short_description = _("Превью")
def file_preview(self, obj):
"""Большое превью файла в форме редактирования."""
if not obj.file:
return "—"
# Для изображений показываем большой thumbnail
if obj.file.file_type == "Image":
thumbnail_url = obj.get_thumbnail("medium")
if thumbnail_url:
return format_html(
'