from django.contrib import admin from .models import ( Service, Project, Client, Order, Review, BlogPost, Category, ServiceRequest, HeroBanner, ContactInfo, Team, Career, ProjectMedia ) from .forms import ProjectForm @admin.register(ContactInfo) class ContactInfoAdmin(admin.ModelAdmin): list_display = ('company_name', 'email', 'phone', 'is_active') list_filter = ('is_active',) search_fields = ('company_name', 'email', 'phone') fields = ('company_name', 'email', 'phone', 'telegram', 'address', 'working_hours', 'description', 'call_to_action', 'subtitle', 'is_active') @admin.register(HeroBanner) class HeroBannerAdmin(admin.ModelAdmin): list_display = ('title', 'is_active', 'order', 'created_at') list_filter = ('is_active', 'created_at') search_fields = ('title', 'subtitle') fields = ('title', 'subtitle', 'description', 'image', 'video', 'video_poster', 'button_text', 'button_link', 'is_active', 'order') list_editable = ('is_active', 'order') @admin.register(Service) class ServiceAdmin(admin.ModelAdmin): list_display = ('name', 'category', 'price', 'has_video') search_fields = ('name', 'category') fields = ('name', 'description', 'price', 'category', 'image', 'video', 'video_poster') def has_video(self, obj): return bool(obj.video) has_video.boolean = True has_video.short_description = 'Есть видео' @admin.register(Client) class ClientAdmin(admin.ModelAdmin): list_display = ('first_name', 'last_name', 'email', 'phone_number') search_fields = ('first_name', 'last_name', 'email') @admin.register(Order) class OrderAdmin(admin.ModelAdmin): list_display = ('id', 'service', 'client', 'client__email', 'client__phone_number', 'status') list_filter = ('status','client', 'order_date') search_fields = ('client__first_name', 'service__name','status','client', 'order_date') @admin.register(Review) class ReviewAdmin(admin.ModelAdmin): list_display = ('client', 'service', 'rating', 'review_date', 'has_video') list_filter = ('rating',) search_fields = ('client__first_name', 'service__name') fields = ('client', 'service', 'project', 'rating', 'comment', 'image', 'video', 'video_poster') def has_video(self, obj): return bool(obj.video) has_video.boolean = True has_video.short_description = 'Есть видео' @admin.register(BlogPost) class BlogPostAdmin(admin.ModelAdmin): list_display = ('title', 'published_date', 'has_video') search_fields = ('title',) fields = ('title', 'content', 'image', 'video', 'video_poster') def has_video(self, obj): return bool(obj.video) has_video.boolean = True has_video.short_description = 'Есть видео' @admin.register(Category) class CategoryAdmin(admin.ModelAdmin): list_display = ('name', 'slug', 'order', 'is_active', 'services_count', 'projects_count') list_filter = ('is_active',) search_fields = ('name', 'description') prepopulated_fields = {'slug': ('name',)} list_editable = ('order', 'is_active') ordering = ('order', 'name') fieldsets = ( ('Основная информация', { 'fields': ('name', 'slug', 'description', 'icon') }), ('Настройки отображения', { 'fields': ('order', 'is_active') }), ) def services_count(self, obj): return obj.services.count() services_count.short_description = 'Услуг' def projects_count(self, obj): return obj.projects.count() projects_count.short_description = 'Проектов' @admin.register(ServiceRequest) class ServiceRequestAdmin(admin.ModelAdmin): list_display = ('service','token', 'client', 'created_at') search_fields = ('service','token', 'client') list_filter = ('service','token','client') @admin.register(Team) class TeamAdmin(admin.ModelAdmin): list_display = ('first_name', 'last_name', 'position', 'department', 'is_active', 'display_order') list_filter = ('department', 'is_active', 'show_on_about') search_fields = ('first_name', 'last_name', 'position', 'skills') list_editable = ('display_order', 'is_active') fieldsets = ( ('Основная информация', { 'fields': ('first_name', 'last_name', 'position', 'department') }), ('Контактные данные', { 'fields': ('email', 'phone', 'photo'), 'classes': ('collapse',) }), ('Профессиональная информация', { 'fields': ('bio', 'skills', 'experience_years') }), ('Социальные сети', { 'fields': ('linkedin', 'github', 'telegram'), 'classes': ('collapse',) }), ('Настройки отображения', { 'fields': ('is_active', 'show_on_about', 'display_order') }), ) def get_queryset(self, request): return super().get_queryset(request).order_by('display_order', 'last_name') @admin.register(Career) class CareerAdmin(admin.ModelAdmin): list_display = ('title', 'department', 'experience_level', 'employment_type', 'status', 'is_featured', 'created_at') list_filter = ('status', 'employment_type', 'experience_level', 'department', 'is_featured') search_fields = ('title', 'department', 'description', 'required_skills') list_editable = ('status', 'is_featured') fieldsets = ( ('Основная информация', { 'fields': ('title', 'department', 'location', 'employment_type', 'experience_level') }), ('Описание вакансии', { 'fields': ('description', 'responsibilities', 'requirements', 'benefits') }), ('Зарплата', { 'fields': ('salary_min', 'salary_max', 'salary_currency'), 'classes': ('collapse',) }), ('Навыки', { 'fields': ('required_skills', 'preferred_skills'), }), ('Контактная информация', { 'fields': ('contact_email', 'contact_person'), 'classes': ('collapse',) }), ('Статус и метаданные', { 'fields': ('status', 'is_featured', 'application_deadline', 'published_at') }), ) readonly_fields = ('created_at', 'updated_at') def get_queryset(self, request): return super().get_queryset(request).order_by('-is_featured', '-created_at') def save_model(self, request, obj, form, change): if obj.status == 'active' and not obj.published_at: from django.utils import timezone obj.published_at = timezone.now() super().save_model(request, obj, form, change) actions = ['mark_as_active', 'mark_as_paused', 'mark_as_closed'] def mark_as_active(self, request, queryset): from django.utils import timezone updated = queryset.update(status='active') queryset.filter(published_at__isnull=True).update(published_at=timezone.now()) self.message_user(request, f'{updated} вакансий отмечены как активные.') mark_as_active.short_description = "Отметить как активные" def mark_as_paused(self, request, queryset): updated = queryset.update(status='paused') self.message_user(request, f'{updated} вакансий приостановлены.') mark_as_paused.short_description = "Приостановить" def mark_as_closed(self, request, queryset): updated = queryset.update(status='closed') self.message_user(request, f'{updated} вакансий закрыты.') mark_as_closed.short_description = "Закрыть" # ============================================ # ПРОЕКТЫ - АДМИНКИ # ============================================ class ProjectMediaInline(admin.TabularInline): """Inline для медиа-файлов проекта""" model = ProjectMedia extra = 1 fields = ('media_type', 'image', 'video', 'video_poster', 'embed_code', 'caption', 'order') ordering = ('order',) @admin.register(Project) class ProjectAdmin(admin.ModelAdmin): """Админка для проектов""" list_display = ('name', 'status', 'is_featured', 'display_order', 'categories_display', 'views_count', 'likes_count', 'media_count', 'completion_date') list_filter = ('status', 'is_featured', 'categories', 'completion_date') search_fields = ('name', 'description', 'client__first_name', 'client__last_name', 'technologies') filter_horizontal = ('categories',) list_editable = ('is_featured', 'display_order', 'status') ordering = ('-is_featured', '-display_order', '-completion_date') date_hierarchy = 'completion_date' inlines = [ProjectMediaInline] fieldsets = ( ('📋 Основная информация', { 'fields': ('name', 'categories', 'status', 'is_featured', 'display_order') }), ('📝 Описание', { 'fields': ('short_description', 'description', 'image') }), ('🏢 Детали проекта', { 'fields': ('client', 'service', 'order', 'category', 'project_url', 'github_url', 'technologies', 'duration', 'team_size', 'completion_date') }), ('🎬 Видео', { 'fields': ('video', 'video_poster'), 'classes': ('collapse',) }), ('🔍 SEO', { 'fields': ('meta_title', 'meta_description', 'meta_keywords'), 'classes': ('collapse',) }), ('📊 Статистика', { 'fields': ('views_count', 'likes_count'), 'classes': ('collapse',) }), ) readonly_fields = ('views_count', 'likes_count') def categories_display(self, obj): return ', '.join([cat.name for cat in obj.categories.all()[:3]]) categories_display.short_description = 'Категории' def media_count(self, obj): return obj.media_files.count() media_count.short_description = 'Медиа' actions = ['mark_as_completed', 'mark_as_featured'] def mark_as_completed(self, request, queryset): updated = queryset.update(status='completed') self.message_user(request, f'{updated} проектов отмечены как завершённые.') mark_as_completed.short_description = "Отметить как завершённые" def mark_as_featured(self, request, queryset): updated = queryset.update(is_featured=True) self.message_user(request, f'{updated} проектов отмечены как избранные.') mark_as_featured.short_description = "Отметить как избранные" @admin.register(ProjectMedia) class ProjectMediaAdmin(admin.ModelAdmin): """Админка для медиа-файлов проектов""" list_display = ('id', 'project', 'media_type', 'caption', 'order', 'uploaded_at') list_filter = ('media_type', 'uploaded_at') search_fields = ('project__name', 'caption', 'alt_text') list_editable = ('order',) ordering = ('project', 'order', '-uploaded_at') fieldsets = ( ('Проект', { 'fields': ('project', 'media_type', 'order') }), ('Изображение', { 'fields': ('image', 'alt_text'), 'classes': ('collapse',) }), ('Видео', { 'fields': ('video', 'video_poster', 'embed_code'), 'classes': ('collapse',) }), ('Описание', { 'fields': ('caption',) }), )