Исправлена ошибка public admin для мультитенантной архитектуры
Проблема: при входе в localhost/admin/ (public схема) возникала ошибка "relation user_roles_userrole does not exist", так как tenant-only таблицы не существуют в public схеме. Решение: - Создан TenantAdminOnlyMixin для скрытия tenant-only моделей от public admin - Применён миксин ко всем ModelAdmin классам в tenant-only приложениях: user_roles, customers, orders, inventory, products - Добавлена проверка _is_public_schema() в RoleBasedPermissionBackend для предотвращения запросов к tenant-only таблицам в public схеме Теперь: - localhost/admin/ показывает только public модели (Client, Domain, User) - shop.localhost/admin/ показывает все модели магазина 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,3 +1,8 @@
|
||||
"""
|
||||
Админка для приложения products.
|
||||
Все модели tenant-only, поэтому используют TenantAdminOnlyMixin
|
||||
для скрытия от public admin (localhost/admin/).
|
||||
"""
|
||||
from django.contrib import admin
|
||||
from django.utils.html import format_html
|
||||
from django.utils import timezone
|
||||
@@ -14,6 +19,7 @@ from .admin_displays import (
|
||||
format_photo_inline_quality,
|
||||
format_photo_preview_with_quality,
|
||||
)
|
||||
from tenants.admin_mixins import TenantAdminOnlyMixin
|
||||
|
||||
|
||||
class DeletedFilter(admin.SimpleListFilter):
|
||||
@@ -292,7 +298,7 @@ def disable_delete_selected(admin_class):
|
||||
|
||||
|
||||
@admin.register(ProductVariantGroup)
|
||||
class ProductVariantGroupAdmin(admin.ModelAdmin):
|
||||
class ProductVariantGroupAdmin(TenantAdminOnlyMixin, admin.ModelAdmin):
|
||||
list_display = ['name', 'get_products_count', 'created_at']
|
||||
search_fields = ['name', 'description']
|
||||
list_filter = ['created_at']
|
||||
@@ -303,7 +309,7 @@ class ProductVariantGroupAdmin(admin.ModelAdmin):
|
||||
get_products_count.short_description = 'Товаров'
|
||||
|
||||
|
||||
class ProductCategoryAdmin(admin.ModelAdmin):
|
||||
class ProductCategoryAdmin(TenantAdminOnlyMixin, admin.ModelAdmin):
|
||||
list_display = ('photo_with_quality', 'name', 'sku', 'slug', 'parent', 'is_active', 'get_deleted_status')
|
||||
list_filter = (DeletedFilter, 'is_active', QualityLevelFilter, 'parent')
|
||||
prepopulated_fields = {'slug': ('name',)}
|
||||
@@ -376,14 +382,14 @@ class ProductCategoryAdmin(admin.ModelAdmin):
|
||||
photo_preview_large.short_description = "Превью основного фото"
|
||||
|
||||
|
||||
class ProductTagAdmin(admin.ModelAdmin):
|
||||
class ProductTagAdmin(TenantAdminOnlyMixin, admin.ModelAdmin):
|
||||
list_display = ('name', 'slug', 'is_active')
|
||||
list_filter = ('is_active',)
|
||||
prepopulated_fields = {'slug': ('name',)}
|
||||
search_fields = ('name',)
|
||||
|
||||
|
||||
class ProductAdmin(admin.ModelAdmin):
|
||||
class ProductAdmin(TenantAdminOnlyMixin, admin.ModelAdmin):
|
||||
list_display = ('photo_with_quality', 'name', 'sku', 'get_categories_display', 'cost_price', 'price', 'sale_price', 'get_variant_groups_display', 'get_status_display')
|
||||
list_filter = (DeletedFilter, QualityLevelFilter, 'categories', 'tags', 'variant_groups')
|
||||
search_fields = ('name', 'sku', 'description', 'search_keywords')
|
||||
@@ -576,7 +582,7 @@ class ProductAdmin(admin.ModelAdmin):
|
||||
photo_preview_large.short_description = "Превью основного фото"
|
||||
|
||||
|
||||
class ProductKitAdmin(admin.ModelAdmin):
|
||||
class ProductKitAdmin(TenantAdminOnlyMixin, admin.ModelAdmin):
|
||||
list_display = ('photo_with_quality', 'name', 'slug', 'get_categories_display', 'get_price_display', 'is_temporary', 'get_order_link', 'get_status_display')
|
||||
list_filter = (DeletedFilter, 'is_temporary', QualityLevelFilter, 'categories', 'tags')
|
||||
prepopulated_fields = {'slug': ('name',)}
|
||||
@@ -836,7 +842,7 @@ class ProductCategoryAdminWithPhotos(ProductCategoryAdmin):
|
||||
|
||||
|
||||
@admin.register(KitItem)
|
||||
class KitItemAdmin(admin.ModelAdmin):
|
||||
class KitItemAdmin(TenantAdminOnlyMixin, admin.ModelAdmin):
|
||||
list_display = ['__str__', 'kit', 'get_type', 'quantity', 'has_priorities']
|
||||
list_filter = ['kit']
|
||||
list_select_related = ['kit', 'product', 'variant_group']
|
||||
@@ -856,7 +862,7 @@ class KitItemAdmin(admin.ModelAdmin):
|
||||
|
||||
|
||||
@admin.register(SKUCounter)
|
||||
class SKUCounterAdmin(admin.ModelAdmin):
|
||||
class SKUCounterAdmin(TenantAdminOnlyMixin, admin.ModelAdmin):
|
||||
list_display = ['counter_type', 'current_value', 'get_next_preview']
|
||||
list_filter = ['counter_type']
|
||||
readonly_fields = ['get_next_preview']
|
||||
@@ -879,7 +885,7 @@ class SKUCounterAdmin(admin.ModelAdmin):
|
||||
|
||||
|
||||
@admin.register(CostPriceHistory)
|
||||
class CostPriceHistoryAdmin(admin.ModelAdmin):
|
||||
class CostPriceHistoryAdmin(TenantAdminOnlyMixin, admin.ModelAdmin):
|
||||
list_display = ['product', 'get_price_change', 'reason', 'created_at']
|
||||
list_filter = ['reason', 'created_at', 'product']
|
||||
search_fields = ['product__name', 'product__sku', 'notes']
|
||||
@@ -965,7 +971,7 @@ class ConfigurableProductAttributeInline(admin.TabularInline):
|
||||
|
||||
|
||||
@admin.register(ConfigurableProduct)
|
||||
class ConfigurableProductAdmin(admin.ModelAdmin):
|
||||
class ConfigurableProductAdmin(TenantAdminOnlyMixin, admin.ModelAdmin):
|
||||
"""Админка для вариативных товаров"""
|
||||
list_display = ('name', 'sku', 'status', 'get_options_count', 'created_at')
|
||||
list_filter = ('status', 'created_at')
|
||||
|
||||
Reference in New Issue
Block a user