Files
ProdMan/bom_manager/admin.py
2026-02-14 09:32:46 +03:00

119 lines
5.4 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

from django.contrib import admin
from mptt.admin import MPTTModelAdmin, DraggableMPTTAdmin
from .models import Item, BOMNode, EntityType, RoutingStep, WorkCenter
# Register your models here.
# Создаем инлайн для отображения RoutingStep в Item
class RoutingStepInline(admin.TabularInline):
model = RoutingStep
extra = 1
# Поле tech_params в стандартной админке — это просто текстовое поле.
# Позже его можно будет "причесать" с помощью JS, чтобы оно выглядело красиво.
fields = ('order', 'operation_type', 'work_center', 'drawing_file', 'tech_params')
# Создаем инлайн для отображения BOMNode в Item
class BOMNodeInline(admin.TabularInline):
model = BOMNode
# Указываем fk_key т
fk_name = 'parent'
# Указываем поля для отображения в инлайне
fields = ('item', 'quantity')
# Колличество пустых строк в инлайне
extra = 3
# добавим автокомплит для удобства
autocomplete_fields = ['item']
def formfield_for_foreignkey(self, db_field, request, **kwargs):
if db_field.name == "parent":
# Родителями в инлайне могут быть только Сборки/Изделия/Комплексы
kwargs["queryset"] = BOMNode.objects.filter(
item__entity_type__in=[EntityType.UNIT, EntityType.ASSEMBLY, EntityType.COMPLEX]
)
return super().formfield_for_foreignkey(db_field, request, **kwargs)
@admin.register(Item)
class ItemAdmin(admin.ModelAdmin):
list_display = ('get_full_name', 'entity_type', 'drawing')
list_filter = ('entity_type', 'is_assembly')
# Поиск по номеру и названию
search_fields = ['designation', 'title']
@admin.display(description='Наименование')
def get_full_name(self, obj):
return f"{obj.designation or ''} {obj.title}"
inlines = [RoutingStepInline]
# def get_queryset(self, request):
# qs = super().get_queryset(request)
# return qs.filter(entity_type=EntityType.ASSEMBLY)
@admin.register(BOMNode)
class BOMNodeAdmin(DraggableMPTTAdmin):
# Настройки отображения древовидной структуры
mptt_level_indent = 40 # отступ в пикселях
# Поля для отображения в админке
fields = ('parent', 'item', 'quantity')
# Чтобы в списке было видно не только название связи, но и данные из Item
list_display = ('tree_actions', 'indented_title', 'get_designation', 'quantity')
list_display_links = ('indented_title',)
# Отображаем инлайн.
inlines = [BOMNodeInline]
# Метод для отображения децимального номера из связанной модели Item
def get_designation(self, obj):
return obj.item.designation
get_designation.short_description = 'Децимальный номер'
# Оптимизация запросов (чтобы админка не тормозила)
def get_queryset(self, request):
qs = super().get_queryset(request)
return qs.select_related('item', 'parent')
# def formfield_for_foreignkey(self, db_field, request, **kwargs):
# if db_field.name == "parent":
# # Фильтруем: родителями могут быть только узлы,
# # где связанный Item является сборкой или изделием
# kwargs["queryset"] = BOMNode.objects.filter(
# item__entity_type__in=[EntityType.UNIT, EntityType.ASSEMBLY]
# )
# return super().formfield_for_foreignkey(db_field, request, **kwargs)
# переопределим метод get_inlines в BOMNodeAdmin.
# Если узел привязан к «Детали» или «Стандартному изделию», таблица внизу просто не появится.
def get_inlines(self, request, obj=None):
# Если мы создаем новый узел (obj is None), инлайн можно показать
if obj is None:
return []
# Разрешенные типы (те, в которые МОЖНО вкладывать)
allowed_types = [EntityType.UNIT, EntityType.ASSEMBLY, EntityType.COMPLEX]
# Если тип изделия связанного узла в списке разрешенных — показываем инлайн
if obj.item.entity_type in allowed_types:
return [BOMNodeInline]
# Для остальных (детали, стандартные) возвращаем пустой список
return []
@admin.register(RoutingStep)
class RoutingStepAdmin(admin.ModelAdmin):
# Поля для отображения в админке
list_display = ('item', 'operation_type', 'work_center', 'order')
list_filter = ('operation_type', 'work_center')
search_fields = ['item__title']
@admin.register(WorkCenter)
class WorkCenterAdmin(admin.ModelAdmin):
list_display = ('name', 'rate_per_hour')
search_fields = ['name']