mod: рефакторинг "каталог типовых проёмов"

This commit is contained in:
2026-04-24 17:31:56 +03:00
parent c184d65c66
commit 4bb77a9892
3 changed files with 94 additions and 87 deletions

View File

@@ -1,82 +1,99 @@
# -*- coding: utf-8 -*-
from django.db.models import F
from django.shortcuts import render
from django.http import HttpRequest, HttpResponse
from oknardia.models import (
Seria_Info,
Win_MountDim,
)
from oknardia.models import MountDim2Apartment
from web.report1 import get_last_all_user_visit_list, get_last_user_visit_cookies, get_last_user_visit_list
from web.add_func import get_flaps_for_mini_pictures
import time
import pytils
from typing import Any
from itertools import groupby
from operator import itemgetter
def standard_opening(request: HttpRequest) -> HttpResponse:
time_start = time.perf_counter()
to_template: dict[str, object] = {} # словарь, для передачи шаблону
q_seria = Seria_Info.objects.raw('SELECT oknardia_seria_info.id, oknardia_seria_info.sName '
'FROM oknardia_seria_info '
'WHERE oknardia_seria_info.id = oknardia_seria_info.kRoot_id '
'ORDER BY oknardia_seria_info.sName;')
to_template.update({'SERIAS': list(q_seria)})
q_win_opening = Win_MountDim.objects.raw(
'SELECT oknardia_win_mountdim.*,'
' oknardia_seria_info.sName,'
' oknardia_seria_info.id AS ID_Seria '
'FROM oknardia_win_mountdim'
' INNER JOIN oknardia_mountdim2apartment'
' ON oknardia_win_mountdim.id = oknardia_mountdim2apartment.kMountDim_id'
' RIGHT OUTER JOIN oknardia_apartment_type'
' ON oknardia_apartment_type.id = oknardia_mountdim2apartment.kApartment_id'
' RIGHT OUTER JOIN oknardia_seria_info'
' ON oknardia_apartment_type.kSeria_id = oknardia_seria_info.id '
'WHERE oknardia_seria_info.id = oknardia_seria_info.kRoot_id '
'GROUP BY oknardia_win_mountdim.iWinWidth, oknardia_win_mountdim.iWinHight,'
' oknardia_win_mountdim.bIsDoor, oknardia_win_mountdim.bIsNearDoor,'
' oknardia_win_mountdim.sFlapConfig, oknardia_win_mountdim.id,'
' oknardia_seria_info.sName, oknardia_seria_info.id '
'ORDER BY oknardia_win_mountdim.iWinWidth DESC,'
' oknardia_win_mountdim.iWinHight DESC,'
' oknardia_win_mountdim.bIsNearDoor,'
' oknardia_win_mountdim.bIsDoor,'
' oknardia_win_mountdim.id,'
' oknardia_seria_info.sName;')
list_windows_opening = []
tmp_id = 0
for i in q_win_opening:
if tmp_id != i.id:
tmp_id = i.id
image_file_name = get_flaps_for_mini_pictures(i.sFlapConfig)
list_windows_opening.append({
"ID": i.id,
"INCLUDING_IN_SERIA": [{
"ID": i.ID_Seria,
"NAME_T": pytils.translit.slugify(i.sName),
"NAME": i.sName
}],
"INCLUDING_IN_SERIA_ID": [],
"URL2IMG": image_file_name,
"FLAP_CONFIG": i.sFlapConfig,
"DESCRIPTION": i.sDescripion.split(" для")[0].split(" (")[0],
"DESCRIPTION_L": i.sDescripion,
"IS_DOOR": i.bIsDoor,
"IS_NEAR_DOOR": i.bIsNearDoor,
"H": i.iWinHight * 10,
"W": i.iWinWidth * 10
})
else:
list_windows_opening[-1]["INCLUDING_IN_SERIA"].append({
"ID": i.ID_Seria,
"NAME_T": pytils.translit.slugify(i.sName),
"NAME": i.sName
})
def _make_slug(value: str) -> str:
"""Транслитерирует строку в slug (pytils)."""
return pytils.translit.slugify(value)
def _append_visit_context(to_template: dict, request: HttpRequest, time_start: float) -> None:
"""Дописывает в контекст стандартный хвост: визиты и время выполнения."""
to_template.update({
'LIST_WIN_OPENING': list_windows_opening,
# получаем последние визиты клиента через куки
'LAST_VISIT': get_last_user_visit_list(get_last_user_visit_cookies(request)[:3]),
# получаем последние визиты всех посетителей из базы
# id2log, log_visit = get_last_all_user_visit_list()
'LOG_VISIT': get_last_all_user_visit_list(),
'ticks': float(time.perf_counter() - time_start)
'ticks': float(time.perf_counter() - time_start),
})
return render(request, "catalog/catalog_standard_opening.html", to_template)
def standard_opening(request: HttpRequest) -> HttpResponse:
"""
Каталог стандартных оконных проёмов и балконных блоков.
Что делает вьюха:
- Собирает уникальные пары «проём ↔ серия» через ORM.
- Агрегирует данные для шаблона в структуру LIST_WIN_OPENING с помощью groupby.
- Добавляет в контекст последние визиты и время выполнения.
"""
time_start = time.perf_counter()
q_win_opening = (
MountDim2Apartment.objects.filter(kApartment__kSeria_id=F('kApartment__kSeria__kRoot_id'))
.values(
'kMountDim_id',
'kMountDim__sFlapConfig',
'kMountDim__sDescripion',
'kMountDim__bIsDoor',
'kMountDim__bIsNearDoor',
'kMountDim__iWinHight',
'kMountDim__iWinWidth',
'kApartment__kSeria_id',
'kApartment__kSeria__sName',
)
.distinct()
.order_by(
'-kMountDim__iWinWidth',
'-kMountDim__iWinHight',
'kMountDim__bIsNearDoor',
'kMountDim__bIsDoor',
'kMountDim_id',
'kApartment__kSeria__sName',
)
)
list_windows_opening: list[dict[str, Any]] = []
# Группируем результаты по ID проёма, чтобы собрать все серии, в которые он входит.
# `order_by` в запросе гарантирует, что все записи для одного проёма идут подряд.
for mount_dim_id, group in groupby(q_win_opening, key=itemgetter('kMountDim_id')):
rows_for_opening = list(group)
first_row = rows_for_opening[0]
description_full = first_row['kMountDim__sDescripion'] or ''
# Собираем список серий для текущего проёма.
serias_for_opening = [
{
'ID': row['kApartment__kSeria_id'],
'NAME_T': _make_slug(row['kApartment__kSeria__sName']),
'NAME': row['kApartment__kSeria__sName'],
}
for row in rows_for_opening
]
# Формируем данные для строки таблиц (типовой проем)
list_windows_opening.append({
'ID': mount_dim_id,
'INCLUDING_IN_SERIA': serias_for_opening,
'URL2IMG': get_flaps_for_mini_pictures(first_row['kMountDim__sFlapConfig']),
'FLAP_CONFIG': first_row['kMountDim__sFlapConfig'],
'DESCRIPTION': description_full.split(' для')[0].split(' (')[0],
'DESCRIPTION_L': description_full,
'IS_DOOR': first_row['kMountDim__bIsDoor'],
'IS_NEAR_DOOR': first_row['kMountDim__bIsNearDoor'],
'H': first_row['kMountDim__iWinHight'] * 10, # см -> мм
'W': first_row['kMountDim__iWinWidth'] * 10, # см -> мм
})
to_template = {'LIST_WIN_OPENING': list_windows_opening}
_append_visit_context(to_template, request, time_start)
return render(request, 'catalog/catalog_standard_opening.html', to_template)