Files
mwy/backend/journal/admin.py

192 lines
5.8 KiB
Python
Raw Normal View History

2026-05-11 19:34:35 +08:00
from django.contrib import admin
from django.utils.html import format_html
from django.utils.safestring import mark_safe
from .models import Config, Guestbook, Memory, MemoryPhoto
class JournalStaffAccessMixin:
"""
手账站点多为小项目 is_staff 即可在后台增删改查无需在用户里逐项勾选 journal.* 权限
生产环境若需细分权限可移除此 Mixin 并改回 Django 默认的 has_perm 校验
"""
def has_module_permission(self, request):
u = request.user
return bool(getattr(u, "is_active", False) and getattr(u, "is_staff", False))
def has_view_permission(self, request, obj=None):
u = request.user
return bool(getattr(u, "is_active", False) and getattr(u, "is_staff", False))
def has_change_permission(self, request, obj=None):
u = request.user
return bool(getattr(u, "is_active", False) and getattr(u, "is_staff", False))
def has_add_permission(self, request):
u = request.user
return bool(getattr(u, "is_active", False) and getattr(u, "is_staff", False))
def has_delete_permission(self, request, obj=None):
u = request.user
return bool(getattr(u, "is_active", False) and getattr(u, "is_staff", False))
class MemoryPhotoInline(admin.TabularInline):
model = MemoryPhoto
extra = 1
fields = ("image", "sort_order")
@admin.register(Memory)
class MemoryAdmin(JournalStaffAccessMixin, admin.ModelAdmin):
inlines = (MemoryPhotoInline,)
list_display = (
"event_title",
"story_order",
"date",
"unique_feature_type",
"nepal_art_style",
"is_finale",
"thumb_preview",
)
list_display_links = ("event_title",)
list_filter = ("unique_feature_type", "nepal_art_style", "is_finale", "date")
list_editable = ("story_order",)
search_fields = ("event_title", "main_text")
readonly_fields = ("image_preview",)
ordering = ("story_order", "id")
fieldsets = (
(
"叙事",
{
"fields": (
"story_order",
"date",
"event_title",
"is_finale",
)
},
),
(
"版式",
{
"fields": (
"unique_feature_type",
"nepal_art_style",
"image",
"image_preview",
"main_text",
)
},
),
)
@admin.display(description="缩略图")
def thumb_preview(self, obj: Memory) -> str:
url = None
if obj.image:
url = obj.image.url
else:
first = obj.photos.order_by("sort_order", "id").first()
if first:
url = first.image.url
if not url:
return ""
return format_html(
'<img src="{}" style="max-height:48px;border-radius:4px;" />',
url,
)
@admin.display(description="配图预览")
def image_preview(self, obj: Memory) -> str:
chunks: list[str] = []
if obj.image:
chunks.append(
format_html(
'<div class="mb-2"><span style="font-size:11px;color:#666">主图</span><br>'
'<img src="{}" style="max-width:280px;border-radius:8px;" /></div>',
obj.image.url,
)
)
for p in obj.photos.order_by("sort_order", "id"):
chunks.append(
format_html(
'<img src="{}" style="max-width:200px;border-radius:6px;margin:4px;" />',
p.image.url,
)
)
if not chunks:
return ""
return mark_safe("".join(str(c) for c in chunks))
@admin.register(Guestbook)
class GuestbookAdmin(JournalStaffAccessMixin, admin.ModelAdmin):
list_display = ("nickname", "short_message", "created_at")
search_fields = ("nickname", "message")
readonly_fields = ("created_at",)
@admin.display(description="留言")
def short_message(self, obj: Guestbook) -> str:
return obj.message[:80] + ("" if len(obj.message) > 80 else "")
@admin.register(Config)
class ConfigAdmin(admin.ModelAdmin):
"""
站点配置单独写权限不继承 JournalStaffAccessMixin避免 MRO/多重继承下
has_change_permission 未按预期生效导致 change 页全部为只读且 submit_row 不显示保存
"""
save_on_top = True
list_display = (
"site_title",
"together_since",
"unlock_at",
)
list_display_links = ("site_title",)
fieldsets = (
(
"站点",
{"fields": ("site_title",)},
),
(
2026-05-20 16:31:07 +08:00
"时间",
2026-05-11 19:34:35 +08:00
{
"fields": (
"together_since",
"unlock_at",
),
2026-05-20 16:31:07 +08:00
"description": "「在一起」时间用于首页计数。unlock_at 已不使用,可留空。",
2026-05-11 19:34:35 +08:00
},
),
)
def _staff_ok(self, request) -> bool:
u = request.user
return bool(
getattr(u, "is_active", False)
and getattr(u, "is_authenticated", False)
and (getattr(u, "is_staff", False) or getattr(u, "is_superuser", False))
)
def has_module_permission(self, request):
return self._staff_ok(request)
def has_view_permission(self, request, obj=None):
return self._staff_ok(request)
def has_change_permission(self, request, obj=None):
return self._staff_ok(request)
def has_add_permission(self, request):
if not self._staff_ok(request):
return False
return not Config.objects.exists()
def has_delete_permission(self, request, obj=None):
return False