mod: raw SQL на ORM, убран макаронный код и исправлена пара ошибок в сравнениях характеристик.

This commit is contained in:
2026-05-07 23:20:59 +03:00
parent fb7096ca3d
commit 26d957a285

View File

@@ -3,6 +3,8 @@
from django.shortcuts import render, redirect from django.shortcuts import render, redirect
from django.http import HttpRequest, HttpResponse from django.http import HttpRequest, HttpResponse
from django.utils.dateformat import format from django.utils.dateformat import format
from django.utils import timezone
from django.db.models import F, Q, ExpressionWrapper, BooleanField, Max, Count, Avg
from oknardia.models import LogVisitPriceReport, SetKit from oknardia.models import LogVisitPriceReport, SetKit
from oknardia.settings import * from oknardia.settings import *
from web.add_func import normalize, get_rating_set_for_stars, sum_through from web.add_func import normalize, get_rating_set_for_stars, sum_through
@@ -13,6 +15,85 @@ import json
import re import re
import pytils import pytils
# Сигнальные значения для поиска min/max: заведомо вне диапазона реальных данных
_INI_MAX = -100_000
_INI_MIN = 1_000_000
def _color_hi(value, val_min: float, val_max: float, threshold=None, epsilon: float = 0.001) -> str | None:
"""Цвет ячейки "чем больше, тем лучше": зеленее → значение ближе к max.
:param value: значение поля для текущей строки
:param val_min: минимум по всей выборке (из первого прогона)
:param val_max: максимум по всей выборке
:param threshold: нижний порог: значения <= threshold считаются "нет данных" и не окрашиваются
:param epsilon: минимальный разброс, при котором окраска имеет смысл
:return: hex-строка цвета или None
"""
try:
v = float(value)
except (TypeError, ValueError):
return None
if val_max == _INI_MAX or val_min == _INI_MIN or val_max - val_min < epsilon:
return None
if threshold is not None and v <= threshold:
return None
if v <= val_min:
return None
ratio = (v - val_min) / (val_max - val_min)
c = 255 - int(ratio * 128)
return f"#{c:02x}ff{c:02x}"
def _color_lo(value, val_min: float, val_max: float, threshold=None, epsilon: float = 0.001) -> str | None:
"""Цвет ячейки "чем меньше, тем лучше": зеленее → значение ближе к min.
:param value: значение поля для текущей строки
:param val_min: минимум по всей выборке
:param val_max: максимум по всей выборке
:param threshold: нижний порог: значения <= threshold не окрашиваются
:param epsilon: минимальный разброс
:return: hex-строка цвета или None
"""
try:
v = float(value)
except (TypeError, ValueError):
return None
if val_max == _INI_MAX or val_min == _INI_MIN or val_max - val_min < epsilon:
return None
if threshold is not None and v <= threshold:
return None
if v >= val_max:
return None
ratio = (v - val_min) / (val_max - val_min)
c = 127 + int(ratio * 128)
return f"#{c:02x}ff{c:02x}"
def _bounds(items: list, field: str, threshold=None) -> tuple[float, float]:
"""Вычисляет (min, max) значений поля field по списку items, игнорируя None и <= threshold.
:param items: список объектов (SetKit с аннотациями)
:param field: имя атрибута
:param threshold: значения <= threshold исключаются из выборки
:return: (min, max) или (_INI_MIN, _INI_MAX) если нет валидных значений
"""
vals = []
for item in items:
raw = getattr(item, field, None)
if raw is None:
continue
try:
v = float(raw)
except (TypeError, ValueError):
continue
if threshold is not None and v <= threshold:
continue
vals.append(v)
if not vals:
return _INI_MIN, _INI_MAX
return min(vals), max(vals)
def get_last_user_visit_cookies(request: HttpRequest) -> list: def get_last_user_visit_cookies(request: HttpRequest) -> list:
""" Служебная функция: проверяет есть ли куки о последних посещениях пользователя, и если есть возвращает их """ Служебная функция: проверяет есть ли куки о последних посещениях пользователя, и если есть возвращает их
@@ -107,55 +188,57 @@ def compare_offers(request: HttpRequest, to_compare: str = "1,2") -> HttpRespons
if to_compare != list_fine: if to_compare != list_fine:
return redirect(f"/compare_offers/{list_fine}") return redirect(f"/compare_offers/{list_fine}")
try: try:
q_set_kit = SetKit.objects.raw( q_set_kit = (
f"SELECT " SetKit.objects
f"oknardia_setkit.id, oknardia_setkit.sSetName, oknardia_setkit.sSetDescription," .filter(id__in=list_fin)
f"oknardia_setkit.sSetClimateControl, oknardia_setkit.sSetSill, oknardia_setkit.sSetImplementAll," .annotate(
f"oknardia_setkit.sSetImplementHandles, oknardia_setkit.sSetImplementHinges," # Активность коммерческого предложения (аналог dSetCommercialUntil > NOW())
f"oknardia_setkit.sSetImplementLatch, oknardia_setkit.sSetImplementLimiter," bCommercial=ExpressionWrapper(
f"oknardia_setkit.sSetImplementCatch, oknardia_setkit.sSetPanes, oknardia_setkit.sSetSlope," Q(dSetCommercialUntil__gt=timezone.now()),
f"oknardia_setkit.sSetDelivery, oknardia_setkit.bSetDelivery, oknardia_setkit.sSetUninstallInstall," output_field=BooleanField()
f"oknardia_setkit.bSetUninstallInstall, oknardia_setkit.sSetOtherConditions," ),
f"oknardia_setkit.fSetRating, oknardia_setkit.iSetNumEval, oknardia_setkit.iSetImpressions," # Алиасы из MerchantBrand (SetKit → OurUser → MerchantOffice → MerchantBrand)
f"oknardia_setkit.iSetViews, oknardia_setkit.sSetActive, oknardia_setkit.dSetModify," MERCHANT_ID=F('kSet2User__kMerchantOffice__kMerchantName'),
f"(oknardia_setkit.dSetCommercialUntil > NOW()) AS bCommercial," sMerchantName=F('kSet2User__kMerchantOffice__kMerchantName__sMerchantName'),
f"oknardia_glazing.sGlazingReflectionAndAbsorptionOfHeat, oknardia_glazing.sGlazingBriefDescription," sMerchantMainURL=F('kSet2User__kMerchantOffice__kMerchantName__sMerchantMainURL'),
f"oknardia_glazing.sGlazingDescription, oknardia_glazing.fGlazingSoundproofing," pMerchantLogo=F('kSet2User__kMerchantOffice__kMerchantName__pMerchantLogo'),
f"oknardia_glazing.fGlazingRating, oknardia_glazing.sGlazingMark," # Алиасы из PVCprofiles (SetKit → kSet2PVCprofiles)
f"oknardia_glazing.fGlazingHeatTransfer, oknardia_glazing.fGlazingLightTransmission," PROFILE_ID=F('kSet2PVCprofiles'),
f"oknardia_glazing.fGlazingPassingSun, oknardia_glazing.sGlazingLightReflectance," sProfileName=F('kSet2PVCprofiles__sProfileName'),
f"oknardia_glazing.sGlazingManufacturer, oknardia_glazing.iGlazingCamerasN," sProfileBriefDescription=F('kSet2PVCprofiles__sProfileBriefDescription'),
f"oknardia_glazing.sGlazingToning, oknardia_glazing.iGlazingThickness," sProfileManufacturer=F('kSet2PVCprofiles__sProfileManufacturer'),
f"oknardia_merchantoffice.dOfficeDataCreate, oknardia_merchantoffice.sOfficeName," sProfileColor=F('kSet2PVCprofiles__sProfileColor'),
f"oknardia_merchantoffice.sOfficeStatus, oknardia_merchantoffice.sOfficePhones," iProfileCameras=F('kSet2PVCprofiles__iProfileCameras'),
f"oknardia_merchantoffice.sOfficeEmails, oknardia_merchantoffice.sOfficeDescription," iProfileThickness=F('kSet2PVCprofiles__iProfileThickness'),
f"oknardia_merchantoffice.sOfficeDiscountMetaFormula, oknardia_merchantoffice.fOfficeGeoCode_Latitude," iProfileGlazingThickness=F('kSet2PVCprofiles__iProfileGlazingThickness'),
f"oknardia_merchantoffice.fOfficeGeoCode_Longitude, oknardia_merchantoffice.sOfficeAddress," fProfileHeatTransf=F('kSet2PVCprofiles__fProfileHeatTransf'),
f"oknardia_ouruser.sUserAvatarImg, oknardia_ouruser.sUserJobTitle, oknardia_ouruser.bUserSubscribe," fProfileSeals=F('kSet2PVCprofiles__fProfileSeals'),
f"oknardia_ouruser.sUserPhone, oknardia_ouruser.sUserStatus, oknardia_merchantbrand.id AS MERCHANT_ID," sProfileSealDescription=F('kSet2PVCprofiles__sProfileSealDescription'),
f"oknardia_merchantbrand.sMerchantMainURL, oknardia_merchantbrand.sMerchantName," fProfileSoundproofing=F('kSet2PVCprofiles__fProfileSoundproofing'),
f"oknardia_merchantbrand.pMerchantLogo, oknardia_pvcprofiles.id AS PROFILE_ID," iProfileHeight=F('kSet2PVCprofiles__iProfileHeight'),
f"oknardia_pvcprofiles.sProfileName, oknardia_pvcprofiles.sProfileBriefDescription," iProfileRabbet=F('kSet2PVCprofiles__iProfileRabbet'),
f"oknardia_pvcprofiles.sProfileReinforcement, oknardia_pvcprofiles.sProfileDescription," sProfileFillet=F('kSet2PVCprofiles__sProfileFillet'),
f"oknardia_pvcprofiles.fProfileHeatTransf, oknardia_pvcprofiles.sProfileSealDescription," sProfileReinforcement=F('kSet2PVCprofiles__sProfileReinforcement'),
f"oknardia_pvcprofiles.fProfileSeals, oknardia_pvcprofiles.fProfileSoundproofing," sProfileOther=F('kSet2PVCprofiles__sProfileOther'),
f"oknardia_pvcprofiles.iProfileCameras, oknardia_pvcprofiles.iProfileGlazingThickness," fProfileRating=F('kSet2PVCprofiles__fProfileRating'),
f"oknardia_pvcprofiles.iProfileHeight, oknardia_pvcprofiles.iProfileRabbet," sProfileDescription=F('kSet2PVCprofiles__sProfileDescription'),
f"oknardia_pvcprofiles.iProfileThickness, oknardia_pvcprofiles.sProfileColor," # Алиасы из Glazing (SetKit → kSet2Glazing)
f"oknardia_pvcprofiles.sProfileFillet, oknardia_pvcprofiles.sProfileManufacturer," iGlazingCamerasN=F('kSet2Glazing__iGlazingCamerasN'),
f"oknardia_pvcprofiles.sProfileOther, oknardia_pvcprofiles.fProfileRating " iGlazingThickness=F('kSet2Glazing__iGlazingThickness'),
f"FROM oknardia_setkit" sGlazingBriefDescription=F('kSet2Glazing__sGlazingBriefDescription'),
f" INNER JOIN oknardia_pvcprofiles" sGlazingDescription=F('kSet2Glazing__sGlazingDescription'),
f" ON oknardia_setkit.kSet2PVCprofiles_id = oknardia_pvcprofiles.id" sGlazingMark=F('kSet2Glazing__sGlazingMark'),
f" INNER JOIN oknardia_glazing" sGlazingManufacturer=F('kSet2Glazing__sGlazingManufacturer'),
f" ON oknardia_setkit.kSet2Glazing_id = oknardia_glazing.id" fGlazingHeatTransfer=F('kSet2Glazing__fGlazingHeatTransfer'),
f" INNER JOIN oknardia_ouruser" fGlazingSoundproofing=F('kSet2Glazing__fGlazingSoundproofing'),
f" ON oknardia_setkit.kSet2User_id = oknardia_ouruser.id" fGlazingLightTransmission=F('kSet2Glazing__fGlazingLightTransmission'),
f" INNER JOIN oknardia_merchantoffice" sGlazingLightReflectance=F('kSet2Glazing__sGlazingLightReflectance'),
f" ON oknardia_ouruser.kMerchantOffice_id = oknardia_merchantoffice.id" fGlazingPassingSun=F('kSet2Glazing__fGlazingPassingSun'),
f" INNER JOIN oknardia_merchantbrand" sGlazingReflectionAndAbsorptionOfHeat=F('kSet2Glazing__sGlazingReflectionAndAbsorptionOfHeat'),
f" ON oknardia_merchantoffice.kMerchantName_id = oknardia_merchantbrand.id " sGlazingToning=F('kSet2Glazing__sGlazingToning'),
f"WHERE oknardia_setkit.id IN ({to_compare})") fGlazingRating=F('kSet2Glazing__fGlazingRating'),
)
)
except SetKit.DoesNotExist: except SetKit.DoesNotExist:
return redirect("/compare_offers/1,2") return redirect("/compare_offers/1,2")
list_set_kit = list(q_set_kit) list_set_kit = list(q_set_kit)
@@ -166,356 +249,156 @@ def compare_offers(request: HttpRequest, to_compare: str = "1,2") -> HttpRespons
except (ValueError, TypeError): except (ValueError, TypeError):
return render("/compare_offers/1,2") return render("/compare_offers/1,2")
# ПРЕДВАРИТЕЛЬНЫЙ "ПРОГОН" # ПРЕДВАРИТЕЛЬНЫЙ "ПРОГОН"
# Для того, чтобы "покрасить" ячейки таблицы сравнения в цвета, нужно для некоторых полей найти min и max... # Вычисляем min/max по каждому параметру для дальнейшей покраски ячеек.
ini_max = -100000 # Камеры профиля требуют sum_through() — обрабатываем отдельно.
ini_min = 1000000 cameras_vals = [
max_i_profile_cameras = max_f_profile_seals = max_i_profile_thickness = max_i_profile_glazing_thickness = \ c for i in list_set_kit
max_f_profile_heat_transf = max_f_profile_soundproofing = max_i_profile_rabbet = max_i_profile_height = \ if (c := sum_through(i.iProfileCameras)) is not None and c > 0
max_i_glazing_cameras_n = max_i_glazing_thickness = max_f_glazing_heat_transfer = max_rating_set = \ ]
max_f_glazing_soundproofing = max_f_glazing_light_transmission = max_f_glazing_passing_sun = ini_max min_cameras = min(cameras_vals) if cameras_vals else _INI_MIN
min_i_profile_cameras = min_f_profile_seals = min_i_profile_thickness = min_i_profile_glazing_thickness = \ max_cameras = max(cameras_vals) if cameras_vals else _INI_MAX
min_f_profile_heat_transf = min_f_profile_soundproofing = min_i_profile_rabbet = min_i_profile_height = \
min_i_glazing_cameras_n = min_i_glazing_thickness = min_f_glazing_heat_transfer = min_rating_set = \ # Остальные поля — через _bounds() с соответствующими порогами
min_f_glazing_soundproofing = min_f_glazing_light_transmission = min_f_glazing_passing_sun = ini_min # (threshold: значения <= порога считаются "нет данных" и исключаются из диапазона)
list_of_merchant_name = [] min_seals, max_seals = _bounds(list_set_kit, 'fProfileSeals', threshold=0)
list_of_profile_name = [] min_thick, max_thick = _bounds(list_set_kit, 'iProfileThickness', threshold=10)
list_of_glazing_brief_description = [] min_glaz_d, max_glaz_d = _bounds(list_set_kit, 'iProfileGlazingThickness', threshold=4)
for i in list_set_kit: min_heat_p, max_heat_p = _bounds(list_set_kit, 'fProfileHeatTransf', threshold=0)
if i.sMerchantName not in list_of_merchant_name: min_sound_p, max_sound_p = _bounds(list_set_kit, 'fProfileSoundproofing', threshold=0)
list_of_merchant_name.append(i.sMerchantName) min_rabbet, max_rabbet = _bounds(list_set_kit, 'iProfileRabbet', threshold=1)
if i.sProfileName not in list_of_profile_name: min_height, max_height = _bounds(list_set_kit, 'iProfileHeight', threshold=12)
list_of_profile_name.append(i.sProfileName) min_gl_cam, max_gl_cam = _bounds(list_set_kit, 'iGlazingCamerasN', threshold=0)
if i.sGlazingMark not in list_of_glazing_brief_description: min_gl_thick, max_gl_thick = _bounds(list_set_kit, 'iGlazingThickness', threshold=3)
list_of_glazing_brief_description.append(i.sGlazingMark) min_heat_g, max_heat_g = _bounds(list_set_kit, 'fGlazingHeatTransfer', threshold=0.05)
profile_num_cameras = sum_through(i.iProfileCameras) min_sound_g, max_sound_g = _bounds(list_set_kit, 'fGlazingSoundproofing', threshold=5)
if profile_num_cameras > 0: # Общее число камер профиля (рама+створка) min_light, max_light = _bounds(list_set_kit, 'fGlazingLightTransmission', threshold=5)
if profile_num_cameras > max_i_profile_cameras: min_sun, max_sun = _bounds(list_set_kit, 'fGlazingPassingSun', threshold=5)
max_i_profile_cameras = profile_num_cameras min_rating, max_rating = _bounds(list_set_kit, 'fSetRating', threshold=0.05)
if profile_num_cameras < min_i_profile_cameras:
min_i_profile_cameras = profile_num_cameras list_of_merchant_name = list({i.sMerchantName for i in list_set_kit})
if i.iProfileThickness > 0: # Контуров уплотнения list_of_profile_name = list({i.sProfileName for i in list_set_kit})
if i.fProfileSeals > max_f_profile_seals: list_of_glazing_brief = list({i.sGlazingMark for i in list_set_kit})
max_f_profile_seals = i.fProfileSeals
if i.fProfileSeals < min_f_profile_seals:
min_f_profile_seals = i.fProfileSeals
if i.iProfileThickness > 10: # Монтажная ширина профиля
if i.iProfileThickness > max_i_profile_thickness:
max_i_profile_thickness = i.iProfileThickness
if i.iProfileThickness < min_i_profile_thickness:
min_i_profile_thickness = i.iProfileThickness
if i.iProfileGlazingThickness > 4: # Максимальная толщина стеклопакета
if i.iProfileGlazingThickness > max_i_profile_glazing_thickness:
max_i_profile_glazing_thickness = i.iProfileGlazingThickness
if i.iProfileGlazingThickness < min_i_profile_glazing_thickness:
min_i_profile_glazing_thickness = i.iProfileGlazingThickness
if i.fProfileHeatTransf > 0: # Сопротивление теплопередаче
if i.fProfileHeatTransf > max_f_profile_heat_transf:
max_f_profile_heat_transf = i.fProfileHeatTransf
if i.fProfileHeatTransf < min_f_profile_heat_transf:
min_f_profile_heat_transf = i.fProfileHeatTransf
if i.fProfileSoundproofing > 0: # Коэффициент звукоизоляции
if i.fProfileSoundproofing > max_f_profile_soundproofing:
max_f_profile_soundproofing = i.fProfileSoundproofing
if i.fProfileSoundproofing < min_f_profile_soundproofing:
min_f_profile_soundproofing = i.fProfileSoundproofing
if i.iProfileRabbet > 1: # Фальц
if i.iProfileRabbet > max_i_profile_rabbet:
max_i_profile_rabbet = i.iProfileRabbet
if i.iProfileRabbet < min_i_profile_rabbet:
min_i_profile_rabbet = i.iProfileRabbet
if i.iProfileHeight > 12: # Высота в световом проеме
if i.iProfileHeight > max_i_profile_height:
max_i_profile_height = i.iProfileHeight
if i.iProfileHeight < min_i_profile_height:
min_i_profile_height = i.iProfileHeight
if i.iGlazingCamerasN > 0: # Камер стеклопакета
if i.iGlazingCamerasN > max_i_glazing_cameras_n:
max_i_glazing_cameras_n = i.iGlazingCamerasN
if i.iGlazingCamerasN < min_i_glazing_cameras_n:
min_i_glazing_cameras_n = i.iGlazingCamerasN
if i.iGlazingThickness > 4: # Толщина стеклопакета
if i.iGlazingThickness > max_i_glazing_thickness:
max_i_glazing_thickness = i.iGlazingThickness
if i.iGlazingThickness < min_i_glazing_thickness:
min_i_glazing_thickness = i.iGlazingThickness
if i.fGlazingHeatTransfer > 0.05: # Сопротивление теплопередаче стеклопакета Ro (м²×°C/Вт)
if i.fGlazingHeatTransfer > max_f_glazing_heat_transfer:
max_f_glazing_heat_transfer = i.fGlazingHeatTransfer
if i.fGlazingHeatTransfer < min_f_glazing_heat_transfer:
min_f_glazing_heat_transfer = i.fGlazingHeatTransfer
if i.fGlazingSoundproofing > 5: # Коэффициент звукоизоляции стеклопакета
if i.fGlazingSoundproofing > max_f_glazing_soundproofing:
max_f_glazing_soundproofing = i.fGlazingSoundproofing
if i.fGlazingSoundproofing < min_f_glazing_soundproofing:
min_f_glazing_soundproofing = i.fGlazingSoundproofing
if i.fGlazingLightTransmission > 5: # Коэффициент светопропускания стеклопакета
if i.fGlazingLightTransmission > max_f_glazing_light_transmission:
max_f_glazing_light_transmission = i.fGlazingLightTransmission
if i.fGlazingLightTransmission < min_f_glazing_light_transmission:
min_f_glazing_light_transmission = i.fGlazingLightTransmission
if i.fGlazingPassingSun > 5: # Коэффициент солнцепропускания стеклопакета
if i.fGlazingPassingSun > max_f_glazing_passing_sun:
max_f_glazing_passing_sun = i.fGlazingPassingSun
if i.fGlazingPassingSun < min_f_glazing_passing_sun:
min_f_glazing_passing_sun = i.fGlazingPassingSun
if i.fSetRating > 0.05: # Рейтинг НАБОРА!
if i.fSetRating > max_rating_set:
max_rating_set = i.fSetRating
if i.fSetRating < min_rating_set:
min_rating_set = i.fSetRating
# ОКОНЧАТЕЛЬНЫЙ ПРОГОН # ОКОНЧАТЕЛЬНЫЙ ПРОГОН
# Передаём данные из SQL-запроса шаблон. Иногда надо вычислять цвета и прочее. # Формируем список словарей для шаблона; цвета вычисляются через хелперы _color_hi / _color_lo.
# Много макаронного стиля кодинга, из-за того что иначе придется передавать в функции большие массивы QuerySet.
# А это жрет много памяти.
dim = [] dim = []
for i in list_set_kit: for i in list_set_kit:
# построим массив "цветов" для рейтинга "Общее число камер профиля (рама+створка)" (чем больше, тем лучше)
profile_num_cameras = sum_through(i.iProfileCameras) profile_num_cameras = sum_through(i.iProfileCameras)
if max_i_profile_cameras == ini_max or min_i_profile_cameras == ini_min or profile_num_cameras <= 1 \
or profile_num_cameras == min_i_profile_cameras or max_i_profile_cameras - min_i_profile_cameras < 0.001: # Рейтинг НАБОРА — особая логика со "звёздочками"
profile_num_cameras_color = None
else:
color_ratio = (profile_num_cameras - min_i_profile_cameras) / (
max_i_profile_cameras - min_i_profile_cameras)
profile_num_cameras_color = f"#{255 - int(color_ratio * 128):02x}ff{255 - int(color_ratio * 128):02x}"
# построим массив "цветов" для рейтинга "Контуров уплотнения" (чем больше, тем лучше)
if max_f_profile_seals == ini_max or min_f_profile_seals == ini_min or i.fProfileSeals <= 0 \
or i.fProfileSeals == min_f_profile_seals or max_f_profile_seals - min_f_profile_seals < 0.001:
profile_seals_color = None
else:
color_ratio = (i.fProfileSeals - min_f_profile_seals) / (max_f_profile_seals - min_f_profile_seals)
profile_seals_color = f"#{255 - int(color_ratio * 128):02x}ff{255 - int(color_ratio * 128):02x}"
# построим массив "цветов" для рейтинга "Монтажная ширина профиля" (чем больше, тем лучше)
if max_i_profile_thickness == ini_max or min_i_profile_thickness == ini_min or i.iProfileThickness <= 10 \
or i.iProfileThickness == min_i_profile_thickness \
or max_i_profile_thickness - min_i_profile_thickness < 0.001:
profile_thickness_color = None
else:
color_ratio = (i.iProfileThickness - min_i_profile_thickness) / (max_i_profile_thickness
- min_i_profile_thickness)
profile_thickness_color = f"#{255 - int(color_ratio * 128):02x}ff{255 - int(color_ratio * 128):02x}"
# построим массив "цветов" для рейтинга "Максимальная толщина стеклопакета" (чем больше, тем лучше)
if max_i_profile_glazing_thickness == ini_max or min_i_profile_glazing_thickness == ini_min \
or i.iProfileGlazingThickness <= 4 or i.iProfileGlazingThickness == min_i_profile_glazing_thickness \
or max_i_profile_glazing_thickness - min_i_profile_glazing_thickness < 0.001:
profile_glazing_thickness_color = None
else:
color_ratio = (i.iProfileGlazingThickness
- min_i_profile_glazing_thickness) / (max_i_profile_glazing_thickness
- min_i_profile_glazing_thickness)
profile_glazing_thickness_color = f"#{255 - int(color_ratio * 128):02x}ff{255 - int(color_ratio * 128):02x}"
# построим массив "цветов" для рейтинга "Сопротивление теплопередаче" (чем больше, тем лучше)
if max_f_profile_heat_transf == ini_max or min_f_profile_heat_transf == ini_min \
or i.fProfileHeatTransf == min_f_profile_heat_transf \
or max_f_profile_heat_transf - min_f_profile_heat_transf < 0.001:
profile_heat_transf_color = None
else:
color_ratio = (i.fProfileHeatTransf - min_f_profile_heat_transf) / (max_f_profile_heat_transf
- min_f_profile_heat_transf)
profile_heat_transf_color = f"#{255 - int(color_ratio * 128):02x}ff{255 - int(color_ratio * 128):02x}"
# построим массив "цветов" для рейтинга "Коэффициент звукоизоляции" (чем больше, тем лучше)
if max_f_profile_soundproofing == ini_max or min_f_profile_soundproofing == ini_min \
or i.fProfileSoundproofing == min_f_profile_soundproofing \
or max_f_profile_soundproofing - min_f_profile_soundproofing < 0.001:
profile_soundproofing_color = None
else:
color_ratio = (i.fProfileSoundproofing - min_f_profile_soundproofing) / (max_f_profile_soundproofing
- min_f_profile_soundproofing)
profile_soundproofing_color = f"#{255 - int(color_ratio * 128):02x}ff{255 - int(color_ratio * 128):02x}"
# построим массив "цветов" для рейтинга "Фальц" (чем больше, тем лучше)
if max_i_profile_rabbet == ini_max or min_i_profile_rabbet == ini_min or i.iProfileRabbet <= 1 \
or i.iProfileRabbet == min_i_profile_rabbet or max_i_profile_rabbet - min_i_profile_rabbet < 0.001:
profile_rabbet_color = None
else:
color_ratio = (i.iProfileRabbet - min_i_profile_rabbet) / (max_i_profile_rabbet - min_i_profile_rabbet)
profile_rabbet_color = f"#{255 - int(color_ratio * 128):02x}ff{255 - int(color_ratio * 128):02x}"
# построим массив "цветов" для рейтинга "Высота в световом проеме" (чем меньше, тем лучше)
if max_i_profile_rabbet == ini_max or min_i_profile_height == ini_min or i.iProfileHeight <= 12 \
or i.iProfileHeight == max_i_profile_height or max_i_profile_height - min_i_profile_height < 0.01:
profile_height_color = None
else:
color_ratio = (i.iProfileHeight - min_i_profile_height) / (max_i_profile_height - min_i_profile_height)
profile_height_color = f"#{127 + int(color_ratio * 128):02x}ff{127 + int(color_ratio * 128):02x}"
# построим массив "цветов" для рейтинга "Камер стеклопакета" (чем больше, тем лучше)
if max_i_glazing_cameras_n == ini_max or min_i_profile_height == ini_min \
or i.iGlazingCamerasN == min_i_glazing_cameras_n \
or max_i_glazing_cameras_n - min_i_glazing_cameras_n < 0.001:
glazing_cameras_n_color = None
else:
color_ratio = (i.iGlazingCamerasN - min_i_glazing_cameras_n) / (max_i_glazing_cameras_n
- min_i_glazing_cameras_n)
glazing_cameras_n_color = f"#{255 - int(color_ratio * 128):02x}ff{255 - int(color_ratio * 128):02x}"
# построим массив "цветов" для рейтинга "Толщина стеклопакета" (чем больше, тем лучше)
if max_i_glazing_thickness == ini_max or min_i_glazing_thickness == ini_min or i.iGlazingThickness <= 3 \
or i.iGlazingThickness == min_i_glazing_thickness \
or max_i_glazing_thickness - min_i_glazing_thickness < 0.001:
glazing_thickness_color = None
else:
color_ratio = (i.iGlazingThickness - min_i_glazing_thickness) / (max_i_glazing_thickness
- min_i_glazing_thickness)
glazing_thickness_color = f"#{255 - int(color_ratio * 128):02x}ff{255 - int(color_ratio * 128):02x}"
# построим массив "цветов" для рейтинга "Сопротивление теплопередаче стеклопакета" (чем больше, тем лучше)
if max_f_glazing_heat_transfer == ini_max or min_f_glazing_heat_transfer == ini_min \
or i.fGlazingHeatTransfer <= 0.05 or i.fGlazingHeatTransfer == min_f_glazing_heat_transfer \
or max_f_glazing_heat_transfer - min_f_glazing_heat_transfer < 0.001:
glazing_heat_transfer_color = None
else:
color_ratio = (i.fGlazingHeatTransfer - min_f_glazing_heat_transfer) / (max_f_glazing_heat_transfer
- min_f_glazing_heat_transfer)
glazing_heat_transfer_color = f"#{255 - int(color_ratio * 128):02x}ff{255 - int(color_ratio * 128):02x}"
# построим массив "цветов" для рейтинга "Коэффициент звукоизоляции стеклопакета" (чем больше, тем лучше)
if max_f_glazing_soundproofing == ini_max or min_f_glazing_soundproofing == ini_min \
or i.fGlazingSoundproofing <= 5 or i.fGlazingSoundproofing == min_f_glazing_heat_transfer \
or max_f_glazing_soundproofing - min_f_glazing_soundproofing < 0.001:
glazing_soundproofing_color = None
else:
color_ratio = (i.fGlazingSoundproofing - min_f_glazing_soundproofing) / (max_f_glazing_soundproofing
- min_f_glazing_soundproofing)
glazing_soundproofing_color = f"#{255 - int(color_ratio * 128):02x}ff{255 - int(color_ratio * 128):02x}"
# построим массив "цветов" для рейтинга "Коэффициент светопропускания стеклопакета" (чем больше, тем лучше)
if max_f_glazing_light_transmission == ini_max or min_f_glazing_light_transmission == ini_min \
or i.fGlazingLightTransmission <= 5 or i.fGlazingLightTransmission == min_f_glazing_light_transmission \
or max_f_glazing_light_transmission - min_f_glazing_light_transmission < 0.002:
glazing_light_transmission_color = None
else:
color_ratio = (i.fGlazingLightTransmission
- min_f_glazing_light_transmission) / (max_f_glazing_light_transmission
- min_f_glazing_light_transmission)
glazing_light_transmission_color = f"#{255 - int(color_ratio * 128):02x}ff{255 - int(color_ratio * 128):02x}"
# построим массив "цветов" для рейтинга "Коэффициент солнцепропускания стеклопакета" (чем меньше, тем лучше)
if max_f_glazing_passing_sun == ini_max or min_f_glazing_passing_sun == ini_min or i.fGlazingPassingSun <= 5 \
or i.fGlazingPassingSun == max_f_glazing_passing_sun \
or max_f_glazing_passing_sun - min_f_glazing_passing_sun < 0.0001:
glazing_passing_sun_color = None
else:
color_ratio = (i.fGlazingPassingSun - min_f_glazing_passing_sun) / (max_f_glazing_passing_sun
- min_f_glazing_passing_sun)
glazing_passing_sun_color = f"#{127 + int(color_ratio * 128):02x}ff{127 + int(color_ratio * 128):02x}"
########################################################################
# построим массив цветов "звездочек" для рейтинга наборов
if i.fSetRating > RARING_SET_MAX: if i.fSetRating > RARING_SET_MAX:
rating_set_n = RARING_SET_MAX rating_set_n = RARING_SET_MAX
rating_set_color = "#80ff80" rating_set_color = "#80ff80"
elif i.fSetRating < RARING_SET_MIN + 0.05 or max_rating_set - min_rating_set < 0.001: elif i.fSetRating < RARING_SET_MIN + 0.05 or max_rating - min_rating < 0.001:
rating_set_n = RARING_SET_MIN rating_set_n = RARING_SET_MIN
rating_set_color = "" rating_set_color = ""
else: else:
try: try:
rating_set_n = i.fSetRating * (RARING_SET_MAX - RARING_SET_MIN) / RARING_STAR rating_set_n = i.fSetRating * (RARING_SET_MAX - RARING_SET_MIN) / RARING_STAR
color_ratio = (i.fSetRating - min_rating_set) / (max_rating_set - min_rating_set) rating_set_color = _color_hi(i.fSetRating, min_rating, max_rating)
rating_set_color = f"#{255 - int(color_ratio * 128):02x}ff{255 - int(color_ratio * 128):02x}"
except (ZeroDivisionError, TypeError): except (ZeroDivisionError, TypeError):
rating_set_color = None rating_set_color = None
rating_set_n = RARING_SET_MIN rating_set_n = RARING_SET_MIN
# print RatingSet
list2_del = f",{to_compare}," list2_del = f",{to_compare},"
dim.append({ dim.append({
"MERCHANT": i.sMerchantName, "MERCHANT": i.sMerchantName,
"MERCHANT_ID": i.MERCHANT_ID, "MERCHANT_ID": i.MERCHANT_ID,
"IS_COMMERCIAL": i.bCommercial, "IS_COMMERCIAL": i.bCommercial,
"MERCHANT_T": pytils.translit.slugify(i.sMerchantName), "MERCHANT_T": pytils.translit.slugify(i.sMerchantName),
'MERCHANT_URL': i.sMerchantMainURL, "MERCHANT_URL": i.sMerchantMainURL,
'MERCHANT_URL_SHOT': re.sub("(?:^http://|^https://|/$|www\.)", "", i.sMerchantMainURL), "MERCHANT_URL_SHOT": re.sub(r"(?:^https?://|/$|www\.)", "", i.sMerchantMainURL),
"SET_NAME": i.sSetName, "SET_NAME": i.sSetName,
"MERCHANT_LOGO": i.pMerchantLogo, "MERCHANT_LOGO": i.pMerchantLogo,
"RATING_SET": get_rating_set_for_stars(i.fSetRating), "RATING_SET": get_rating_set_for_stars(i.fSetRating),
"RATING_SET_N": rating_set_n, "RATING_SET_N": rating_set_n,
"RATING_SET_COLOR": rating_set_color, "RATING_SET_COLOR": rating_set_color,
"PROFILE_ID": i.PROFILE_ID, "PROFILE_ID": i.PROFILE_ID,
"PROFILE_NAME": i.sProfileName, "PROFILE_NAME": i.sProfileName,
"PROFILE_NAME_T": pytils.translit.slugify(i.sProfileName), "PROFILE_NAME_T": pytils.translit.slugify(i.sProfileName),
"PROFILE_MANUFACTURER": i.sProfileManufacturer, "PROFILE_MANUFACTURER": i.sProfileManufacturer,
"PROFILE_MANUFACTURER_T": pytils.translit.slugify(i.sProfileManufacturer), "PROFILE_MANUFACTURER_T": pytils.translit.slugify(i.sProfileManufacturer),
"PROFILE_NUM_COLOR": i.sProfileColor, "PROFILE_NUM_COLOR": i.sProfileColor,
"PROFILE_NUM_CAMERAS": i.iProfileCameras, # Число камер рамы/створки "PROFILE_NUM_CAMERAS": i.iProfileCameras, # Число камер рамы/створки
"PROFILE_NUM_CAMERAS_COLOR": profile_num_cameras_color, # Число камер рамы/створки ЦВЕТА "PROFILE_NUM_CAMERAS_COLOR": _color_hi(profile_num_cameras, min_cameras, max_cameras, threshold=1),
"PROFILE_THICKNESS": i.iProfileThickness, # Монтажная ширина профиля "PROFILE_THICKNESS": i.iProfileThickness, # Монтажная ширина профиля
"PROFILE_THICKNESS_COLOR": profile_thickness_color, # Окраска Монтажная ширина профиля ЦВЕТА "PROFILE_THICKNESS_COLOR": _color_hi(i.iProfileThickness, min_thick, max_thick, threshold=10),
"PROFILE_GLAZING_THICKNESS": i.iProfileGlazingThickness, # Максимальная толщина стеклопакета "PROFILE_GLAZING_THICKNESS": i.iProfileGlazingThickness, # Макс. толщина стеклопакета
"PROFILE_GLAZING_THICKNESS_COLOR": profile_glazing_thickness_color, # Макс-толщина стеклопакета ЦВЕТА "PROFILE_GLAZING_THICKNESS_COLOR": _color_hi(i.iProfileGlazingThickness, min_glaz_d, max_glaz_d, threshold=4),
"PROFILE_HEAT_TRANSFER": i.fProfileHeatTransf, # Сопротивление теплопередаче "PROFILE_HEAT_TRANSFER": i.fProfileHeatTransf, # Сопротивление теплопередаче
"PROFILE_HEAT_TRANSFER_COLOR": profile_heat_transf_color, # Сопротивление теплопередаче ЦВЕТА "PROFILE_HEAT_TRANSFER_COLOR": _color_hi(i.fProfileHeatTransf, min_heat_p, max_heat_p),
"PROFILE_NUM_SEALS": i.fProfileSeals, # Контуров уплотнения "PROFILE_NUM_SEALS": i.fProfileSeals, # Контуров уплотнения
"PROFILE_NUM_SEALS_COLOR": profile_seals_color, # Контуров уплотнения ЦВЕТА "PROFILE_NUM_SEALS_COLOR": _color_hi(i.fProfileSeals, min_seals, max_seals, threshold=0),
"PROFILE_SEAL_DESCRIPTION": i.sProfileSealDescription, "PROFILE_SEAL_DESCRIPTION": i.sProfileSealDescription,
"PROFILE_SOUND_PROOFING": i.fProfileSoundproofing, # Коэффициент звукоизоляции "PROFILE_SOUND_PROOFING": i.fProfileSoundproofing, # Коэффициент звукоизоляции профиля
"PROFILE_SOUND_PROOFING_COLOR": profile_soundproofing_color, # Коэффициент звукоизоляции ЦВЕТА "PROFILE_SOUND_PROOFING_COLOR": _color_hi(i.fProfileSoundproofing, min_sound_p, max_sound_p),
"PROFILE_HEIGHT": i.iProfileHeight, # Высота в световом проеме "PROFILE_HEIGHT": i.iProfileHeight, # Высота в световом проеме (меньше = лучше)
"PROFILE_HEIGHT_COLOR": profile_height_color, # Высота в световом проеме ЦВЕТА "PROFILE_HEIGHT_COLOR": _color_lo(i.iProfileHeight, min_height, max_height, threshold=12),
"PROFILE_RABBET": i.iProfileRabbet, # Фальц "PROFILE_RABBET": i.iProfileRabbet, # Фальц
"PROFILE_RABBET_COLOR": profile_rabbet_color, # Фальц ЦВЕТА "PROFILE_RABBET_COLOR": _color_hi(i.iProfileRabbet, min_rabbet, max_rabbet, threshold=1),
"PROFILE_FILLET": i.sProfileFillet, # Штапик "PROFILE_FILLET": i.sProfileFillet, # Штапик
"PROFILE_REINFORCEMENT": i.sProfileReinforcement, # Армирование профиля "PROFILE_REINFORCEMENT": i.sProfileReinforcement, # Армирование профиля
"PROFILE_OTHER": i.sProfileOther, "PROFILE_OTHER": i.sProfileOther,
"SET_ID": i.id, # id-набора "SET_ID": i.id,
"SET_CLIMATE_CONTROL": i.sSetClimateControl, # климат контроль "SET_CLIMATE_CONTROL": i.sSetClimateControl,
"SET_STILL": i.sSetSill, # Подоконник "SET_STILL": i.sSetSill,
"SET_IMPLEMENTS_ALL": i.sSetImplementAll, # Фурнитура "SET_IMPLEMENTS_ALL": i.sSetImplementAll,
"SET_IMPLEMENTS_HANDLES": i.sSetImplementHandles, # Фурнитура: Ручки "SET_IMPLEMENTS_HANDLES": i.sSetImplementHandles,
"SET_IMPLEMENTS_HINGES": i.sSetImplementHinges, # Фурнитура: Петли "SET_IMPLEMENTS_HINGES": i.sSetImplementHinges,
"SET_IMPLEMENTS_LATCH": i.sSetImplementLatch, # Фурнитура: механизма запирания (запор) "SET_IMPLEMENTS_LATCH": i.sSetImplementLatch,
"SET_IMPLEMENTS_LIMITER": i.sSetImplementLimiter, # Фурнитура: Ограничитель "SET_IMPLEMENTS_LIMITER": i.sSetImplementLimiter,
"SET_IMPLEMENTS_CATCH": i.sSetImplementCatch, # Фурнитура: Фиксаторы открывания "SET_IMPLEMENTS_CATCH": i.sSetImplementCatch,
"SET_PANES": i.sSetPanes, # Водоотлив "SET_PANES": i.sSetPanes,
"SET_SLOPE": i.sSetSlope, # Откос "SET_SLOPE": i.sSetSlope,
"SET_DELIVERY": i.sSetDelivery, # Доставка (условия "SET_DELIVERY": i.sSetDelivery,
"SET_DELIVERY_B": i.bSetDelivery, # Доставка (да/нет) "SET_DELIVERY_B": i.bSetDelivery,
"SET_UNINSTALL_INSTALL": i.sSetUninstallInstall, # Монтаж/демонтаж (условия) "SET_UNINSTALL_INSTALL": i.sSetUninstallInstall,
"SET_UNINSTALL_INSTALL_B": i.bSetUninstallInstall, # Монтаж/демонтаж (да/нет) "SET_UNINSTALL_INSTALL_B": i.bSetUninstallInstall,
"SET_OTHER_CONDITIONS": i.sSetOtherConditions, # Прочие условия "SET_OTHER_CONDITIONS": i.sSetOtherConditions,
"GLAZING_CAMERAS_NUM": i.iGlazingCamerasN, # Камер стеклопакета "GLAZING_CAMERAS_NUM": i.iGlazingCamerasN, # Камер стеклопакета
"GLAZING_CAMERAS_COLOR": glazing_cameras_n_color, # Камер стеклопакета ЦВЕТА "GLAZING_CAMERAS_COLOR": _color_hi(i.iGlazingCamerasN, min_gl_cam, max_gl_cam),
"GLAZING_THICKNESS": i.iGlazingThickness, # Толщина стеклопакета "GLAZING_THICKNESS": i.iGlazingThickness, # Толщина стеклопакета
"GLAZING_THICKNESS_COLOR": glazing_thickness_color, # Толщина стеклопакета "GLAZING_THICKNESS_COLOR": _color_hi(i.iGlazingThickness, min_gl_thick, max_gl_thick, threshold=3),
"GLAZING_BRIEF_DESCRIPTION": re.sub(u",[\s\d]+мм", "", i.sGlazingBriefDescription), # Кратко о стеклопакете "GLAZING_BRIEF_DESCRIPTION": re.sub(r",[\s\d]+мм", "", i.sGlazingBriefDescription),
"GLAZING_MARK": i.sGlazingMark, # Схема, марка, маркировка, модель стеклопакета "GLAZING_MARK": i.sGlazingMark,
"GLAZING_MANUFACTURER": i.sGlazingManufacturer, # Производитель стеклопакета "GLAZING_MANUFACTURER": i.sGlazingManufacturer,
"GLAZING_HEAT_TRANSFER": i.fGlazingHeatTransfer, # Сопротивление теплопередаче стеклопакета Ro (м²×°C/Вт) "GLAZING_HEAT_TRANSFER": i.fGlazingHeatTransfer, # Ro стеклопакета (м²×°C/Вт)
"GLAZING_HEAT_TRANSFER_COLOR": glazing_heat_transfer_color, # Сопротивление теплопередаче стеклопакета ЦВЕТ "GLAZING_HEAT_TRANSFER_COLOR": _color_hi(i.fGlazingHeatTransfer, min_heat_g, max_heat_g, threshold=0.05),
"GLAZING_SOUNDPROOFING": i.fGlazingSoundproofing, # Коэффициент звукоизоляции стеклопакета "GLAZING_SOUNDPROOFING": i.fGlazingSoundproofing, # Звукоизоляция стеклопакета
"GLAZING_SOUNDPROOFING_COLOR": glazing_soundproofing_color, # Коэффициент звукоизоляции стеклопакета ЦВЕТА "GLAZING_SOUNDPROOFING_COLOR": _color_hi(i.fGlazingSoundproofing, min_sound_g, max_sound_g, threshold=5),
"GLAZING_LIGHT_TRANSMISSION": i.fGlazingLightTransmission, # Коэффициент светопропускания стеклопакета "GLAZING_LIGHT_TRANSMISSION": i.fGlazingLightTransmission,
"GLAZING_LIGHT_TRANSMISSION_COLOR": glazing_light_transmission_color, # Коэффициент светопропускания ЦВЕТА "GLAZING_LIGHT_TRANSMISSION_COLOR": _color_hi(i.fGlazingLightTransmission, min_light, max_light, threshold=5, epsilon=0.002),
"GLAZING_LIGHT_REFLECTION": i.sGlazingLightReflectance, # Коэффициент светоотражения внешний/внутренний "GLAZING_LIGHT_REFLECTION": i.sGlazingLightReflectance,
"GLAZING_PASSING_SUN": i.fGlazingPassingSun, # Коэффициент солнцепропускания стеклопакета "GLAZING_PASSING_SUN": i.fGlazingPassingSun, # Солнцепропускание (меньше = лучше)
"GLAZING_PASSING_SUN_COLOR": glazing_passing_sun_color, # Коэффициент солнцепропускания ЦВЕТ "GLAZING_PASSING_SUN_COLOR": _color_lo(i.fGlazingPassingSun, min_sun, max_sun, threshold=5, epsilon=0.0001),
"GLAZING_REFLECTION_AND_ABSORPTION": i.sGlazingReflectionAndAbsorptionOfHeat, "GLAZING_REFLECTION_AND_ABSORPTION": i.sGlazingReflectionAndAbsorptionOfHeat,
# Коэффициент теплоотражения/теплопоглощения стеклопакета "GLAZING_TONING": i.sGlazingToning,
"GLAZING_TONING": i.sGlazingToning, # Тонирование стеклопакета "URL_W_DEL": list2_del.replace(f",{i.id},", ",")[1:-1],
"URL_W_DEL": list2_del.replace(f",{i.id},", ",")[1:-1] # Тонирование стеклопакета
}) })
to_template.update({'SET_LIST': dim, to_template.update({'SET_LIST': dim,
'LIST_MERCHANT': list_of_merchant_name, 'LIST_MERCHANT': list_of_merchant_name,
'LIST_PROFILE': list_of_profile_name, 'LIST_PROFILE': list_of_profile_name,
'LIST_GLAZING': list_of_glazing_brief_description}) 'LIST_GLAZING': list_of_glazing_brief})
# Предложения для добавления в сравнения: # Предложения для добавления в сравнения:
if len(list_set_kit) < 7: if len(list_set_kit) < 7:
try: try:
q_set_kit = SetKit.objects.raw( q_set_kit = (
f"SELECT " SetKit.objects
f" oknardia_setkit.id, oknardia_setkit.sSetName," .exclude(id__in=list_fin) # исключаем уже сравниваемые наборы
f" oknardia_setkit.dSetModify, oknardia_setkit.fSetRating," .filter(priceoffer__isnull=False) # только наборы с ценовыми предложениями
f" oknardia_merchantbrand.sMerchantName," .annotate(
f" MAX(oknardia_priceoffer.dOfferModify) AS dLastData," dLastData=Max('priceoffer__dOfferModify'),
f" TO_DAYS(NOW()) - TO_DAYS(MAX(oknardia_priceoffer.dOfferModify)) AS deltaData " sMerchantName=F('kSet2User__kMerchantOffice__kMerchantName__sMerchantName'),
f"FROM oknardia_ouruser" )
f" INNER JOIN oknardia_setkit" .order_by('-dLastData')[:25]
f" ON oknardia_ouruser.id = oknardia_setkit.kSet2User_id" )
f" INNER JOIN oknardia_merchantoffice"
f" ON oknardia_merchantoffice.id = oknardia_ouruser.kMerchantOffice_id"
f" INNER JOIN oknardia_merchantbrand"
f" ON oknardia_merchantbrand.id = oknardia_merchantoffice.kMerchantName_id"
f" INNER JOIN oknardia_priceoffer"
f" ON oknardia_setkit.id = oknardia_priceoffer.kOffer2SetKit_id "
f"WHERE oknardia_setkit.id NOT IN (%s) "
f"GROUP BY oknardia_setkit.id,"
f" oknardia_setkit.sSetName,"
f" oknardia_merchantbrand.sMerchantName,"
f" oknardia_setkit.fSetRating "
f"ORDER BY dLastData DESC "
f"LIMIT 25;" % to_compare)
dim = [] dim = []
for i in q_set_kit: for i in q_set_kit:
# Вычисляем deltaData в Python (аналог TO_DAYS(NOW()) - TO_DAYS(MAX(dOfferModify)))
i.deltaData = (
(timezone.now().date() - i.dLastData.date()).days
if i.dLastData else 999
)
if i.deltaData < 100: if i.deltaData < 100:
early_data = pytils.dt.distance_of_time_in_words( early_data = pytils.dt.distance_of_time_in_words(
int(django.utils.dateformat.format(i.dLastData, 'U')), accuracy=2 int(django.utils.dateformat.format(i.dLastData, 'U')), accuracy=2
@@ -557,22 +440,17 @@ def show_rating_components(request: HttpRequest, win_set: str = "1") -> HttpResp
win_set = int(win_set) win_set = int(win_set)
except ValueError: except ValueError:
win_set = 1 win_set = 1
q = SetKit.objects.raw( q = (
f"SELECT oknardia_pvcprofiles.fProfileRating, oknardia_glazing.fGlazingRating," SetKit.objects
f" oknardia_setkit.fSetRating, oknardia_setkit.id, MAX(oknardia_priceoffer.dOfferModify) AS dPriceModify," .filter(id=win_set)
f" COUNT(oknardia_priceoffer.id) AS NumOffer, AVG(oknardia_priceoffer.fOfferRating) AS fOfferRatingAvg " .annotate(
f"FROM oknardia_setkit" dPriceModify=Max('priceoffer__dOfferModify'),
f" INNER JOIN oknardia_glazing" NumOffer=Count('priceoffer__id'),
f" ON oknardia_setkit.kSet2Glazing_id = oknardia_glazing.id" fOfferRatingAvg=Avg('priceoffer__fOfferRating'),
f" INNER JOIN oknardia_pvcprofiles" fProfileRating=F('kSet2PVCprofiles__fProfileRating'),
f" ON oknardia_setkit.kSet2PVCprofiles_id = oknardia_pvcprofiles.id" fGlazingRating=F('kSet2Glazing__fGlazingRating'),
f" INNER JOIN oknardia_priceoffer" )
f" ON oknardia_priceoffer.kOffer2SetKit_id = oknardia_setkit.id " )
f"WHERE oknardia_setkit.id = {win_set} "
f"GROUP BY oknardia_pvcprofiles.fProfileRating,"
f" oknardia_glazing.fGlazingRating,"
f" oknardia_setkit.fSetRating,"
f" oknardia_setkit.id;")
raring_list = list(q) raring_list = list(q)
f_rating_service = raring_list[0].fSetRating - RARING_WEIGHT_PVC_PROFILE_IN_SET * normalize( f_rating_service = raring_list[0].fSetRating - RARING_WEIGHT_PVC_PROFILE_IN_SET * normalize(
raring_list[0].fProfileRating, val_max=RARING_PVC_PROFILE_MAX raring_list[0].fProfileRating, val_max=RARING_PVC_PROFILE_MAX