From e0a5a5739b3044f352b11e887c22b74f7561c40d Mon Sep 17 00:00:00 2001 From: erjemin Date: Thu, 16 Apr 2026 21:12:31 +0300 Subject: [PATCH] minor: del print --- oknardia/web/prices.py | 5 +- oknardia/web/service.py | 333 +++++++++++++++++++++++++++++++++++++++- 2 files changed, 334 insertions(+), 4 deletions(-) diff --git a/oknardia/web/prices.py b/oknardia/web/prices.py index 37c4771..0b60da2 100644 --- a/oknardia/web/prices.py +++ b/oknardia/web/prices.py @@ -644,7 +644,10 @@ def report_price(request: HttpRequest, build_id: str = "22427", apart_id: str = # получаем последние визиты всех посетителей из базы log_visit = get_last_all_user_visit_list() - id_last_visit_log = log_visit[0]['id'] + 1 + if log_visit[0]['id'] is not None: + id_last_visit_log = log_visit[0]['id'] + 1 + else: + id_last_visit_log = 1 # print("id_last_visit_log:", id_last_visit_log) to_template.update({'LOG_VISIT': log_visit}) if id_last_visit_log > MAX_LEN_RING_LOG_BUFFER: # максимальный размер циклического буфера diff --git a/oknardia/web/service.py b/oknardia/web/service.py index dfa8da5..53e8402 100644 --- a/oknardia/web/service.py +++ b/oknardia/web/service.py @@ -20,7 +20,7 @@ def service(request: HttpRequest) -> HttpResponse: """ time_start = time.time() # проверка на аутентификацию - print(request.user.is_authenticated) + # print(request.user.is_authenticated) if not request.user.is_authenticated: return redirect("/service/not-denice") return render(request, "service/index.html", {'ticks': float(time.time()-time_start)}) @@ -157,7 +157,7 @@ def make_site_maps (request: HttpRequest) -> HttpResponse: with open(f"{SITEMAP_ROOT}sitemap.xml", "w", encoding="utf-8") as f: f.write(f"\n" f"\n{msg}") - print(SITEMAP_ROOT) + # print(SITEMAP_ROOT) msg = f"Создан единственный sitemap.xml\nВсего ссылок: {count_total_item:06d}" else: # Файлов sitemap.xml много. @@ -176,7 +176,7 @@ def make_site_maps (request: HttpRequest) -> HttpResponse: f.write(msg) msg = f"Создан каскадный sitemap.xml\nВсего вложенных файлов: {count_file+1:04d}\n" \ f"Всего ссылок: {count_total_item:08d}" - print(msg) + # print(msg) return HttpResponse(f"
{msg}\n\nвремя выполнения: {float(time.time()-time_start)} сек.
") @@ -222,3 +222,330 @@ def compare() -> list: # print(i1) # print(f"---------------{count}---------------") return dim_comp + + +def make_rating(request: HttpRequest) -> HttpResponse: + """ + Вычисляем (каждый раз заново) рейтинги оконных профилей, стеклопакетов и оконных наборов. + Вычисление базируется на ренкинге. В базовом ренкинге участвуют только стеклопакеты и профиля + присутствующие в коммерческих предложениях размещенных в ОКНАРДИИ. + + Ренкинг профилей: Для получения ранка вся совокупность профилей из коммерческих предложений сортируется + по тому или иному признаку (характеристике). Каждому профилю присваивается ранк, который вычисляется как + весу той или иной характеристики и порядковому номеру профиля в сортированному по этому признаку + (характеристике) в списке. + + ВНИМАНИЕ ТЕХНИЧЕСКИЙ ДОЛГ: + Система ренкинга разрабатывалась когда в базе было уже достаточно предложений. Возможно, если + объектов ренкинга будет мало что-то не сработает. И выдаст ошибку. + + :param request: HttpRequest -- запрос + :return: HttpResponse -- ответ + """ + time_start = time.time() + msg = "" + # ВЫЧИСЛЯЕМ РЕЙТИНГ ПРОФИЛЕЙ + # устанавливаем рейтинг всех профилей в базе в ноль + profile_all_num = PVCprofiles.objects.all().update(fProfileRating=0.0) + to_template = {'NUM_PROFILE_TOTAL': profile_all_num} # засовываем данные в шаблон + q = PVCprofiles.objects.raw("SELECT" + " oknardia_pvcprofiles.*," + " COUNT(oknardia_priceoffer.id) AS NumOffer " + "FROM oknardia_setkit" + " INNER JOIN oknardia_priceoffer" + " ON oknardia_setkit.id = oknardia_priceoffer.kOffer2SetKit_id" + " RIGHT OUTER JOIN oknardia_pvcprofiles" + " ON oknardia_setkit.kSet2PVCprofiles_id = oknardia_pvcprofiles.id " + "GROUP BY oknardia_pvcprofiles.id;") + profile_use_list = list(q) + # получаем словарь из RawQuerySet + PVC_Dictionary = Prepare_PVC_Dictionary(profile_use_list) + # получаем рейтинги + dim, PVC_Dictionary = RankingPVC(PVC_Dictionary) + to_template.update(dim) # засовываем данные в шаблон + # сортируем по полученному рейтингу + PVC_Dictionary = sorted(PVC_Dictionary, key=lambda item: item["TmpRating"]) + # print u"РЕЙТИНГИ ПРОФИЛЕЙ IN USE" + # найдем минимальный и максимальный ранкинг для последующей нормализации + NumMaxRank = 0 + NumMinRank = -1 + j = 0 + for i in PVC_Dictionary: + if i["NumOffer"] != 0: + NumMaxRank = j + if NumMinRank == -1: + NumMinRank = j + j += 1 + j = 0 + for i in PVC_Dictionary: + obj = PVCprofiles.objects.get(id=i["id"]) + try: + GettedJSON = json.loads(obj.sProfileDescription) + except: + GettedJSON = {} + if i["NumOffer"] != 0: + try: del GettedJSON[KEY_RATING_VIRTUAL] + except: pass + GettedJSON[KEY_RATING] = i["RatingConsist"] + # GettedJSON.update({KEY_RATING:i["RatingConsist"]}) + else: + try: del GettedJSON[KEY_RATING] + except: pass + GettedJSON[KEY_RATING_VIRTUAL] = i["RatingConsist"] + # GettedJSON.update({KEY_RATING_VIRTUAL:i["RatingConsist"]}) + obj.sProfileDescription = json.dumps(GettedJSON, + separators=(",",":"), + sort_keys=True, + encoding="utf-8", + ensure_ascii=False) + if j <= NumMaxRank: + obj.fProfileRating = Normalize(i["TmpRating"],PVC_Dictionary[NumMaxRank]["TmpRating"]) * (RARING_PVC_PROFILE_MAX-RARING_PVC_PROFILE_MIN) + RARING_PVC_PROFILE_MIN + else: + obj.fProfileRating = 5.0 + # print "id_PVC:", i["id"], u"\tΣ:", obj.fProfileRating, u"\tСостав:", + # print json.dumps(i["RatingConsist"], separators=(",",":"), encoding="utf-8", ensure_ascii=False) + obj.save() + j += 1 + # вычисляем рейтинги стеклопакетоа + # ░▒▓█▓▒░ ░▒▓█▓▒░ ░▒▓█▓▒░ ░▒▓█▓▒░ ░▒▓█▓▒░ ░▒▓█▓▒░ ░▒▓█▓▒░ ░▒▓█▓▒░ + # устанавливаем рейтинг всех стеклопакетоа в базе в ноль + GlazingAllNum = Glazing.objects.all().update(fGlazingRating=0.0) + to_template.update({'NUM_GLAZING_TOTAL':GlazingAllNum}) # засовываем данные в шаблон + q = Glazing.objects.raw("SELECT" + " oknardia_glazing.*," + " COUNT(oknardia_priceoffer.id) AS NumOffer " + "FROM oknardia_setkit" + " INNER JOIN oknardia_priceoffer" + " ON oknardia_priceoffer.kOffer2SetKit_id = oknardia_setkit.id" + " INNER JOIN oknardia_glazing" + " ON oknardia_setkit.kSet2Glazing_id = oknardia_glazing.id " + "GROUP BY oknardia_glazing.id;") + GlazingUseList = list(q) + # получаем словарь из RawQuerySet + GLAZ_Dictionary = Prepare_GLAZ_Dictionary(GlazingUseList) + # получаем рейтинги + dim, GLAZ_Dictionary = RankingGlazing(GLAZ_Dictionary) + to_template.update(dim) # засовываем данные в шаблон + # сортируем по полученному рейтингу + GLAZ_Dictionary = sorted(GLAZ_Dictionary, key=lambda item: item["TmpRating"]) + # print u"РЕЙТИНГИ СТЕКЛОПАКЕТОВ IN USE" + for i in GLAZ_Dictionary: + obj = Glazing.objects.get(id=i["id"]) + obj.fGlazingRating = Normalize(i["TmpRating"], ValMax=GLAZ_Dictionary[-1]["TmpRating"]) * (RARING_GLAZING_MAX-RARING_GLAZING_MIN) + RARING_GLAZING_MIN + try: + GettedJSON = json.loads(obj.sGlazingDescription) + except: + GettedJSON = {} + try: del GettedJSON[KEY_RATING_VIRTUAL] + except: pass + GettedJSON.update({KEY_RATING:i["RatingConsist"]}) + obj.sGlazingDescription = json.dumps(GettedJSON, + separators=(",",":"), + sort_keys=True, + encoding="utf-8", + ensure_ascii=False) + # print u"id:",i["id"], u"\tRank:", i["TmpRating"], u"\rate:", obj.fGlazingRating, u"\tGLAZ:", i["sGlazingMark"] + obj.save() + # получаем все стеклопакеты, чтобы забацать рейтинг и для тех, которые есть в каталоге но нет в КП + q = Glazing.objects.raw("SELECT oknardia_glazing.* " + "FROM oknardia_glazing;") + GlazingAllList = list(q) + # получаем словарь из RawQuerySet + GLAZ_Dictionary = Prepare_GLAZ_Dictionary(GlazingAllList) + # получаем рейтинги + dim, GLAZ_Dictionary = RankingGlazing(GLAZ_Dictionary) + GLAZ_Dictionary = sorted(GLAZ_Dictionary, key=lambda item: item["TmpRating"]) + if GlazingAllNum > len(GlazingUseList): + CutStartIndex = -1 + CutStartRatingValue = 0. + CutEndIndex = -1 + CutEndRatingValue = 0. + for i in range(0, GlazingAllNum): + # print i, GLAZ_Dictionary[i]["id"], u"\trank --> ", GLAZ_Dictionary[i]["TmpRating"], "\t(", + # print GLAZ_Dictionary[i]["fGlazingRating"], ")\tFormulaGLAZING:", GLAZ_Dictionary[i]["sGlazingMark"] + if GLAZ_Dictionary[i]["fGlazingRating"] != 0.: + # нашли конец следующего отрезка, нужно отрезок переопределить + CutStartRatingValue = CutEndRatingValue + CutStartIndex = CutEndIndex + CutEndRatingValue = GLAZ_Dictionary[i]["fGlazingRating"] + CutEndIndex = i + if CutEndIndex == 0: + continue + else: + # надо перебрать все объекты внутри отрезка + for j in range(CutStartIndex+1, CutEndIndex): + # и пересчитать рейтинги внутри этого, нового отрезка + GLAZ_Dictionary[j]["fGlazingRating"] = CutStartRatingValue + (GLAZ_Dictionary[j]["TmpRating"]-GLAZ_Dictionary[CutStartIndex]["TmpRating"])*((CutEndRatingValue-CutStartRatingValue)/(GLAZ_Dictionary[CutEndIndex]["TmpRating"]-GLAZ_Dictionary[CutStartIndex]["TmpRating"])) + # print j, GLAZ_Dictionary[j]["id"], u"\trank >>> ", GLAZ_Dictionary[j]["TmpRating"], "\t(", + # print GLAZ_Dictionary[j]["fGlazingRating"], ")\tFormulaGLAZING:", GLAZ_Dictionary[j]["sGlazingMark"] + # и записать этот рейтинг в базу + obj = Glazing.objects.get(id=GLAZ_Dictionary[j]["id"]) + obj.fGlazingRating = GLAZ_Dictionary[j]["fGlazingRating"] + try: + GettedJSON = json.loads(obj.sGlazingDescription) + except: + GettedJSON = {} + try: del GettedJSON[KEY_RATING] + except: pass + GettedJSON.update({KEY_RATING_VIRTUAL:GLAZ_Dictionary[j]["RatingConsist"]}) + obj.sGlazingDescription = json.dumps(GettedJSON, + separators=(",",":"), + sort_keys=True, + encoding="utf-8", + ensure_ascii=False) + obj.save() + for j in range(CutEndIndex+1, GlazingAllNum): + # пересчитать рейтинги хвоста (для отрезка после последнего отрейтингованного) + # внимание это код не для работы со словарями. при ревизии переделать GlazingAllList[j].fGlazingRating = CutStartRatingValue + (GlazingAllList[j].TmpRating-GlazingAllList[CutStartIndex].TmpRating)*((CutEndRatingValue-CutStartRatingValue)/(GlazingAllList[CutEndIndex].TmpRating-GlazingAllList[CutStartIndex].TmpRating)) + GLAZ_Dictionary[j]["fGlazingRating"] = RARING_GLAZING_MAX # т.к. для виртуальный рейтинг иногда снижается, то ставим 5* + # и записать этот рейтинг в базу + obj = Glazing.objects.get(id=GLAZ_Dictionary[j]["id"]) + obj.fGlazingRating = GLAZ_Dictionary[j]["fGlazingRating"] + try: + GettedJSON = json.loads(obj.sGlazingDescription) + except: + GettedJSON = {} + try: del GettedJSON[KEY_RATING] + except: pass + GettedJSON.update({KEY_RATING_VIRTUAL:GLAZ_Dictionary[j]["RatingConsist"]}) + obj.sGlazingDescription = json.dumps(GettedJSON, + separators=(",",":"), + sort_keys=True, + encoding="utf-8", + ensure_ascii=False) + + obj.save() + # вычисляем рейтинги наборов (стеклопакет + профиль + сопутсвующие услуги т.п. + # ░▒▓█▓▒░ ░▒▓█▓▒░ ░▒▓█▓▒░ ░▒▓█▓▒░ ░▒▓█▓▒░ ░▒▓█▓▒░ ░▒▓█▓▒░ ░▒▓█▓▒░ + # устанавливаем рейтинг всех наборов в базе в ноль + SetAllNum = SetKit.objects.all().update(fSetRating=0.0) + to_template.update({'NUM_SET_TOTAL':SetAllNum}) # засовываем данные в шаблон + q = SetKit.objects.raw("SELECT" + " COUNT(oknardia_priceoffer.id) AS NumOffer," + " MAX(oknardia_priceoffer.dOfferModify) AS dModify," + " oknardia_pvcprofiles.fProfileRating," + " oknardia_glazing.fGlazingRating," + " oknardia_setkit.*," + " oknardia_merchantoffice.sOfficeDiscountMetaFormula " + "FROM oknardia_setkit" + " INNER JOIN oknardia_priceoffer" + " ON oknardia_priceoffer.kOffer2SetKit_id = oknardia_setkit.id" + " INNER JOIN oknardia_glazing" + " ON oknardia_setkit.kSet2Glazing_id = oknardia_glazing.id" + " INNER JOIN oknardia_pvcprofiles" + " ON oknardia_pvcprofiles.id = oknardia_setkit.kSet2PVCprofiles_id " + " INNER JOIN oknardia_ouruser" + " ON oknardia_setkit.kSet2User_id = oknardia_ouruser.id" + " INNER JOIN oknardia_merchantoffice" + " ON oknardia_ouruser.kMerchantOffice_id = oknardia_merchantoffice.id " + "WHERE oknardia_setkit.sSetActive = TRUE " + "GROUP BY oknardia_pvcprofiles.fProfileRating," + " oknardia_glazing.fGlazingRating," + " oknardia_merchantoffice.sOfficeDiscountMetaFormula," + " oknardia_setkit.sSetActive, oknardia_setkit.id " + "ORDER BY MAX(oknardia_priceoffer.dOfferModify);") + # q = SetKit.objects.order_by("dModify") + SetUseList = list(q) + to_template.update({'NUM_SET': len(SetUseList) }) + SetDictionary = [] + # Превратим RawQuerySet в массив словарей (почти JSON). Так получится избежать "макаронного кода". + # Заодно переопределяем для правильного ранжирования некоторые параметры из строк в цифры. + for i in range(0,len(SetUseList)): + SetDictionary.append(q[i].__dict__) + if SetDictionary[i]["sSetSill"].lower() in [u"нет",u"-",u"—",""," "]: + SetDictionary[i]["sSetSill"] = 0 # Подоконника нет + else: SetDictionary[i]["sSetSill"] = 1 # Подоконник есть + if SetDictionary[i]["sSetPanes"].lower() in [u"нет",u"-",u"—",""," "]: + SetDictionary[i]["sSetPanes"] = 0 # Водоотлив нет + else: SetDictionary[i]["sSetPanes"] = 1 # Водоотлив есть + if SetDictionary[i]["sSetSlope"].lower() in [u"нет",u"-",u"—",""," "]: + SetDictionary[i]["sSetSlope"] = 0 # Откос нет + else: SetDictionary[i]["sSetSlope"] = 1 # Откос есть + if SetDictionary[i]["sSetClimateControl"].lower() in [u"нет",u"-",u"—",""," "]: + SetDictionary[i]["sSetClimateControl"] = 0 # Климат-контроль нет + else: SetDictionary[i]["sSetClimateControl"] = 1 # Климат-контроль есть + try: + # print eval(SetDictionary[i]["sOfficeDiscountMetaFormula"])[KEY_DICSOUNT].keys() + # print max(eval(SetDictionary[i]["sOfficeDiscountMetaFormula"])[KEY_DICSOUNT].values()) + SetDictionary[i].update({"DiscountMax": max(eval(SetDictionary[i]["sOfficeDiscountMetaFormula"])[KEY_DICSOUNT].values())}) + SetDictionary[i]["sOfficeDiscountMetaFormula"] = len(eval(SetDictionary[i]["sOfficeDiscountMetaFormula"])[KEY_DICSOUNT].keys()) + except: + SetDictionary[i].update({"DiscountMax": 0}) + SetDictionary[i]["sOfficeDiscountMetaFormula"] = 0 + # Отранжируем наборы по параметру "дата последнего обновления цены" -- ПО ВОЗРАСТАНИЮ + SetDictionary, MaxRank = GetRank(SetDictionary, "dModify", key_weight=RANK_STEP_SET_MODIFY, + rank_name=u"Актуальность", revers=False) + to_template.update({'S_Modify_Step': RANK_STEP_SET_MODIFY }) + to_template.update({'S_Modify_MaxRank': MaxRank }) + # Отранжируем наборы по параметру "доставка включена в стоимость" -- ПО ВОЗРАСТАНИЮ + SetDictionary, MaxRank = GetRank(SetDictionary, "bSetDelivery", key_weight=RANK_STEP_SET_DELIVERY, + rank_name=u"Доставка", revers=False) + to_template.update({'S_Delivery_Step': RANK_STEP_SET_DELIVERY }) + to_template.update({'S_Delivery_MaxRank': MaxRank }) + # Отранжируем наборы по параметру Демонтаж/Монтаж" -- ПО ВОЗРАСТАНИЮ + SetDictionary, MaxRank = GetRank(SetDictionary, "bSetUninstallInstall", key_weight=RANK_STEP_SET_UNINSTALL_INSTALL, + rank_name=u"Монтаж") + to_template.update({'S_UninstallInstall_Step': RANK_STEP_SET_UNINSTALL_INSTALL }) + to_template.update({'S_UninstallInstall_MaxRank': MaxRank }) + # Отранжируем наборы по параметру Подоконник" -- ПО ВОЗРАСТАНИЮ + SetDictionary, MaxRank = GetRank(SetDictionary, "sSetSill", key_weight=RANK_STEP_SET_SILL, + rank_name=u"Подоконник") + to_template.update({'S_Sill_Step': RANK_STEP_SET_SILL }) + to_template.update({'S_Sill_MaxRank': MaxRank }) + # Отранжируем наборы по параметру Водоотлив" -- ПО ВОЗРАСТАНИЮ + SetDictionary, MaxRank = GetRank(SetDictionary, "sSetPanes", key_weight=RANK_STEP_SET_PANES, + rank_name=u"Водоотлив") + to_template.update({'S_Panes_Step': RANK_STEP_SET_PANES }) + to_template.update({'S_Panes_MaxRank': MaxRank }) + # Отранжируем наборы по параметру Откос" -- ПО ВОЗРАСТАНИЮ + SetDictionary, MaxRank = GetRank(SetDictionary, "sSetSlope", key_weight=RANK_STEP_SET_SLOPE, + rank_name=u"Откос") + to_template.update({'S_Slope_Step': RANK_STEP_SET_SLOPE }) + to_template.update({'S_Slope_MaxRank': MaxRank }) + # Отранжируем наборы по параметру Климат-контроль" -- ПО ВОЗРАСТАНИЮ + SetDictionary, MaxRank = GetRank(SetDictionary, "sSetClimateControl", key_weight=RANK_STEP_SET_CLIMATE_CONTROL, + rank_name=u"Климат-контроль") + to_template.update({'S_ClimateControl_Step': RANK_STEP_SET_CLIMATE_CONTROL }) + to_template.update({'S_ClimateControl_MaxRank': MaxRank }) + # Отранжируем наборы по параметру Число предложений -- ПО ВОЗРАСТАНИЮ + SetDictionary, MaxRank = GetRank(SetDictionary, "NumOffer", key_weight=RANK_STEP_SET_NUM_OFFER, + rank_name=u"Число предложений") + to_template.update({'S_NumOffer_Step': RANK_STEP_SET_NUM_OFFER }) + to_template.update({'S_NumOffer_MaxRank': MaxRank }) + # Отранжируем наборы по параметру Гибкие скидки -- ПО ВОЗРАСТАНИЮ + SetDictionary, MaxRank = GetRank(SetDictionary, "sOfficeDiscountMetaFormula", key_weight=RANK_STEP_DISCOUNT_FLEX, + rank_name=u"Гибкость скидок") + to_template.update({'S_DiscountFlex_Step': RANK_STEP_DISCOUNT_FLEX }) + to_template.update({'S_DiscountFlex_MaxRank': MaxRank }) + # Отранжируем наборы по параметру Гибкие скидки -- ПО ВОЗРАСТАНИЮ + SetDictionary, MaxRank = GetRank(SetDictionary, "DiscountMax", key_weight=RANK_STEP_DISCOUNT_MAX, + rank_name=u"Размеры скидок") + to_template.update({'S_DiscountMax_Step': RANK_STEP_DISCOUNT_MAX }) + to_template.update({'S_DiscountMax_MaxRank': MaxRank }) + # расчитываем обзий рейтинг наборов и записываем в базу + SetDictionary = sorted(SetDictionary, key=lambda item: item["TmpRating"]) + # print u"РЕЙТИНГИ НАБОРОВ" + for i in SetDictionary: + obj = SetKit.objects.get(id=i["id"]) + try: + GettedJSON = json.loads(obj.sSetDescription) + except: + GettedJSON = {} + # нормализованный рейтинг сета + # print GettedJSON + k1 = Normalize(i["TmpRating"], SetDictionary[-1]["TmpRating"] )*(RARING_SET_MAX-RARING_WEIGHT_PVC_PROFILE_IN_SET-RARING_WEIGHT_GLAZING_IN_SET-RARING_SET_MIN) + k2 = Normalize(i["fGlazingRating"], RARING_GLAZING_MAX) * RARING_WEIGHT_GLAZING_IN_SET + k3 = Normalize(i["fProfileRating"], RARING_PVC_PROFILE_MAX) * RARING_WEIGHT_PVC_PROFILE_IN_SET + # print "id:", i["id"], u"\tk1:", k1, u"\tk2", k2, u"\tk3", k3, u"\tΣ:", k1+k2+k3 + obj.fSetRating = k1+k2+k3 + # print str(i["RatingConsist"]) + try: del GettedJSON[KEY_RATING_VIRTUAL] + except: pass + GettedJSON.update({KEY_RATING:i["RatingConsist"]}) + obj.sSetDescription = json.dumps(GettedJSON, separators=(",",":"), encoding="utf-8", ensure_ascii=False) + # print obj.sSetDescription + obj.save() + # print u"id:",i["id"], u"\tRank:", i["TmpRating"], u"\tRate:", obj.fSetRating, u"\tSet:", i["sSetName"], i["fProfileRating"], i["fGlazingRating"] + to_template.update({'msg': msg}) + to_template.update({'ticks': float(time.time()-time_start)}) + return render(request, "service/make_rating.html", to_template) \ No newline at end of file