Complete Admin-Backend Overhaul - Neue zentrale Admin-Site mit besserer Strukturierung und Übersichtlichkeit

This commit is contained in:
thomas 2025-07-06 09:54:09 +02:00
parent 97afd62c55
commit f89e715c80
5 changed files with 694 additions and 214 deletions

View File

@ -1,90 +1,2 @@
from django.contrib import admin
from .models import (
Product, Cart, CartItem, Order, OrderItem,
Review, UserProfile, FAQ, ContactMessage,
CustomOrder, OrderProgress, GalleryImage
)
from django.utils.safestring import mark_safe
@admin.register(Product)
class ProductAdmin(admin.ModelAdmin):
list_display = ('name', 'price', 'stock', 'fursuit_type', 'style', 'is_featured', 'is_custom_order')
list_filter = ('fursuit_type', 'style', 'is_featured', 'is_custom_order')
search_fields = ('name', 'description')
ordering = ('-created',)
@admin.register(Order)
class OrderAdmin(admin.ModelAdmin):
list_display = ('id', 'full_name', 'total_amount', 'status', 'payment_status', 'created')
list_filter = ('status', 'payment_status', 'payment_method')
search_fields = ('full_name', 'email')
ordering = ('-created',)
@admin.register(OrderItem)
class OrderItemAdmin(admin.ModelAdmin):
list_display = ('order', 'product_name', 'quantity', 'price')
search_fields = ('product_name',)
@admin.register(Review)
class ReviewAdmin(admin.ModelAdmin):
list_display = ('product', 'user', 'rating', 'created')
list_filter = ('rating',)
search_fields = ('comment', 'user__username')
@admin.register(Cart)
class CartAdmin(admin.ModelAdmin):
list_display = ('id', 'user', 'created')
search_fields = ('user__username',)
@admin.register(CartItem)
class CartItemAdmin(admin.ModelAdmin):
list_display = ('cart', 'product', 'quantity')
@admin.register(UserProfile)
class UserProfileAdmin(admin.ModelAdmin):
list_display = ('user', 'phone', 'newsletter')
list_filter = ('newsletter',)
search_fields = ('user__username', 'phone', 'address')
@admin.register(FAQ)
class FAQAdmin(admin.ModelAdmin):
list_display = ('question', 'category', 'order')
list_filter = ('category',)
search_fields = ('question', 'answer')
ordering = ('category', 'order')
@admin.register(ContactMessage)
class ContactMessageAdmin(admin.ModelAdmin):
list_display = ('subject', 'name', 'email', 'category', 'status', 'created')
list_filter = ('category', 'status')
search_fields = ('name', 'email', 'subject', 'message')
ordering = ('-created',)
@admin.register(CustomOrder)
class CustomOrderAdmin(admin.ModelAdmin):
list_display = ('character_name', 'user', 'fursuit_type', 'status', 'created')
list_filter = ('fursuit_type', 'style', 'status')
search_fields = ('character_name', 'user__username', 'character_description')
ordering = ('-created',)
@admin.register(OrderProgress)
class OrderProgressAdmin(admin.ModelAdmin):
list_display = ('custom_order', 'stage', 'completed', 'created')
list_filter = ('stage', 'completed')
search_fields = ('custom_order__character_name', 'description')
ordering = ('custom_order', 'created')
@admin.register(GalleryImage)
class GalleryImageAdmin(admin.ModelAdmin):
list_display = ('title', 'fursuit_type', 'style', 'is_featured', 'order', 'created', 'admin_image')
list_filter = ('fursuit_type', 'style', 'is_featured')
search_fields = ('title', 'description')
ordering = ('order', '-created')
list_editable = ('order', 'is_featured')
readonly_fields = ('admin_image',)
def admin_image(self, obj):
if obj.image:
return mark_safe(f'<img src="{obj.image.url}" style="max-height: 50px;" />')
return "Kein Bild"
admin_image.short_description = 'Vorschau'
# Diese Datei ist jetzt leer, da alle Admin-Konfigurationen in webshop/admin.py zentral verwaltet werden
# Die Admin-Konfigurationen wurden in die neue zentrale Admin-Site verschoben

View File

@ -1,123 +1,2 @@
from django.contrib import admin
from django.utils.translation import gettext_lazy as _
from django.utils.html import format_html
from .models import (
Product, Category, FursuitGallery, GalleryImage,
DesignTemplate, CustomerDesign, Order, OrderProgress,
Cart, CartItem, ShippingAddress, Checkout,
ProductType, ProductImage, ProductVariant, CustomDesign,
PayPalPayment, PaymentError
)
@admin.register(Category)
class CategoryAdmin(admin.ModelAdmin):
list_display = ['name', 'slug', 'parent']
list_filter = ['parent']
search_fields = ['name']
prepopulated_fields = {'slug': ('name',)}
@admin.register(ProductType)
class ProductTypeAdmin(admin.ModelAdmin):
list_display = ['name', 'has_sizes', 'has_colors', 'has_custom_design', 'requires_measurements']
list_filter = ['has_sizes', 'has_colors', 'has_custom_design', 'requires_measurements']
search_fields = ['name']
class ProductImageInline(admin.TabularInline):
model = ProductImage
extra = 1
class ProductVariantInline(admin.TabularInline):
model = ProductVariant
extra = 1
@admin.register(Product)
class ProductAdmin(admin.ModelAdmin):
list_display = ['name', 'category', 'price', 'stock', 'available', 'created']
list_filter = ['available', 'category', 'product_type', 'created']
search_fields = ['name', 'description']
prepopulated_fields = {'slug': ('name',)}
inlines = [ProductImageInline, ProductVariantInline]
date_hierarchy = 'created'
@admin.register(CustomDesign)
class CustomDesignAdmin(admin.ModelAdmin):
list_display = ['product', 'customer', 'status', 'created']
list_filter = ['status', 'created']
search_fields = ['product__name', 'customer__username']
date_hierarchy = 'created'
@admin.register(DesignTemplate)
class DesignTemplateAdmin(admin.ModelAdmin):
list_display = ['name', 'created_at']
search_fields = ['name', 'description']
@admin.register(CustomerDesign)
class CustomerDesignAdmin(admin.ModelAdmin):
list_display = ['user', 'name', 'created_at']
search_fields = ['user__username', 'name']
date_hierarchy = 'created_at'
class OrderProgressInline(admin.TabularInline):
model = OrderProgress
extra = 1
@admin.register(Order)
class OrderAdmin(admin.ModelAdmin):
list_display = ['id', 'user', 'product', 'status', 'payment_method', 'total_price', 'created_at']
list_filter = ['status', 'payment_method', 'created_at']
search_fields = ['user__username', 'product__name']
inlines = [OrderProgressInline]
date_hierarchy = 'created_at'
class CartItemInline(admin.TabularInline):
model = CartItem
extra = 1
@admin.register(Cart)
class CartAdmin(admin.ModelAdmin):
list_display = ['user', 'created_at', 'updated_at']
search_fields = ['user__username']
inlines = [CartItemInline]
date_hierarchy = 'created_at'
@admin.register(ShippingAddress)
class ShippingAddressAdmin(admin.ModelAdmin):
list_display = ['user', 'first_name', 'last_name', 'city', 'country']
list_filter = ['country']
search_fields = ['user__username', 'first_name', 'last_name', 'city']
@admin.register(Checkout)
class CheckoutAdmin(admin.ModelAdmin):
list_display = ['user', 'status', 'payment_method', 'created_at']
list_filter = ['status', 'payment_method']
search_fields = ['user__username']
date_hierarchy = 'created_at'
@admin.register(PayPalPayment)
class PayPalPaymentAdmin(admin.ModelAdmin):
list_display = ['order', 'payment_id', 'status', 'amount', 'currency', 'created_at']
list_filter = ['status', 'currency']
search_fields = ['payment_id', 'order__id']
date_hierarchy = 'created_at'
@admin.register(PaymentError)
class PaymentErrorAdmin(admin.ModelAdmin):
list_display = ['order', 'error_code', 'created_at']
search_fields = ['order__id', 'error_code', 'error_message']
date_hierarchy = 'created_at'
@admin.register(FursuitGallery)
class FursuitGalleryAdmin(admin.ModelAdmin):
list_display = ['name', 'created_at']
search_fields = ['name', 'description']
prepopulated_fields = {'slug': ('name',)}
class GalleryImageInline(admin.TabularInline):
model = GalleryImage
extra = 1
@admin.register(GalleryImage)
class GalleryImageAdmin(admin.ModelAdmin):
list_display = ['gallery', 'title', 'order']
list_filter = ['gallery']
search_fields = ['gallery__name', 'title']
# Diese Datei ist jetzt leer, da alle Admin-Konfigurationen in webshop/admin.py zentral verwaltet werden
# Die Admin-Konfigurationen wurden in die neue zentrale Admin-Site verschoben

View File

@ -0,0 +1,219 @@
{% extends "admin/base_site.html" %}
{% load static %}
{% block title %}Dashboard - Kasico Administration{% endblock %}
{% block extrastyle %}
<style>
.dashboard-stats {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
gap: 1rem;
margin-bottom: 2rem;
}
.stat-card {
background: white;
border-radius: 8px;
padding: 1.5rem;
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
border-left: 4px solid #8B5CF6;
}
.stat-card h3 {
margin: 0 0 0.5rem 0;
color: #374151;
font-size: 0.875rem;
text-transform: uppercase;
letter-spacing: 0.05em;
}
.stat-card .stat-value {
font-size: 2rem;
font-weight: bold;
color: #8B5CF6;
margin: 0;
}
.stat-card .stat-change {
font-size: 0.875rem;
color: #6B7280;
margin-top: 0.5rem;
}
.dashboard-section {
background: white;
border-radius: 8px;
padding: 1.5rem;
margin-bottom: 1.5rem;
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
}
.dashboard-section h2 {
margin: 0 0 1rem 0;
color: #374151;
font-size: 1.25rem;
}
.recent-item {
padding: 0.75rem;
border-bottom: 1px solid #E5E7EB;
display: flex;
justify-content: space-between;
align-items: center;
}
.recent-item:last-child {
border-bottom: none;
}
.status-badge {
padding: 0.25rem 0.5rem;
border-radius: 4px;
font-size: 0.75rem;
font-weight: 500;
}
.status-new { background: #DBEAFE; color: #1E40AF; }
.status-pending { background: #FEF3C7; color: #92400E; }
.status-paid { background: #D1FAE5; color: #065F46; }
.status-shipped { background: #E0E7FF; color: #3730A3; }
.quick-actions {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
gap: 1rem;
margin-top: 1rem;
}
.quick-action {
background: #F3F4F6;
border-radius: 6px;
padding: 1rem;
text-align: center;
text-decoration: none;
color: #374151;
transition: all 0.2s;
}
.quick-action:hover {
background: #E5E7EB;
transform: translateY(-1px);
}
.quick-action-icon {
font-size: 2rem;
margin-bottom: 0.5rem;
}
</style>
{% endblock %}
{% block content %}
<div class="dashboard">
<h1 style="margin-bottom: 2rem; color: #374151;">🐾 Kasico Dashboard</h1>
<!-- Statistiken -->
<div class="dashboard-stats">
<div class="stat-card">
<h3>Gesamtbestellungen</h3>
<div class="stat-value">{{ total_orders }}</div>
<div class="stat-change">+12% diese Woche</div>
</div>
<div class="stat-card">
<h3>Produkte</h3>
<div class="stat-value">{{ total_products }}</div>
<div class="stat-change">{{ low_stock_products.count }} niedriger Lagerbestand</div>
</div>
<div class="stat-card">
<h3>Kunden</h3>
<div class="stat-value">{{ total_users }}</div>
<div class="stat-change">+5% diesen Monat</div>
</div>
<div class="stat-card">
<h3>Offene Anfragen</h3>
<div class="stat-value">{{ pending_contacts.count }}</div>
<div class="stat-change">Neue Nachrichten</div>
</div>
</div>
<div style="display: grid; grid-template-columns: 1fr 1fr; gap: 1.5rem;">
<!-- Letzte Bestellungen -->
<div class="dashboard-section">
<h2>📦 Letzte Bestellungen</h2>
{% for order in recent_orders %}
<div class="recent-item">
<div>
<strong>#{{ order.id }}</strong> - {{ order.full_name }}
<br>
<small>{{ order.created|date:"d.m.Y H:i" }}</small>
</div>
<div>
<span class="status-badge status-{{ order.payment_status }}">
{{ order.get_payment_status_display }}
</span>
<br>
<small>{{ order.total_amount }}€</small>
</div>
</div>
{% empty %}
<p style="color: #6B7280; text-align: center; padding: 2rem;">Keine Bestellungen vorhanden</p>
{% endfor %}
</div>
<!-- Niedriger Lagerbestand -->
<div class="dashboard-section">
<h2>⚠️ Niedriger Lagerbestand</h2>
{% for product in low_stock_products %}
<div class="recent-item">
<div>
<strong>{{ product.name }}</strong>
<br>
<small>{{ product.get_fursuit_type_display }} • {{ product.get_style_display }}</small>
</div>
<div>
<span class="status-badge status-pending">
{{ product.stock }} Stück
</span>
</div>
</div>
{% empty %}
<p style="color: #6B7280; text-align: center; padding: 2rem;">Alle Produkte verfügbar</p>
{% endfor %}
</div>
</div>
<!-- Schnellaktionen -->
<div class="dashboard-section">
<h2>⚡ Schnellaktionen</h2>
<div class="quick-actions">
<a href="{% url 'admin:products_product_add' %}" class="quick-action">
<div class="quick-action-icon"></div>
<div>Neues Produkt</div>
</a>
<a href="{% url 'admin:products_order_changelist' %}" class="quick-action">
<div class="quick-action-icon">📦</div>
<div>Bestellungen</div>
</a>
<a href="{% url 'admin:products_contactmessage_changelist' %}" class="quick-action">
<div class="quick-action-icon">💬</div>
<div>Nachrichten</div>
</a>
<a href="{% url 'admin:products_customorder_changelist' %}" class="quick-action">
<div class="quick-action-icon">🎨</div>
<div>Custom Orders</div>
</a>
<a href="{% url 'admin:chat_chatroom_changelist' %}" class="quick-action">
<div class="quick-action-icon">💬</div>
<div>Chat Support</div>
</a>
<a href="{% url 'admin:recommendations_recommendationmodel_changelist' %}" class="quick-action">
<div class="quick-action-icon">🤖</div>
<div>ML Models</div>
</a>
</div>
</div>
</div>
{% endblock %}

469
webshop/admin.py Normal file
View File

@ -0,0 +1,469 @@
"""
Zentrale Admin-Konfiguration für Kasico Fursuit Shop
"""
from django.contrib import admin
from django.contrib.admin import AdminSite
from django.utils.html import format_html
from django.urls import path
from django.db.models import Count, Sum, Avg
from django.utils import timezone
from datetime import timedelta
# Import aller Modelle
from products.models import (
Product, Order, OrderItem, Review, UserProfile, FAQ,
ContactMessage, CustomOrder, OrderProgress, GalleryImage
)
from shop.models import (
Category, ProductType, ProductImage, ProductVariant,
CustomDesign, PayPalPayment, PaymentError
)
from chat.models import (
ChatRoom, ChatMessage, UserOnlineStatus, QuickResponse, ChatAnalytics
)
from recommendations.models import (
UserBehavior, UserProfile as RecUserProfile, ProductSimilarity,
Recommendation, RecommendationModel, ABTest, RecommendationAnalytics
)
from mobile.models import MobileDevice, MobileSession
from paypal_integration.models import PayPalConfig
# Custom Admin Site
class KasicoAdminSite(AdminSite):
site_header = "🐾 Kasico Fursuit Shop Administration"
site_title = "Kasico Admin"
index_title = "Willkommen in der Kasico Administration"
def get_app_list(self, request):
"""
Gruppiere Apps in logische Kategorien
"""
app_list = super().get_app_list(request)
# Definiere App-Gruppen
app_groups = {
'Shop Management': ['products', 'shop'],
'Customer Service': ['chat'],
'Analytics & ML': ['recommendations'],
'Mobile & API': ['mobile'],
'Payment & Integration': ['paypal_integration'],
}
# Gruppiere Apps
grouped_apps = {}
for app in app_list:
app_name = app['app_label']
for group, apps in app_groups.items():
if app_name in apps:
if group not in grouped_apps:
grouped_apps[group] = []
grouped_apps[group].append(app)
break
else:
# Apps die nicht in Gruppen sind
if 'Other' not in grouped_apps:
grouped_apps['Other'] = []
grouped_apps['Other'].append(app)
# Flatten und sortieren
final_app_list = []
for group in sorted(grouped_apps.keys()):
if group != 'Other':
final_app_list.extend(grouped_apps[group])
if 'Other' in grouped_apps:
final_app_list.extend(grouped_apps['Other'])
return final_app_list
# Erstelle Admin Site Instanz
admin_site = KasicoAdminSite(name='kasico_admin')
# =============================================================================
# SHOP MANAGEMENT - PRODUCTS
# =============================================================================
@admin.register(Product, site=admin_site)
class ProductAdmin(admin.ModelAdmin):
list_display = ('name', 'price', 'stock', 'fursuit_type', 'style', 'is_featured', 'is_custom_order', 'admin_image')
list_filter = ('fursuit_type', 'style', 'is_featured', 'is_custom_order', 'created')
search_fields = ('name', 'description')
ordering = ('-created',)
list_editable = ('is_featured', 'is_custom_order')
readonly_fields = ('admin_image',)
fieldsets = (
('Grundinformationen', {
'fields': ('name', 'description', 'price', 'stock')
}),
('Fursuit-Details', {
'fields': ('fursuit_type', 'style', 'extras_description')
}),
('Status & Features', {
'fields': ('is_featured', 'is_custom_order', 'image')
}),
('Vorschau', {
'fields': ('admin_image',),
'classes': ('collapse',)
}),
)
def admin_image(self, obj):
if obj.image:
return format_html('<img src="{}" style="max-height: 50px;" />', obj.image.url)
return "Kein Bild"
admin_image.short_description = 'Vorschau'
@admin.register(Category, site=admin_site)
class CategoryAdmin(admin.ModelAdmin):
list_display = ('name', 'slug', 'parent', 'product_count')
list_filter = ('parent',)
search_fields = ('name',)
prepopulated_fields = {'slug': ('name',)}
def product_count(self, obj):
return obj.products.count()
product_count.short_description = 'Produkte'
@admin.register(GalleryImage, site=admin_site)
class GalleryImageAdmin(admin.ModelAdmin):
list_display = ('title', 'fursuit_type', 'style', 'is_featured', 'order', 'created', 'admin_image')
list_filter = ('fursuit_type', 'style', 'is_featured')
search_fields = ('title', 'description')
ordering = ('order', '-created')
list_editable = ('order', 'is_featured')
readonly_fields = ('admin_image',)
def admin_image(self, obj):
if obj.image:
return format_html('<img src="{}" style="max-height: 50px;" />', obj.image.url)
return "Kein Bild"
admin_image.short_description = 'Vorschau'
# =============================================================================
# SHOP MANAGEMENT - ORDERS
# =============================================================================
class OrderItemInline(admin.TabularInline):
model = OrderItem
extra = 0
readonly_fields = ('product_name', 'price')
@admin.register(Order, site=admin_site)
class OrderAdmin(admin.ModelAdmin):
list_display = ('id', 'full_name', 'total_amount', 'status', 'payment_status', 'payment_method', 'created')
list_filter = ('status', 'payment_status', 'payment_method', 'created')
search_fields = ('full_name', 'email', 'id')
ordering = ('-created',)
readonly_fields = ('id', 'created', 'total_amount')
inlines = [OrderItemInline]
fieldsets = (
('Bestellinformationen', {
'fields': ('id', 'user', 'full_name', 'email', 'phone', 'address')
}),
('Zahlung & Status', {
'fields': ('status', 'payment_status', 'payment_method', 'total_amount')
}),
('Zeitstempel', {
'fields': ('created',),
'classes': ('collapse',)
}),
)
actions = ['mark_as_paid', 'mark_as_shipped']
def mark_as_paid(self, request, queryset):
updated = queryset.update(payment_status='paid')
self.message_user(request, f'{updated} Bestellungen als bezahlt markiert.')
mark_as_paid.short_description = "Als bezahlt markieren"
def mark_as_shipped(self, request, queryset):
updated = queryset.update(status='shipped')
self.message_user(request, f'{updated} Bestellungen als versendet markiert.')
mark_as_shipped.short_description = "Als versendet markieren"
@admin.register(CustomOrder, site=admin_site)
class CustomOrderAdmin(admin.ModelAdmin):
list_display = ('character_name', 'user', 'fursuit_type', 'style', 'budget_range', 'status', 'created')
list_filter = ('fursuit_type', 'style', 'status', 'budget_range', 'created')
search_fields = ('character_name', 'user__username', 'character_description')
ordering = ('-created',)
readonly_fields = ('created',)
fieldsets = (
('Character & Design', {
'fields': ('character_name', 'character_description', 'fursuit_type', 'style')
}),
('Kunde & Budget', {
'fields': ('user', 'budget_range', 'deadline_request')
}),
('Details & Dateien', {
'fields': ('color_preferences', 'special_requests', 'reference_images')
}),
('Status', {
'fields': ('status', 'created')
}),
)
@admin.register(OrderProgress, site=admin_site)
class OrderProgressAdmin(admin.ModelAdmin):
list_display = ('custom_order', 'stage', 'completed', 'created')
list_filter = ('stage', 'completed', 'created')
search_fields = ('custom_order__character_name', 'description')
ordering = ('custom_order', 'created')
# =============================================================================
# CUSTOMER SERVICE
# =============================================================================
@admin.register(ContactMessage, site=admin_site)
class ContactMessageAdmin(admin.ModelAdmin):
list_display = ('subject', 'name', 'email', 'category', 'status', 'created')
list_filter = ('category', 'status', 'created')
search_fields = ('name', 'email', 'subject', 'message')
ordering = ('-created',)
readonly_fields = ('created',)
fieldsets = (
('Nachricht', {
'fields': ('subject', 'name', 'email', 'category', 'message')
}),
('Status & Notizen', {
'fields': ('status', 'staff_notes')
}),
('Zeitstempel', {
'fields': ('created',),
'classes': ('collapse',)
}),
)
actions = ['mark_as_in_progress', 'mark_as_resolved']
def mark_as_in_progress(self, request, queryset):
updated = queryset.update(status='in_progress')
self.message_user(request, f'{updated} Nachrichten als in Bearbeitung markiert.')
mark_as_in_progress.short_description = "Als in Bearbeitung markieren"
def mark_as_resolved(self, request, queryset):
updated = queryset.update(status='resolved')
self.message_user(request, f'{updated} Nachrichten als erledigt markiert.')
mark_as_resolved.short_description = "Als erledigt markieren"
@admin.register(ChatRoom, site=admin_site)
class ChatRoomAdmin(admin.ModelAdmin):
list_display = ('id', 'customer', 'admin', 'status', 'subject', 'last_message_at', 'message_count')
list_filter = ('status', 'created_at')
search_fields = ('customer__username', 'admin__username', 'subject')
ordering = ('-last_message_at',)
readonly_fields = ('id', 'created_at', 'last_message_at')
def message_count(self, obj):
return obj.messages.count()
message_count.short_description = 'Nachrichten'
@admin.register(ChatMessage, site=admin_site)
class ChatMessageAdmin(admin.ModelAdmin):
list_display = ('chat_room', 'sender', 'message_type', 'content_preview', 'created_at')
list_filter = ('message_type', 'created_at')
search_fields = ('content', 'sender__username')
ordering = ('-created_at',)
readonly_fields = ('created_at',)
@admin.register(QuickResponse, site=admin_site)
class QuickResponseAdmin(admin.ModelAdmin):
list_display = ('title', 'category', 'is_active', 'use_count', 'created_by')
list_filter = ('category', 'is_active', 'created_at')
search_fields = ('title', 'content')
ordering = ('category', 'title')
# =============================================================================
# ANALYTICS & ML
# =============================================================================
@admin.register(UserBehavior, site=admin_site)
class UserBehaviorAdmin(admin.ModelAdmin):
list_display = ('user', 'behavior_type', 'product', 'created_at')
list_filter = ('behavior_type', 'created_at')
search_fields = ('user__username', 'product__name')
ordering = ('-created_at',)
readonly_fields = ('created_at',)
@admin.register(Recommendation, site=admin_site)
class RecommendationAdmin(admin.ModelAdmin):
list_display = ('user', 'product', 'recommendation_type', 'confidence_score', 'is_clicked', 'is_purchased')
list_filter = ('recommendation_type', 'is_clicked', 'is_purchased', 'created_at')
search_fields = ('user__username', 'product__name')
ordering = ('-created_at',)
readonly_fields = ('created_at',)
@admin.register(RecommendationModel, site=admin_site)
class RecommendationModelAdmin(admin.ModelAdmin):
list_display = ('model_name', 'model_type', 'model_version', 'accuracy_score', 'is_active', 'trained_at')
list_filter = ('model_type', 'is_active', 'trained_at')
search_fields = ('model_name',)
readonly_fields = ('created_at', 'trained_at')
fieldsets = (
('Model Info', {
'fields': ('model_type', 'model_name', 'model_version', 'model_file')
}),
('Performance', {
'fields': ('training_data_size', 'accuracy_score', 'precision_score', 'recall_score', 'f1_score')
}),
('Status', {
'fields': ('is_active', 'created_at', 'trained_at')
}),
)
# =============================================================================
# MOBILE & API
# =============================================================================
@admin.register(MobileDevice, site=admin_site)
class MobileDeviceAdmin(admin.ModelAdmin):
list_display = ('user', 'device_type', 'device_name', 'is_active', 'last_seen')
list_filter = ('device_type', 'is_active', 'created_at')
search_fields = ('user__username', 'device_name', 'device_token')
ordering = ('-created_at',)
readonly_fields = ('created_at', 'last_seen')
# =============================================================================
# PAYMENT & INTEGRATION
# =============================================================================
@admin.register(PayPalConfig, site=admin_site)
class PayPalConfigAdmin(admin.ModelAdmin):
list_display = ('get_mode', 'client_id', 'is_sandbox', 'updated_at')
readonly_fields = ('created_at', 'updated_at')
fieldsets = (
('API Konfiguration', {
'fields': ('client_id', 'client_secret', 'is_sandbox')
}),
('Zeitstempel', {
'fields': ('created_at', 'updated_at'),
'classes': ('collapse',)
}),
)
# =============================================================================
# USERS & PROFILES
# =============================================================================
@admin.register(UserProfile, site=admin_site)
class UserProfileAdmin(admin.ModelAdmin):
list_display = ('user', 'phone', 'newsletter', 'created')
list_filter = ('newsletter', 'created')
search_fields = ('user__username', 'phone', 'address')
ordering = ('-created',)
readonly_fields = ('created',)
@admin.register(Review, site=admin_site)
class ReviewAdmin(admin.ModelAdmin):
list_display = ('product', 'user', 'rating', 'created')
list_filter = ('rating', 'created')
search_fields = ('comment', 'user__username', 'product__name')
ordering = ('-created',)
readonly_fields = ('created',)
@admin.register(FAQ, site=admin_site)
class FAQAdmin(admin.ModelAdmin):
list_display = ('question', 'category', 'order')
list_filter = ('category',)
search_fields = ('question', 'answer')
ordering = ('category', 'order')
list_editable = ('order',)
# =============================================================================
# DASHBOARD & STATISTICS
# =============================================================================
class DashboardAdmin(admin.ModelAdmin):
def get_urls(self):
urls = super().get_urls()
custom_urls = [
path('dashboard/', self.admin_site.admin_view(self.dashboard_view), name='dashboard'),
]
return custom_urls + urls
def dashboard_view(self, request):
# Dashboard Statistiken
context = {
'total_orders': Order.objects.count(),
'total_products': Product.objects.count(),
'total_users': UserProfile.objects.count(),
'recent_orders': Order.objects.order_by('-created')[:5],
'low_stock_products': Product.objects.filter(stock__lte=5),
'pending_contacts': ContactMessage.objects.filter(status='new'),
}
return render(request, 'admin/dashboard.html', context)
# Registriere Dashboard
admin_site.register(DashboardAdmin, DashboardAdmin)
# =============================================================================
# ADMIN ACTIONS
# =============================================================================
@admin.action(description="Produkte als hervorgehoben markieren")
def mark_featured(modeladmin, request, queryset):
updated = queryset.update(is_featured=True)
modeladmin.message_user(request, f'{updated} Produkte als hervorgehoben markiert.')
@admin.action(description="Lagerbestand auf 0 setzen")
def set_stock_zero(modeladmin, request, queryset):
updated = queryset.update(stock=0)
modeladmin.message_user(request, f'{updated} Produkte auf Lagerbestand 0 gesetzt.')
# Füge Actions zu Admin-Klassen hinzu
ProductAdmin.actions = [mark_featured, set_stock_zero]
# =============================================================================
# ADMIN SITE REGISTRATION
# =============================================================================
# Registriere alle Modelle bei der neuen Admin Site
admin_site.register(OrderItem)
admin_site.register(Cart)
admin_site.register(CartItem)
admin_site.register(ProductType)
admin_site.register(ProductImage)
admin_site.register(ProductVariant)
admin_site.register(CustomDesign)
admin_site.register(PayPalPayment)
admin_site.register(PaymentError)
admin_site.register(ChatMessage)
admin_site.register(UserOnlineStatus)
admin_site.register(ChatAnalytics)
admin_site.register(RecUserProfile)
admin_site.register(ProductSimilarity)
admin_site.register(ABTest)
admin_site.register(RecommendationAnalytics)
admin_site.register(MobileSession)

View File

@ -22,9 +22,10 @@ from django.contrib.auth import views as auth_views
from shop import views as shop_views
from products.forms import CustomAuthenticationForm
from rest_framework.documentation import include_docs_urls
from .admin import admin_site
urlpatterns = [
path('admin/', admin.site.urls),
path('admin/', admin_site.urls), # Neue Admin-Site
path('', include('shop.urls')),
path('products/', include('products.urls')),
path('paypal/', include('paypal_integration.urls')),