Site/products/admin.py

157 lines
6.8 KiB
Python
Raw Permalink 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.

from django.contrib import admin
from django.utils.html import format_html
from django.shortcuts import render
from django_ckeditor_5.widgets import CKEditor5Widget
from .models import ProductCategory, Configuration, Product, Order
from programmer.utils.email_notifications import send_multiple_order_notifications, send_multiple_order_notifications_async
from django.urls import reverse
from programmer.tasks import send_new_product_notification
from django.contrib import messages
@admin.register(ProductCategory)
class ProductCategoryAdmin(admin.ModelAdmin):
list_display = ('name', 'slug', 'description')
prepopulated_fields = {'slug': ('name',)}
search_fields = ('name',)
@admin.register(Configuration)
class ConfigurationAdmin(admin.ModelAdmin):
list_display = ('name', 'slug', 'description')
prepopulated_fields = {'slug': ('name',)}
search_fields = ('name',)
@admin.register(Product)
class ProductAdmin(admin.ModelAdmin):
def get_form(self, request, obj=None, **kwargs):
form = super().get_form(request, obj, **kwargs)
form.base_fields['content'].widget = CKEditor5Widget(config_name='default')
return form
list_display = ('title', 'category', 'price', 'is_published', 'time_create', 'configurations_list')
list_filter = ('is_published', 'category', 'configurations', 'time_create')
search_fields = ('title', 'short_description', 'content')
prepopulated_fields = {'slug': ('title',)}
filter_horizontal = ('configurations',)
date_hierarchy = 'time_create'
actions = ['make_published', 'make_unpublished', 'send_notification']
fieldsets = (
(None, {
'fields': ('title', 'slug', 'category', 'price', 'is_published')
}),
('Описания', {
'fields': ('short_description', 'content', 'image'),
'description': 'Краткое обычный текст для карточки; полное HTML-редактор для детальной страницы.'
}),
('Совместимость', {
'fields': ('configurations',),
}),
('SEO', {
'fields': ('meta_description',),
'classes': ('collapse',),
}),
)
def configurations_list(self, obj):
return ", ".join(c.name for c in obj.configurations.all())
configurations_list.short_description = "Конфигурации"
def view_on_site(self, obj):
if obj.is_published:
return obj.get_absolute_url()
# Для неопубликованных — ссылка на предпросмотр
return reverse('products:product_draft_preview', args=[obj.slug])
def make_published(self, request, queryset):
queryset.update(is_published=True)
make_published.short_description = "Опубликовать выбранные продукты"
def make_unpublished(self, request, queryset):
queryset.update(is_published=False)
make_unpublished.short_description = "Снять с публикации"
def send_notification(self, request, queryset):
"""Отправить уведомления подписчикам для выбранных продуктов."""
published = queryset.filter(is_published=True)
count = published.count()
if count == 0:
self.message_user(request, "Нет опубликованных продуктов для отправки уведомлений.", level=messages.WARNING)
return
for product in published:
send_new_product_notification.delay(product.id)
self.message_user(request, f"Уведомления отправлены для {count} продуктов.")
send_notification.short_description = "Отправить уведомление подписчикам о новых продуктах"
@admin.register(Order)
class OrderAdmin(admin.ModelAdmin):
list_display = ('id', 'product', 'name', 'phone', 'created_at', 'is_processed', 'notification_sent')
list_filter = ('is_processed', 'product', 'configuration', 'notification_sent')
search_fields = ('name', 'phone', 'email')
list_editable = ('is_processed',)
readonly_fields = ('created_at',)
actions = ['resend_order_notification'] # добавляем действие в выпадающий список
def notification_badge(self, obj):
# Если в модели Order добавите поле notification_sent, можно показывать иконку
# Пока просто заглушка всегда зелёная галочка (уведомление считается отправленным при создании)
return format_html('<span style="color:green;">✓</span>')
notification_badge.short_description = 'Уведомление'
def resend_order_notification(self, request, queryset):
"""
Переотправляет уведомления для выбранных заказов.
"""
# count = send_multiple_order_notifications(queryset)
count = send_multiple_order_notifications_async(queryset)
self.message_user(request, f'Уведомления отправлены для {count} заказов.')
resend_order_notification.short_description = 'Переотправить email уведомления'
# Опционально: добавить кастомную кнопку на страницу списка
def get_urls(self):
from django.urls import path
from django.shortcuts import render
from django.contrib import messages
urls = super().get_urls()
custom_urls = [
path(
'order-stats/',
self.admin_site.admin_view(self.order_stats_view),
name='order_stats',
),
]
return custom_urls + urls
def notification_badge(self, obj):
if obj.notification_sent:
return format_html('<span style="color:green;">✓</span>')
return format_html('<span style="color:red;">✗</span>')
def order_stats_view(self, request):
from .models import Order
from django.utils import timezone
today = timezone.now().date()
week_ago = today - timezone.timedelta(days=7)
stats = {
'total': Order.objects.count(),
'today': Order.objects.filter(created_at__date=today).count(),
'week': Order.objects.filter(created_at__date__gte=week_ago).count(),
'unprocessed': Order.objects.filter(is_processed=False).count(),
}
context = {
**self.admin_site.each_context(request),
'title': 'Статистика заказов',
'stats': stats,
}
return render(request, 'admin/order_stats.html', context)