All checks were successful
Auto-Deploy-prodman / deploy (push) Successful in 6s
135 lines
4.9 KiB
Python
135 lines
4.9 KiB
Python
from django.contrib import admin
|
||
from django.utils.html import format_html
|
||
from polymorphic.admin import (
|
||
PolymorphicChildModelAdmin,
|
||
PolymorphicParentModelAdmin,
|
||
PolymorphicChildModelFilter
|
||
)
|
||
from .models import Gost, MaterialGrade, BaseMaterial, SheetMaterial, ProfileMaterial, StockItem
|
||
|
||
# --- 1. Справочники (ГОСТ и Марки) ---
|
||
|
||
@admin.register(Gost)
|
||
class GostAdmin(admin.ModelAdmin):
|
||
list_display = ('name', 'description', 'get_pdf_link')
|
||
search_fields = ('name',)
|
||
|
||
def get_pdf_link(self, obj):
|
||
if obj.pdf_file:
|
||
return format_html('<a href="{}" target="_blank">📄 PDF</a>', obj.pdf_file.url)
|
||
return "—"
|
||
get_pdf_link.short_description = "Файл"
|
||
|
||
|
||
@admin.register(MaterialGrade)
|
||
class MaterialGradeAdmin(admin.ModelAdmin):
|
||
list_display = ('name', 'gost', 'density')
|
||
search_fields = ('name', 'gost__name')
|
||
|
||
|
||
# --- 2. Дочерние админки для заготовок ---
|
||
|
||
class BaseChildAdmin(PolymorphicChildModelAdmin):
|
||
base_model = BaseMaterial
|
||
# Делаем название кликабельным и в дочерних списках
|
||
list_display_links = ('title',)
|
||
|
||
|
||
@admin.register(SheetMaterial)
|
||
class SheetMaterialAdmin(BaseChildAdmin):
|
||
list_display = ('title', 'thickness', 'grade', 'gost')
|
||
|
||
|
||
@admin.register(ProfileMaterial)
|
||
class ProfileMaterialAdmin(BaseChildAdmin):
|
||
list_display = ('title', 'profile_type', 'weight_per_meter', 'grade', 'gost')
|
||
|
||
|
||
# --- 3. Главная (родительская) админка заготовок ---
|
||
|
||
@admin.register(BaseMaterial)
|
||
class BaseMaterialParentAdmin(PolymorphicParentModelAdmin):
|
||
base_model = BaseMaterial
|
||
child_models = (SheetMaterial, ProfileMaterial)
|
||
|
||
# Заменяем обычный title на наш кликабельный метод
|
||
list_display = ('clickable_title', 'grade', 'gost', 'get_specs')
|
||
list_display_links = ('clickable_title',)
|
||
list_filter = (PolymorphicChildModelFilter, 'grade', 'gost')
|
||
search_fields = ('title',)
|
||
|
||
def clickable_title(self, obj):
|
||
"""Объединяет иконку и название в одну ссылку"""
|
||
# Безопасно получаем реальный тип (Лист или Профиль)
|
||
real_obj = obj.get_real_instance()
|
||
|
||
icon = "❓"
|
||
if isinstance(real_obj, SheetMaterial):
|
||
icon = "📄"
|
||
elif isinstance(real_obj, ProfileMaterial):
|
||
icon = "🏗️"
|
||
|
||
return format_html(
|
||
'<span style="margin-right: 8px; font-size: 1.1rem;">{}</span> <b>{}</b>',
|
||
icon,
|
||
obj.title
|
||
)
|
||
clickable_title.short_description = "Наименование заготовки"
|
||
clickable_title.admin_order_field = 'title' # Чтобы работала сортировка
|
||
|
||
def get_specs(self, obj):
|
||
"""Вывод ключевых параметров в общий список"""
|
||
real_obj = obj.get_real_instance()
|
||
if isinstance(real_obj, SheetMaterial):
|
||
return f"t = {real_obj.thickness} мм"
|
||
if isinstance(real_obj, ProfileMaterial):
|
||
return f"{real_obj.get_profile_type_display()}: {real_obj.weight_per_meter} кг/м"
|
||
return "-"
|
||
get_specs.short_description = "Характеристики"
|
||
|
||
|
||
# --- 4. Складской учет ---
|
||
|
||
@admin.register(StockItem)
|
||
class StockItemAdmin(admin.ModelAdmin):
|
||
list_display = (
|
||
'get_material_name',
|
||
'display_dimensions',
|
||
'quantity',
|
||
'colored_status',
|
||
'order_reference',
|
||
'location'
|
||
)
|
||
list_display_links = ('get_material_name',)
|
||
list_filter = ('is_scrap', 'material__grade', 'material')
|
||
search_fields = ('order_reference', 'material__title', 'location')
|
||
|
||
def get_material_name(self, obj):
|
||
return obj.material.title
|
||
get_material_name.short_description = "Заготовка"
|
||
|
||
def display_dimensions(self, obj):
|
||
"""Красивое отображение габаритов"""
|
||
if obj.width:
|
||
return format_html(f"<b>{obj.length} × {obj.width}</b>")
|
||
return format_html(f"L = <b>{obj.length}</b>")
|
||
display_dimensions.short_description = "Размеры (мм)"
|
||
|
||
def colored_status(self, obj):
|
||
"""Цветовая маркировка остатков"""
|
||
if obj.is_scrap:
|
||
return format_html('<b style="color: #ca8a04;">ОБРЕЗОК</b>')
|
||
return format_html('<b style="color: #16a34a;">ЦЕЛЫЙ</b>')
|
||
colored_status.short_description = "Статус"
|
||
|
||
fieldsets = (
|
||
(None, {
|
||
'fields': ('material', 'quantity')
|
||
}),
|
||
('Габариты (мм)', {
|
||
'fields': (('length', 'width'),)
|
||
}),
|
||
('Учет и хранение', {
|
||
'fields': ('is_scrap', 'order_reference', 'location')
|
||
}),
|
||
) |