from django.contrib import admin from django.utils.html import format_html from .models import ( CustomUser, Category, Article, ArticleImage, ArticleFile, ArticleLink, Project, ProjectStatus, Skill, Comment, ArticleLike, CommentLike, ContactMessage, Experience, Education, SiteSettings ) @admin.register(CustomUser) class CustomUserAdmin(admin.ModelAdmin): list_display = ['username', 'email', 'is_verified', 'is_active', 'date_joined'] list_filter = ['is_verified', 'is_active', 'is_staff', 'date_joined'] search_fields = ['username', 'email'] ordering = ['-date_joined'] readonly_fields = ['date_joined', 'last_login'] @admin.register(Category) class CategoryAdmin(admin.ModelAdmin): list_display = ['name', 'slug', 'icon', 'order', 'articles_count'] list_editable = ['order'] prepopulated_fields = {'slug': ('name',)} search_fields = ['name'] def articles_count(self, obj): return obj.articles_count articles_count.short_description = 'Статей' class ArticleImageInline(admin.TabularInline): model = ArticleImage extra = 1 fields = ['image', 'caption', 'order', 'is_inline'] ordering = ['order'] class ArticleFileInline(admin.TabularInline): model = ArticleFile extra = 1 fields = ['file', 'title', 'description', 'order', 'is_inline'] ordering = ['order'] class ArticleLinkInline(admin.TabularInline): model = ArticleLink extra = 1 fields = ['url', 'title', 'description', 'preview_image', 'order', 'is_inline'] ordering = ['order'] readonly_fields = [] @admin.register(Article) class ArticleAdmin(admin.ModelAdmin): list_display = ['title', 'category', 'is_published', 'comments_enabled', 'is_achievement', 'views', 'date', 'image_preview'] list_filter = ['is_published', 'comments_enabled', 'is_achievement', 'category', 'date'] search_fields = ['title', 'post', 'excerpt'] prepopulated_fields = {'slug': ('title',)} date_hierarchy = 'date' list_editable = ['is_published', 'comments_enabled'] readonly_fields = ['views', 'date', 'updated_at', 'image_preview_large'] inlines = [ArticleImageInline, ArticleFileInline, ArticleLinkInline] fieldsets = ( ('Основное', { 'fields': ('title', 'slug', 'sub_title', 'excerpt', 'post') }), ('Превью (обложка)', { 'fields': ('img', 'show_cover_in_article', 'image_preview_large') }), ('Галерея изображений', { 'fields': ('gallery_display_mode',), 'description': 'Добавьте изображения ниже в инлайн-форме "Изображения статьи"' }), ('Категоризация', { 'fields': ('category', 'author') }), ('Комментарии и медиа', { 'fields': ('comments_enabled', 'exclude_inline_from_blocks'), 'description': 'Управление комментариями и отображением медиа-контента' }), ('Достижение', { 'fields': ('is_achievement', 'achievement_icon', 'achievement_date'), 'classes': ('collapse',) }), ('Публикация', { 'fields': ('is_published', 'views', 'date', 'updated_at') }), ) def image_preview(self, obj): if obj.img: return format_html('', obj.img.url) return '-' image_preview.short_description = 'Превью' def image_preview_large(self, obj): if obj.img: return format_html('', obj.img.url) return 'Нет изображения' image_preview_large.short_description = 'Изображение' @admin.register(ProjectStatus) class ProjectStatusAdmin(admin.ModelAdmin): list_display = ['name', 'slug', 'color', 'is_release', 'order'] list_editable = ['order', 'is_release'] prepopulated_fields = {'slug': ('name',)} search_fields = ['name'] ordering = ['order'] @admin.register(Project) class ProjectAdmin(admin.ModelAdmin): list_display = ['title', 'status', 'card_size', 'languages_short', 'technologies_short', 'show_on_homepage', 'homepage_order', 'order', 'is_visible'] list_filter = ['status', 'card_size', 'is_visible', 'show_on_homepage'] search_fields = ['title', 'description', 'technologies', 'programming_languages'] prepopulated_fields = {'slug': ('title',)} list_editable = ['order', 'is_visible', 'card_size', 'show_on_homepage', 'homepage_order'] fieldsets = ( ('Основное', { 'fields': ('title', 'slug', 'short_description', 'description', 'features') }), ('Визуальное', { 'fields': ('img_main', 'icon', 'card_size') }), ('Техническое', { 'fields': ('programming_languages', 'technologies', 'github_url', 'demo_url'), 'description': 'Языки программирования и технологии указываются через запятую' }), ('Статус и отображение', { 'fields': ('status', 'users_count', 'is_visible', 'order') }), ('Главная страница', { 'fields': ('show_on_homepage', 'homepage_order'), 'description': 'Настройки отображения проекта на главной странице' }), ) def languages_short(self, obj): langs = obj.get_languages_list()[:2] return ', '.join(langs) + ('...' if len(obj.get_languages_list()) > 2 else '') if langs else '-' languages_short.short_description = 'Языки' def technologies_short(self, obj): techs = obj.get_technologies_list()[:3] return ', '.join(techs) + ('...' if len(obj.get_technologies_list()) > 3 else '') technologies_short.short_description = 'Технологии' @admin.register(Skill) class SkillAdmin(admin.ModelAdmin): list_display = ['name', 'category', 'icon', 'order'] list_filter = ['category'] list_editable = ['order'] search_fields = ['name'] ordering = ['category', 'order'] @admin.register(Experience) class ExperienceAdmin(admin.ModelAdmin): list_display = ['title', 'company', 'start_date', 'end_date', 'is_current', 'duration', 'order'] list_filter = ['is_current', 'company'] list_editable = ['order'] search_fields = ['title', 'company', 'description'] ordering = ['order', '-start_date'] @admin.register(Education) class EducationAdmin(admin.ModelAdmin): list_display = ['institution_short_display', 'degree', 'education_type', 'start_year', 'end_year', 'is_current', 'order'] list_filter = ['education_type', 'is_current'] list_editable = ['order'] search_fields = ['institution', 'degree'] ordering = ['order', '-start_year'] def institution_short_display(self, obj): return obj.institution_short or obj.institution[:30] + '...' institution_short_display.short_description = 'Учреждение' @admin.register(Comment) class CommentAdmin(admin.ModelAdmin): list_display = ['user', 'article', 'content_short', 'is_approved', 'created_at'] list_filter = ['is_approved', 'created_at'] search_fields = ['content', 'user__username', 'article__title'] list_editable = ['is_approved'] readonly_fields = ['created_at', 'updated_at'] actions = ['approve_comments', 'reject_comments'] def content_short(self, obj): return obj.content[:50] + '...' if len(obj.content) > 50 else obj.content content_short.short_description = 'Содержание' def approve_comments(self, request, queryset): count = queryset.update(is_approved=True) self.message_user(request, f'Одобрено {count} комментариев') approve_comments.short_description = 'Одобрить выбранные комментарии' def reject_comments(self, request, queryset): count = queryset.update(is_approved=False) self.message_user(request, f'Отклонено {count} комментариев') reject_comments.short_description = 'Отклонить выбранные комментарии' @admin.register(ContactMessage) class ContactMessageAdmin(admin.ModelAdmin): list_display = ['name', 'email', 'subject', 'is_read', 'is_replied', 'created_at'] list_filter = ['is_read', 'is_replied', 'created_at'] search_fields = ['name', 'email', 'subject', 'message'] readonly_fields = ['name', 'email', 'subject', 'message', 'created_at'] list_editable = ['is_read', 'is_replied'] ordering = ['-created_at'] fieldsets = ( ('Сообщение', { 'fields': ('name', 'email', 'subject', 'message', 'created_at') }), ('Статус', { 'fields': ('is_read', 'is_replied', 'admin_notes') }), ) @admin.register(SiteSettings) class SiteSettingsAdmin(admin.ModelAdmin): fieldsets = ( ('Основное', { 'fields': ('site_name', 'site_description') }), ('Владелец', { 'fields': ('owner_name', 'owner_title', 'owner_bio', 'owner_photo') }), ('Контакты', { 'fields': ('owner_email', 'owner_phone', 'owner_city') }), ('Социальные сети', { 'fields': ('telegram_url', 'github_url', 'vk_url', 'linkedin_url') }), ('Файлы', { 'fields': ('resume_file',) }), ('Аналитика', { 'fields': ('yandex_metrika_id', 'google_analytics_id'), 'classes': ('collapse',) }), ) def has_add_permission(self, request): return not SiteSettings.objects.exists() def has_delete_permission(self, request, obj=None): return False admin.site.register(ArticleLike) admin.site.register(CommentLike) admin.site.site_header = 'deev.space — Администрирование' admin.site.site_title = 'deev.space Admin' admin.site.index_title = 'Панель управления'