fix_test #4
@ -3,7 +3,8 @@ from django.utils import timezone
|
|||||||
from django.utils.html import format_html
|
from django.utils.html import format_html
|
||||||
from django.urls import path
|
from django.urls import path
|
||||||
from django.shortcuts import render
|
from django.shortcuts import render
|
||||||
from django.contrib import messages
|
from django.db import models
|
||||||
|
from django_ckeditor_5.widgets import CKEditor5Widget
|
||||||
|
|
||||||
from .models import Home, Solution, Competence, Recall, CallbackRequest, PageView
|
from .models import Home, Solution, Competence, Recall, CallbackRequest, PageView
|
||||||
|
|
||||||
@ -11,38 +12,103 @@ from .models import Home, Solution, Competence, Recall, CallbackRequest, PageVie
|
|||||||
# ===== BASE ADMIN CLASSES =====
|
# ===== BASE ADMIN CLASSES =====
|
||||||
|
|
||||||
class BaseContentAdmin(admin.ModelAdmin):
|
class BaseContentAdmin(admin.ModelAdmin):
|
||||||
"""Общий базовый класс для контентных моделей."""
|
"""
|
||||||
|
Базовый класс для контентных моделей.
|
||||||
|
CKEditor, actions публикации, date_hierarchy.
|
||||||
|
"""
|
||||||
list_display_links = ('id', 'title')
|
list_display_links = ('id', 'title')
|
||||||
list_editable = ('is_published',)
|
list_editable = ('is_published',)
|
||||||
list_filter = ('time_create', 'is_published')
|
list_filter = ('time_create', 'is_published')
|
||||||
search_fields = ('title',)
|
search_fields = ('title',)
|
||||||
|
date_hierarchy = 'time_create'
|
||||||
|
actions = ['make_published', 'make_unpublished']
|
||||||
|
|
||||||
|
formfield_overrides = {
|
||||||
|
models.TextField: {'widget': CKEditor5Widget(config_name='default')},
|
||||||
|
}
|
||||||
|
|
||||||
|
def make_published(self, request, queryset):
|
||||||
|
updated = queryset.update(is_published=True)
|
||||||
|
self.message_user(request, f'{updated} объектов опубликовано.')
|
||||||
|
make_published.short_description = 'Опубликовать выбранные'
|
||||||
|
|
||||||
|
def make_unpublished(self, request, queryset):
|
||||||
|
updated = queryset.update(is_published=False)
|
||||||
|
self.message_user(request, f'{updated} объектов снято с публикации.')
|
||||||
|
make_unpublished.short_description = 'Снять с публикации'
|
||||||
|
|
||||||
|
|
||||||
# ===== MODEL ADMINS =====
|
# ===== MODEL ADMINS =====
|
||||||
|
|
||||||
@admin.register(Home)
|
@admin.register(Home)
|
||||||
class HomeAdmin(BaseContentAdmin):
|
class HomeAdmin(BaseContentAdmin):
|
||||||
|
# Поля: title, content, home_image, time_create, time_update, is_published
|
||||||
list_display = ('id', 'title', 'time_create', 'is_published')
|
list_display = ('id', 'title', 'time_create', 'is_published')
|
||||||
search_fields = ('title', 'content')
|
search_fields = ('title', 'content')
|
||||||
|
|
||||||
|
fieldsets = (
|
||||||
|
(None, {
|
||||||
|
'fields': ('title', 'is_published'),
|
||||||
|
}),
|
||||||
|
('Содержание', {
|
||||||
|
'fields': ('content', 'home_image'),
|
||||||
|
'description': 'Основной текст главной страницы.',
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@admin.register(Solution)
|
@admin.register(Solution)
|
||||||
class SolutionAdmin(BaseContentAdmin):
|
class SolutionAdmin(BaseContentAdmin):
|
||||||
|
# Поля: title, description, implementation, closing, time_create, time_update, is_published
|
||||||
list_display = ('id', 'title', 'time_create', 'is_published')
|
list_display = ('id', 'title', 'time_create', 'is_published')
|
||||||
search_fields = ('title', 'description', 'implementation')
|
search_fields = ('title', 'description', 'implementation')
|
||||||
|
|
||||||
|
fieldsets = (
|
||||||
|
(None, {
|
||||||
|
'fields': ('title', 'is_published'),
|
||||||
|
}),
|
||||||
|
('Содержание', {
|
||||||
|
'fields': ('description', 'implementation', 'closing'),
|
||||||
|
'description': 'Описание, реализация и заключение по проекту.',
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@admin.register(Competence)
|
@admin.register(Competence)
|
||||||
class CompetenceAdmin(BaseContentAdmin):
|
class CompetenceAdmin(BaseContentAdmin):
|
||||||
|
# Поля: title, content, photo, time_create, time_update, is_published
|
||||||
list_display = ('id', 'title', 'time_create', 'is_published')
|
list_display = ('id', 'title', 'time_create', 'is_published')
|
||||||
search_fields = ('title', 'content')
|
search_fields = ('title', 'content')
|
||||||
|
|
||||||
|
fieldsets = (
|
||||||
|
(None, {
|
||||||
|
'fields': ('title', 'is_published'),
|
||||||
|
}),
|
||||||
|
('Содержание', {
|
||||||
|
'fields': ('content', 'photo'),
|
||||||
|
'description': 'Описание компетенции и фото.',
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@admin.register(Recall)
|
@admin.register(Recall)
|
||||||
class RecallAdmin(BaseContentAdmin):
|
class RecallAdmin(BaseContentAdmin):
|
||||||
|
# Поля: title, content, scan, time_create, time_update, is_published
|
||||||
list_display = ('id', 'title', 'time_create', 'scan', 'is_published')
|
list_display = ('id', 'title', 'time_create', 'scan', 'is_published')
|
||||||
search_fields = ('title', 'content')
|
search_fields = ('title', 'content')
|
||||||
|
|
||||||
|
fieldsets = (
|
||||||
|
(None, {
|
||||||
|
'fields': ('title', 'is_published'),
|
||||||
|
}),
|
||||||
|
('Содержание', {
|
||||||
|
'fields': ('content', 'scan'),
|
||||||
|
'description': 'Текст отзыва и скан документа.',
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
# ===== CALLBACK =====
|
||||||
|
|
||||||
@admin.register(CallbackRequest)
|
@admin.register(CallbackRequest)
|
||||||
class CallbackAdmin(admin.ModelAdmin):
|
class CallbackAdmin(admin.ModelAdmin):
|
||||||
@ -54,16 +120,12 @@ class CallbackAdmin(admin.ModelAdmin):
|
|||||||
readonly_fields = ('time_create',)
|
readonly_fields = ('time_create',)
|
||||||
actions = ['mark_as_read', 'mark_as_unread', 'mark_as_processed', 'resend_notification']
|
actions = ['mark_as_read', 'mark_as_unread', 'mark_as_processed', 'resend_notification']
|
||||||
|
|
||||||
# ── badge helper ──────────────────────────────────────────────────────────
|
|
||||||
|
|
||||||
def new_badge(self, obj):
|
def new_badge(self, obj):
|
||||||
if not obj.is_read:
|
if not obj.is_read:
|
||||||
return format_html('<span style="color:red;font-weight:bold;">🆕 НОВАЯ</span>')
|
return format_html('<span style="color:red;font-weight:bold;">🆕 НОВАЯ</span>')
|
||||||
return ''
|
return ''
|
||||||
new_badge.short_description = 'Статус'
|
new_badge.short_description = 'Статус'
|
||||||
|
|
||||||
# ── bulk actions ──────────────────────────────────────────────────────────
|
|
||||||
|
|
||||||
def mark_as_read(self, request, queryset):
|
def mark_as_read(self, request, queryset):
|
||||||
updated = queryset.update(is_read=True)
|
updated = queryset.update(is_read=True)
|
||||||
self.message_user(request, f'{updated} заявок отмечены как прочитанные')
|
self.message_user(request, f'{updated} заявок отмечены как прочитанные')
|
||||||
@ -85,8 +147,6 @@ class CallbackAdmin(admin.ModelAdmin):
|
|||||||
self.message_user(request, f'Уведомления отправлены для {count} заявок')
|
self.message_user(request, f'Уведомления отправлены для {count} заявок')
|
||||||
resend_notification.short_description = 'Переотправить email уведомления'
|
resend_notification.short_description = 'Переотправить email уведомления'
|
||||||
|
|
||||||
# ── custom URL + view for stats ───────────────────────────────────────────
|
|
||||||
|
|
||||||
def get_urls(self):
|
def get_urls(self):
|
||||||
urls = super().get_urls()
|
urls = super().get_urls()
|
||||||
custom_urls = [
|
custom_urls = [
|
||||||
@ -117,11 +177,8 @@ class CallbackAdmin(admin.ModelAdmin):
|
|||||||
}
|
}
|
||||||
return render(request, 'admin/callback_stats.html', context)
|
return render(request, 'admin/callback_stats.html', context)
|
||||||
|
|
||||||
# ── FIX: removed get_queryset message_user spam ───────────────────────────
|
|
||||||
# Previously, a warning banner was shown on EVERY request to the changelist,
|
|
||||||
# including background requests. Removed entirely — the new_badge column
|
|
||||||
# and base_site.html header notification already surface unread counts.
|
|
||||||
|
|
||||||
|
# ===== PAGE VIEWS =====
|
||||||
|
|
||||||
@admin.register(PageView)
|
@admin.register(PageView)
|
||||||
class PageViewAdmin(admin.ModelAdmin):
|
class PageViewAdmin(admin.ModelAdmin):
|
||||||
@ -134,7 +191,6 @@ class PageViewAdmin(admin.ModelAdmin):
|
|||||||
def get_queryset(self, request):
|
def get_queryset(self, request):
|
||||||
return super().get_queryset(request).order_by('-timestamp')
|
return super().get_queryset(request).order_by('-timestamp')
|
||||||
|
|
||||||
# PageViews should never be created or edited manually
|
|
||||||
def has_add_permission(self, request):
|
def has_add_permission(self, request):
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user