# -*- coding: utf-8 -*- from django.core.exceptions import ObjectDoesNotExist from django.shortcuts import render, redirect from django.http import HttpRequest, HttpResponse from django.template.loader import render_to_string from django.utils import timezone from oknardia.settings import * from oknardia.models import PVCprofiles, Seria_Info, Win_MountDim, Building_Info 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 normalize, get_rating_set_for_stars, get_flaps_for_big_pictures import time import json import random import re import os import math import pytils def catalog_root(request: HttpRequest) -> HttpResponse: """ Корневая страница каталога ИДЕЯ: со временем нужно сделать функционал показа случайных картинок в каждый раздел (чтоб поисковики фигели) :param request: HttpRequest -- входящий http-запрос :return response: HttpResponse -- исходящий http-ответ """ time_start = time.time() # получаем из cookies последние визиты клиента to_template = { 'LAST_VISIT': get_last_user_visit_list(get_last_user_visit_cookies(request)[:3]), 'LOG_VISIT': get_last_all_user_visit_list(), 'ticks': float(time.time() - time_start)} response = render(request, "catalog/catalog_root.html", to_template) return response def catalog_profile(request: HttpRequest) -> HttpResponse: """ КАТАЛОГ ПРОФИЛЕЙ: страница со списком производителей и моделей (марками) профилей :param request: HttpRequest -- входящий http-запрос :return response: HttpResponse -- исходящий http-ответ """ time_start = time.time() q_profile = PVCprofiles.objects.raw('SELECT' ' oknardia_pvcprofiles.id,' ' oknardia_pvcprofiles.sProfileName,' ' oknardia_pvcprofiles.sProfileBriefDescription,' ' oknardia_pvcprofiles.sProfileManufacturer,' ' oknardia_catalog2profile.sCatalogCardType,' ' oknardia_blogposts.sPostContent,' ' oknardia_blogposts.sPostHeader,' 'oknardia_pvcprofiles.dProfileModify,' 'MAX(oknardia_blogposts.dPostDataModify) AS lastBlog ' 'FROM oknardia_catalog2profile' ' RIGHT OUTER JOIN oknardia_pvcprofiles' ' ON oknardia_catalog2profile.kProfile_id = oknardia_pvcprofiles.id' ' LEFT OUTER JOIN oknardia_blogposts' ' ON oknardia_catalog2profile.kBlogCatalog_id = oknardia_blogposts.id ' 'GROUP BY oknardia_catalog2profile.sCatalogCardType,' ' oknardia_pvcprofiles.sProfileName,' ' oknardia_pvcprofiles.id,' ' oknardia_pvcprofiles.sProfileBriefDescription,' ' oknardia_pvcprofiles.sProfileManufacturer,' ' oknardia_blogposts.sPostHeader,' ' oknardia_blogposts.sPostContent,' ' oknardia_pvcprofiles.dProfileModify ' 'ORDER BY oknardia_pvcprofiles.sProfileManufacturer,' ' oknardia_pvcprofiles.sProfileBriefDescription;') to_template = {'CATALOG_PROFILE_NUM': pytils.numeral.get_plural(len(list(q_profile)), "профиль,профиля,профилей")} list_profile_manufactures = [] tmp_profile_manufacture = "" last_update = None for i in q_profile: if last_update is None: last_update = i.dProfileModify if last_update < i.dProfileModify: last_update = i.dProfileModify # if (i.lastBlog is not None) and (last_update < i.lastBlog): # last_update = i.lastBlog if tmp_profile_manufacture != i.sProfileManufacturer: tmp_profile_manufacture = i.sProfileManufacturer list_profile_manufactures.append({ "PROF_MAN_ID": i.id, "PROF_MAN": i.sProfileManufacturer, "PROF_MAN_T": pytils.translit.slugify(i.sProfileManufacturer).lower(), "PROF_MAN_LIST": [{ "PROF_NAME_ID": i.id, "PROF_NAME": i.sProfileBriefDescription, "PROF_NAME_T": pytils.translit.slugify(i.sProfileName).lower(), }] }) # print("===", i.sProfileManufacturer, ">>> >>> >>>", Rus2Url(i.sProfileManufacturer)) elif len(list_profile_manufactures) == 0: # Какая-то фигня. Похоже "пустой" производитель профиля (пустая строка). Ну его нафиг. continue else: list_profile_manufactures[-1]["PROF_MAN_LIST"].append({ "PROF_NAME_ID": i.id, "PROF_NAME": i.sProfileBriefDescription, "PROF_NAME_T": pytils.translit.slugify(i.sProfileName).lower(), }) # print(\"--- ---", i.sProfileBriefDescription, ">>>", Rus2Url(i.sProfileBriefDescription)) to_template.update({ 'CATALOG_PROFILE_MAN1_NAME2': list_profile_manufactures, 'CATALOG_MANUFACT_NUM': len(list_profile_manufactures), 'CATALOG_MANUFACT_NUM_W': pytils.numeral.sum_string(len(list_profile_manufactures), pytils.numeral.MALE, ("производитель", "производителя", "производителей")), 'CATALOG_LAST_UPDATE': last_update, 'CATALOG_LAST_UPDATE_W': pytils.dt.distance_of_time_in_words(time.mktime(last_update.timetuple()), accuracy=2), 'LAST_VISIT': get_last_user_visit_list(get_last_user_visit_cookies(request)[:3]), 'LOG_VISIT': get_last_all_user_visit_list(), 'ticks': float(time.time() - time_start) }) return render(request, "catalog/catalog_of_profiles.html", to_template) def catalog_profile_model(request: HttpRequest, manufacture_id: int, manufacture_name: str, model_id: id, model_name: str) -> HttpResponse: """ КАТАЛОГ ПРОФИЛЕЙ: страница с описанием марки профиля :param request: HttpRequest -- входящий http-запрос :param manufacture_id: id профиля. Предполагается, что это первый id при сортировке по sProfileBriefDescription :param manufacture_name: название производителя (транслитерированное pytils.translit.slugify()) :param model_id: id модели (марки) профиля :param model_name: модель (марка) профиля (транслитерированное pytils.translit.slugify(sProfileName)) :return response: HttpResponse -- исходящий http-ответ """ time_start = time.time() manufacture_id = int(manufacture_id) model_id = int(model_id) q_pvc_by_id = PVCprofiles.objects.get(id=model_id) if pytils.translit.slugify(q_pvc_by_id.sProfileManufacturer) != manufacture_name \ or pytils.translit.slugify(q_pvc_by_id.sProfileName) != model_name \ or manufacture_id != model_id: return redirect(f"/catalog/profile/{model_id}-{pytils.translit.slugify(q_pvc_by_id.sProfileManufacturer)}/" f"{model_id}-{pytils.translit.slugify(q_pvc_by_id.sProfileName)}") to_template = {"CATALOG_MODEL": q_pvc_by_id, "CATALOG_MAN2URL": manufacture_name, "CATALOG_URL": f"{manufacture_id}-{manufacture_name}", "CATALOG_URL2": f"{manufacture_id}-{manufacture_name}/{model_id}-{model_name}", "PROFILE_RATING_STARS": get_rating_set_for_stars(q_pvc_by_id.fProfileRating)} try: got_json = json.loads(q_pvc_by_id.sProfileDescription) # раскрашиваем кружочки рейтинга напротив характеристик профиля if KEY_RATING in got_json: # RatingReal = True # Рейтинг реальный (профиль представлен в ценовых предложениях) # кружочки зелёные rating = got_json[KEY_RATING] color = int(255 - rating[RANK_PVCP_CAMERAS_NUM_NAME] * 255) to_template.update({"RANK_PVCP_CAMERAS_COLOR": f"{color},255,{color}"}) color = int(255 - rating[RANK_PVCP_SEALS_NAME] * 255) to_template.update({"RANK_PVCP_SEALS_COLOR": f"{color},255,{color}"}) color = int(255 - rating[RANK_PVCP_THICKNESS_NAME] * 255) to_template.update({"RANK_PVCP_THICKNESS_COLOR": f"{color},255,{color}"}) color = int(255 - rating[RANK_PVCP_G_THICKNESS_NAME] * 255) to_template.update({"RANK_PVCP_G_THICKNESS_COLOR": f"{color},255,{color}"}) color = int(255 - rating[RANK_PVCP_RABBET_NAME] * 255) to_template.update({"RANK_PVCP_RABBET_COLOR": f"{color},255,{color}"}) color = int(255 - rating[RANK_PVCP_HEAT_TRANSFER_NAME] * 255) to_template.update({"RANK_PVCP_HEAT_TRANSFER_COLOR": f"{color},255,{color}"}) color = int(255 - rating[RANK_PVCP_SOUNDPROOFING_NAME] * 255) to_template.update({"RANK_PVCP_SOUNDPROOFING_COLOR": f"{color},255,{color}"}) color = int(255 - rating[RANK_PVCP_HEIGHT_NAME] * 255) to_template.update({"RANK_PVCP_HEIGHT_COLOR": f"{color},255,{color}"}) elif KEY_RATING_VIRTUAL in got_json: # RatingReal = False # Рейтинг виртуальный (профиль представлен в ценовых предложениях) # кружочки серые rating = got_json[KEY_RATING_VIRTUAL] color = int(255 - rating[RANK_PVCP_CAMERAS_NUM_NAME] * 64) to_template.update({"RANK_PVCP_CAMERAS_COLOR": f"{color},{color},{color}"}) color = int(255 - rating[RANK_PVCP_SEALS_NAME] * 64) to_template.update({"RANK_PVCP_SEALS_COLOR": f"{color},{color},{color}"}) color = int(255 - rating[RANK_PVCP_THICKNESS_NAME] * 64) to_template.update({"RANK_PVCP_THICKNESS_COLOR": f"{color},{color},{color}"}) color = int(255 - rating[RANK_PVCP_G_THICKNESS_NAME] * 64) to_template.update({"RANK_PVCP_G_THICKNESS_COLOR": f"{color},{color},{color}"}) color = int(255 - rating[RANK_PVCP_RABBET_NAME] * 64) to_template.update({"RANK_PVCP_RABBET_COLOR": f"{color},{color},{color}"}) color = int(255 - rating[RANK_PVCP_HEAT_TRANSFER_NAME] * 64) to_template.update({"RANK_PVCP_HEAT_TRANSFER_COLOR": f"{color},{color},{color}"}) color = int(255 - rating[RANK_PVCP_SOUNDPROOFING_NAME] * 64) to_template.update({"RANK_PVCP_SOUNDPROOFING_COLOR": f"{color},{color},{color}"}) color = int(255 - rating[RANK_PVCP_HEIGHT_NAME] * 64) to_template.update({"RANK_PVCP_HEIGHT_COLOR": f"{color},{color},{color}"}) else: pass if KEY_HTML in got_json: to_template.update({"EXTRA_INFO": got_json[KEY_HTML]}) except (TypeError, ValueError, KeyError): pass list_other = [] for i in q_pvc_by_id.sProfileOther.split(";"): j = i.find(":") list_other.append(u"" + i[:j + 1] + u"" + i[j + 1:]) to_template.update({"LIST_OTHER": list_other}) q_merchant = PVCprofiles.objects.raw(f"SELECT" f" COUNT(oknardia_priceoffer.id) AS offers_by_merchant," f" oknardia_merchantbrand.sMerchantName," f" oknardia_merchantbrand.pMerchantLogo," f" oknardia_merchantbrand.id " f"FROM oknardia_priceoffer" f" INNER JOIN oknardia_setkit" f" ON oknardia_priceoffer.kOffer2SetKit_id = oknardia_setkit.id" f" INNER JOIN oknardia_pvcprofiles" f" ON oknardia_setkit.kSet2PVCprofiles_id = oknardia_pvcprofiles.id" f" INNER JOIN oknardia_ouruser" f" ON oknardia_setkit.kSet2User_id = oknardia_ouruser.id" f" INNER JOIN oknardia_merchantoffice" f" ON oknardia_ouruser.kMerchantOffice_id = oknardia_merchantoffice.id" f" INNER JOIN oknardia_merchantbrand" f" ON oknardia_merchantoffice.kMerchantName_id = oknardia_merchantbrand.id " f"WHERE oknardia_pvcprofiles.id = {model_id} " f"GROUP BY oknardia_merchantbrand.sMerchantName," f" oknardia_merchantbrand.pMerchantLogo," f" oknardia_merchantbrand.id " f"ORDER BY offers_by_merchant DESC;") list_merchant = [] for i in q_merchant: list_merchant.append({ "MERCHANT_ID": i.id, "MERCHANT_NAME": i.sMerchantName, "MERCHANT_NAME_T": pytils.translit.slugify(i.sMerchantName), "MERCHANT_LOGO_URL": i.pMerchantLogo, "MERCHANT_OFFERS": i.offers_by_merchant, }) to_template.update({'MERCHANTS': list_merchant}) q_profiles = PVCprofiles.objects.raw(f"SELECT oknardia_pvcprofiles.id," f" oknardia_pvcprofiles.fProfileRating," f" oknardia_pvcprofiles.sProfileBriefDescription," f" oknardia_pvcprofiles.sProfileName " f"FROM oknardia_pvcprofiles " f"WHERE oknardia_pvcprofiles.sProfileManufacturer =" f" '{q_pvc_by_id.sProfileManufacturer}' " f"ORDER BY oknardia_pvcprofiles.fProfileRating;") list_profiles = [] for i in q_profiles: if i.id != model_id: list_profiles.append({ "PROFILE_NAME": i.sProfileBriefDescription, "PROFILE_ID": i.id, "PROFILE_URL": pytils.translit.slugify(i.sProfileName).lower(), "PROFILE_RATING": i.fProfileRating, "PROFILE_RATING_STARS": get_rating_set_for_stars(i.fProfileRating), }) to_template.update({'PROFILES': list_profiles}) q_profiles_detail = PVCprofiles.objects.raw(f"SELECT" f" oknardia_blogposts.*," f" oknardia_pvcprofiles.id," f" oknardia_catalog2profile.sCatalogCardType," f" oknardia_blogposts.iCatalogSort " f"FROM oknardia_catalog2profile" f" INNER JOIN oknardia_blogposts" f" ON oknardia_catalog2profile.kBlogCatalog_id=oknardia_blogposts.id" f" INNER JOIN oknardia_pvcprofiles" f" ON oknardia_catalog2profile.kProfile_id=oknardia_pvcprofiles.id " f"WHERE oknardia_pvcprofiles.id = {model_id} " f"AND oknardia_catalog2profile.sCatalogCardType =" f" {CATALOG_RECORD_FOR_PROFILE_MODEL} " f"ORDER BY oknardia_blogposts.iCatalogSort;") list_profiles_detail = list(q_profiles_detail) to_template.update({'PROFILE_DETAIL': list_profiles_detail}) list_img_for_blog = [] for i in list_profiles_detail: if i.sImgForBlogSocial != "": list_img_for_blog.append(i.sImgForBlogSocial) if len(list_profiles_detail) > 0: random.shuffle(list_img_for_blog) to_template.update({'IMG_FOR_BLOG': list_img_for_blog[0]}) to_template.update({'PUB_DAT': q_pvc_by_id.dProfileModify}) if len(list_profiles_detail) > 0: pub_data = sorted(list_profiles_detail, key=lambda item: item.dPostDataModify)[0].dPostDataModify if pub_data.replace(tzinfo=None) < q_pvc_by_id.dProfileModify.replace(tzinfo=None): to_template.update({'PUB_DAT': pub_data}) to_template.update({ # получаем последние визиты клиента через куки '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.time() - time_start) }) return render(request, "catalog/catalog_of_profiles_model.html", to_template) def catalog_profile_manufacture(request: HttpRequest, manufacture_id: int, manufacture_name: str) -> HttpResponse: """ КАТАЛОГ ПРОФИЛЕЙ: страница с описанием производителя профилей и списком марки производимых им профилей :param request: HttpRequest -- входящий http-запрос :param manufacture_id: id профиля. Предполагается, что это первый id при сортировке по sProfileBriefDescription :param manufacture_name: название производителя (транслитерированное pytils.translit.slugify()) :return response: HttpResponse -- исходящий http-ответ """ time_start = time.time() manufacture_id = int(manufacture_id) q_pvc_by_id = PVCprofiles.objects.get(id=manufacture_id) if pytils.translit.slugify(q_pvc_by_id.sProfileManufacturer) != manufacture_name: return redirect(f'/catalog/profile/{manufacture_id}-' f'{pytils.translit.slugify(q_pvc_by_id.sProfileManufacturer)}') else: q_pvc_by_id = PVCprofiles.objects.order_by('id') \ .filter(sProfileManufacturer=q_pvc_by_id.sProfileManufacturer).first() if q_pvc_by_id.id != manufacture_id: return redirect(f'/catalog/profile/{q_pvc_by_id.id}-' f'{pytils.translit.slugify(q_pvc_by_id.sProfileManufacturer)}') to_template = {'CATALOG_MANUFACT': q_pvc_by_id.sProfileManufacturer, 'CATALOG_MAN2URL': manufacture_name, 'CATALOG_URL': f"{manufacture_id}-{manufacture_name}"} try: # получаем информацию о производителе (статью из блога) manufacture_description = list(PVCprofiles.objects.raw( f"SELECT " f" oknardia_blogposts.* " f"FROM oknardia_catalog2profile" f" RIGHT OUTER JOIN oknardia_pvcprofiles" f" ON oknardia_catalog2profile.kProfile_id = oknardia_pvcprofiles.id" f" LEFT OUTER JOIN oknardia_blogposts" f" ON oknardia_catalog2profile.kBlogCatalog_id = oknardia_blogposts.id " f"WHERE oknardia_catalog2profile.sCatalogCardType = {CATALOG_RECORD_FOR_PROFILE_MANUFACTURER} " f" AND oknardia_pvcprofiles.sProfileManufacturer = '{q_pvc_by_id.sProfileManufacturer}'" f" AND oknardia_blogposts.bCatalog IS TRUE " f"GROUP BY oknardia_blogposts.bCatalog " f"LIMIT 1;" ))[0] to_template.update({'PUB_DAT': manufacture_description.dPostDataModify}) if PATH_FOR_IMG_BLOG in manufacture_description.sImgForBlogSocial: to_template.update({'IMG_FOR_BLOG': manufacture_description.sImgForBlogSocial}) to_template.update({'HEADER': manufacture_description.sPostHeader, 'CONTENT': re.sub(r'', '', manufacture_description.sPostContent, 0, re.IGNORECASE)}) to_template.update({'TIZER': re.sub(r'||', '', to_template["CONTENT"], 0, re.IGNORECASE)}) except (ObjectDoesNotExist, IndexError, TypeError, KeyError,): pass q_profiles = PVCprofiles.objects.raw( f"SELECT oknardia_pvcprofiles.id," f" oknardia_pvcprofiles.fProfileRating," f" oknardia_pvcprofiles.sProfileBriefDescription," f" oknardia_pvcprofiles.sProfileName " f"FROM oknardia_pvcprofiles " f"WHERE oknardia_pvcprofiles.sProfileManufacturer = '{q_pvc_by_id.sProfileManufacturer}' " f"ORDER BY oknardia_pvcprofiles.fProfileRating;" ) list_profiles = [] for i in q_profiles: list_profiles.append({ "PROFILE_NAME": i.sProfileBriefDescription, "PROFILE_ID": i.id, "PROFILE_URL": pytils.translit.slugify(i.sProfileName).lower(), "PROFILE_RATING": i.fProfileRating, "PROFILE_RATING_STARS": get_rating_set_for_stars(i.fProfileRating), }) to_template.update({'PROFILES': list_profiles}) try: q_share_of_offers = list(PVCprofiles.objects.raw( f"SELECT" f" 1 AS id," f" SUM(Q1.offers_by_model) AS offers_by_maufacture," f" Q2.tatal_offers-SUM(Q1.offers_by_model) AS offers_other " f"FROM (SELECT COUNT(oknardia_priceoffer.id) AS offers_by_model" f" FROM oknardia_priceoffer" f" LEFT OUTER JOIN oknardia_setkit" f" ON oknardia_priceoffer.kOffer2SetKit_id = oknardia_setkit.id" f" RIGHT OUTER JOIN oknardia_pvcprofiles" f" ON oknardia_setkit.kSet2PVCprofiles_id = oknardia_pvcprofiles.id" f" WHERE oknardia_pvcprofiles.sProfileManufacturer = '{q_pvc_by_id.sProfileManufacturer}') Q1," f" (SELECT COUNT(oknardia_priceoffer.id) AS tatal_offers" f" FROM oknardia_priceoffer) AS Q2 " f"LIMIT 1;" ))[0] to_template.update({ 'OFFERS_BY_MAUFACTURE': q_share_of_offers.offers_by_maufacture, 'OFFERS_OTHER': q_share_of_offers.offers_other, 'OFFERS_ANGLE': 90 + 180 * normalize(q_share_of_offers.offers_by_maufacture, q_share_of_offers.offers_other + q_share_of_offers.offers_by_maufacture) }) if q_share_of_offers is not None and q_share_of_offers.offers_by_maufacture != 0: q_merchant = PVCprofiles.objects.raw( f"SELECT" f" COUNT(oknardia_priceoffer.id) AS offers_by_merchant," f" oknardia_merchantbrand.sMerchantName," f" oknardia_merchantbrand.pMerchantLogo," f" oknardia_merchantbrand.id " f"FROM oknardia_priceoffer" f" INNER JOIN oknardia_setkit" f" ON oknardia_priceoffer.kOffer2SetKit_id = oknardia_setkit.id" f" INNER JOIN oknardia_pvcprofiles" f" ON oknardia_setkit.kSet2PVCprofiles_id = oknardia_pvcprofiles.id" f" INNER JOIN oknardia_ouruser" f" ON oknardia_setkit.kSet2User_id = oknardia_ouruser.id" f" INNER JOIN oknardia_merchantoffice" f" ON oknardia_ouruser.kMerchantOffice_id = oknardia_merchantoffice.id" f" INNER JOIN oknardia_merchantbrand" f" ON oknardia_merchantoffice.kMerchantName_id = oknardia_merchantbrand.id " f"WHERE oknardia_pvcprofiles.sProfileManufacturer = '{q_pvc_by_id.sProfileManufacturer}' " f"GROUP BY oknardia_merchantbrand.sMerchantName," f" oknardia_merchantbrand.pMerchantLogo," f" oknardia_merchantbrand.id " f"ORDER BY offers_by_merchant DESC;" ) list_merchant = [] for i in q_merchant: list_merchant.append({ "MERCHANT_ID": i.id, "MERCHANT_NAME": i.sMerchantName, "MERCHANT_NAME_T": pytils.translit.slugify(i.sMerchantName), "MERCHANT_LOGO_URL": i.pMerchantLogo, "MERCHANT_OFFERS": i.offers_by_merchant }) to_template.update({'MERCHANTS': list_merchant}) except (ObjectDoesNotExist, IndexError, TypeError): # вообще-то, запрос q_share_of_offers всегда что-то вернёт, pass # но на всякий случай to_template.update({ # получаем последние визиты клиента через куки '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.time() - time_start) }) return render(request, "catalog/catalog_of_profiles_manufacture.html", to_template) # Каталог типовый серий зданий (пока переадресация) def catalog_seria(request: HttpRequest) -> HttpResponse: """ КАТАЛОГ ТИПОВЫЙ СЕРИЙ: страница со всеми сериями зданий в базе окнардии :param request: HttpRequest -- входящий http-запрос :return response: HttpResponse -- исходящий http-ответ """ time_start = time.time() try: q_seria = Seria_Info.objects.raw('SELECT' ' oknardia_seria_info.id,' ' oknardia_seria_info.sURL2IMG,' ' oknardia_seria_info.sName ' 'FROM oknardia_seria_info ' 'WHERE oknardia_seria_info.id = oknardia_seria_info.kRoot_id ' 'ORDER BY oknardia_seria_info.sName;') list_seria = [] for i in q_seria: list_seria.append({ "ID": i.id, "URL": i.sURL2IMG, "NAME": i.sName, "NAME_T": pytils.translit.slugify(i.sName) }) to_template = {'SERIAS': list_seria} except (ObjectDoesNotExist,): to_template = {} to_template.update({ # получаем последние визиты клиента через куки '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.time() - time_start) }) return render(request, "catalog/catalog_seria.html", to_template) def catalog_seria_info(request: HttpRequest, seria_name_translit: str = "II-49", seria_id: int = 12) -> HttpResponse: """ КАТАЛОГ ТИПОВЫЙ СЕРИЙ: страница детальной информацией по серии зданий :param request: HttpRequest -- входящий http-запрос :param seria_name_translit: str -- имя серии здания (транслитерированное pytils.translit.slugify()) :param seria_id: int -- id серии :return response: HttpResponse -- исходящий http-ответ """ time_start = time.time() msg = "" try: seria_id = int(seria_id) q_seria = Seria_Info.objects.get(id=seria_id) if q_seria.id != q_seria.kRoot_id or seria_name_translit != pytils.translit.slugify(q_seria.sName): return redirect(f"/catalog/seria/{pytils.translit.slugify(q_seria.sName)}/all{seria_id}") except(ObjectDoesNotExist, ValueError,): return redirect("/catalog/") # если есть "облегченный" шаблон с частичным пре-рендером, то используем его. light_template = f"{PATH_FOR_SERIA_INFO_HTML_INCLUDE}{str(seria_id)}_id.html" light_template_w_path = f"{TEMPLATES[0]['DIRS'][0]}/{light_template}" # print(f"{TEMPLATES[0]['DIRS'][0]}/{light_template}") # print(light_template_w_path) if os.path.isfile(light_template_w_path): is_hard_template = False else: is_hard_template = True to_template = {} # получаем проемы использующиеся в данной серии домов q_windows_in_seria = Win_MountDim.objects.raw( f"SELECT DISTINCT" f" oknardia_win_mountdim.iWinWidth, oknardia_win_mountdim.iWinHight," f" oknardia_win_mountdim.sDescripion, oknardia_win_mountdim.bIsDoor," f" oknardia_win_mountdim.bIsNearDoor, oknardia_win_mountdim.sFlapConfig," f" oknardia_win_mountdim.iWinDepth, oknardia_win_mountdim.id," f" 1 AS iQuantity " f"FROM oknardia_mountdim2apartment" f" INNER JOIN oknardia_win_mountdim" f" ON oknardia_mountdim2apartment.kMountDim_id = oknardia_win_mountdim.id" f" INNER JOIN oknardia_apartment_type" f" ON oknardia_mountdim2apartment.kApartment_id = oknardia_apartment_type.id " f"WHERE oknardia_apartment_type.kSeria_id = {seria_id}" f" ORDER BY oknardia_win_mountdim.bIsNearDoor DESC," f" oknardia_win_mountdim.bIsDoor DESC," f" oknardia_win_mountdim.iWinWidth," f" oknardia_win_mountdim.iWinHight DESC;") if is_hard_template: # Получаем данные для отрисовки больших картинок с проёмами и передаём в "тяжёлый" шаблон to_template.update(get_flaps_for_big_pictures(q_windows_in_seria)) # формируем строку для включения в SQL-запрос вида "(2,8,16,46,1)" str_for_sql_in = "(" for count in q_windows_in_seria: str_for_sql_in += str(count.id) + "," str_for_sql_in = str_for_sql_in[:-1] + ")" # print StringForSqlIN # Получаем данные для таблички Окон по типам квартирах в серии дома # " IFNULL(oknardia_mountdim2apartment.iQuantity, 0) AS iQuantity," \ # tStart2 = time.time() # замер времени q_win_in_apartment_in_seria = Win_MountDim.objects.raw( f"SELECT" f" oknardia_win_mountdim.id," f" oknardia_apartment_type.sNameApartment," f" oknardia_win_mountdim.iWinWidth," f" oknardia_win_mountdim.iWinHight," f" oknardia_apartment_type.id AS id_apart," f" IFNULL(oknardia_mountdim2apartment.iQuantity, 0) AS iQuantity," f" COUNT(oknardia_priceoffer.id) AS NumOffers " f"FROM oknardia_apartment_type" f" INNER JOIN oknardia_win_mountdim" f" LEFT OUTER JOIN oknardia_mountdim2apartment" f" ON oknardia_mountdim2apartment.kMountDim_id = oknardia_win_mountdim.id" f" AND oknardia_mountdim2apartment.kApartment_id = oknardia_apartment_type.id" f" LEFT OUTER JOIN oknardia_priceoffer" f" ON oknardia_priceoffer.kOffer2MountDim_id = oknardia_win_mountdim.id" f" LEFT OUTER JOIN oknardia_ouruser" f" ON oknardia_ouruser.id = oknardia_priceoffer.kOfferFromUser_id " f"WHERE oknardia_apartment_type.kSeria_id = {seria_id} " f"AND oknardia_win_mountdim.id IN {str_for_sql_in} " f"GROUP BY oknardia_apartment_type.id," f" oknardia_apartment_type.sNameApartment," f" oknardia_win_mountdim.id," f" oknardia_mountdim2apartment.iQuantity " f"ORDER BY oknardia_apartment_type.iSort," f" oknardia_win_mountdim.bIsNearDoor DESC," f" oknardia_win_mountdim.bIsDoor DESC," f" oknardia_win_mountdim.iWinWidth," f" oknardia_win_mountdim.iWinHight DESC;") list_win_in_seria = list(q_windows_in_seria) total_column = len(list_win_in_seria) - 1 count_column = 0 min_offer_in_row = 1000000000 table_of_win_in_seria_by_apartmment = [] row_for_table = [] offer_and_merchant_per_win = [ { "WIN_OFFER": 0, "WIN_MERCHANT": 0, "WIN_W": list_win_in_seria[i].iWinWidth, "WIN_H": list_win_in_seria[i].iWinHight, "WIN_ID": list_win_in_seria[i].id } for i in range(total_column + 1)] for count in q_win_in_apartment_in_seria: if count.iQuantity != 0: row_for_table.append({ "WIN_NUM": [chr(65 + count_column)], "WIN_Q": count.iQuantity, "WIN_ID": count.id, "WIN_WIDTH": list_win_in_seria[count_column].iWinWidth, "WIN_HEIGHT": list_win_in_seria[count_column].iWinHight, "WIN_DESCRIPTION": list_win_in_seria[count_column].sDescripion, "WIN_FLAPCFG": list_win_in_seria[count_column].sFlapConfig }) if min_offer_in_row > count.NumOffers: min_offer_in_row = count.NumOffers if offer_and_merchant_per_win[count_column]["WIN_OFFER"] < count.NumOffers: offer_and_merchant_per_win[count_column]["WIN_OFFER"] = count.NumOffers else: row_for_table.append({"WIN_NUM": "—"}) if count_column < total_column: count_column += 1 else: # print row_for_table table_of_win_in_seria_by_apartmment.append({"WIN_IN_APART": row_for_table, "APART_NAME": count.sNameApartment, "APART_ID": count.id_apart, "NUM_OFFERS": min_offer_in_row}) count_column = 0 min_offer_in_row = 10000 row_for_table = [] # print(table_of_win_in_seria_by_apartmment) # print(f"==============>{float(time.time()-tStart2)}<==============") # print NumOffersPerColumn, NumMerchantPerColumn to_template.update({"WIN_OFFER_AND_MERCHANT": offer_and_merchant_per_win, "TABLE_OF_WINDOWS": table_of_win_in_seria_by_apartmment}) # для "тяжелого шаблона" получаем навигацию страницы, данные для карты и графика ввода в эксплуатацию if is_hard_template: # если вызывается "тяжелый" шаблон, то нужно подготовить тяжелые данные для построения навигации seria_id, for_seria_nav = seria_nav(seria_id) to_template.update(for_seria_nav) # данные для навигации по сериям to_template.update(seria_info_year(seria_id)) # данные для графика ввода зданий серии в эксплуатацию to_template.update(seria_info_geo_code(seria_id)) # данные для карты # т.к. обрабатывается "тяжелый шаблон" надо создать "легкий шаблон" # для его использования в будущем. string_prerender = render_to_string("seria_info/all_seria_info_pre_light.html", to_template) file = open(light_template_w_path, 'w') # file.write(AA.encode('utf-8')) file.write(string_prerender) file.close() else: seria_name = Seria_Info.objects.get(id=seria_id).sName to_template.update({'THIS_SERIA_NAME': seria_name}) # to_template.update({'LOG_VISIT': GetLastAllUserVisitSeriaList(SeriaName), # 'ticks': float(time.time()-time_start)}) to_template.update({ # получаем последние визиты клиента через куки '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.time() - time_start) }) return render(request, light_template, to_template) def seria_nav(seria_id: int = 12) -> (int, dict): """ Возвращает корректный seria_id и кортеж для построения навигации по сериям дома :param seria_id: id серии :return: """ q_seria = Seria_Info.objects.raw( 'SELECT oknardia_seria_info.id,' ' oknardia_seria_info.sName,' ' oknardia_seria_info.sSeriaDescription,' ' oknardia_seria_info.kRoot_id,' ' oknardia_seria_info.kParent_id ' 'FROM oknardia_seria_info ' 'WHERE oknardia_seria_info.id = oknardia_seria_info.kRoot_id ' 'ORDER BY oknardia_seria_info.sName;') error_seria = True for count_seria in q_seria: if count_seria.id == int(seria_id): error_seria = False break if error_seria: # Ошибочный seria_id. Такой базовой серии нет и надо ее найти. try: query = Seria_Info.objects.get(id=int(seria_id)) if query.kRoot_id is not None: # базовая серия прописана в kRoot_id seria_id = query.kRoot_id else: # == корневой нет # == ищем методом наименьших расстояний" min_min = 100000000 min_id = seria_id for count_seria in q_seria: if math.fabs(int(seria_id) - count_seria.id) < min_min: min_min = math.fabs(int(seria_id) - count_seria.id) min_id = count_seria.id seria_id = min_id except ObjectDoesNotExist: seria_id = q_seria[0].id # print(f"-->{seria_id}<--") return all_seria_nav(seria_id, q_seria) def all_seria_nav(seria_id: int, q_seria) -> (int, dict): seria_nav_dim = [] this_return = {} for count_seria in q_seria: one_seria = {} one_seria.update({"SERIA_R": count_seria.sName, "ID2URL": count_seria.id}) if count_seria.id == seria_id: this_return.update({"THIS_SERIA_NAME": count_seria.sName, "THIS_SERIA_DESCRIPTION": count_seria.sSeriaDescription}) one_seria.update({"SERIA_L": ""}) else: one_seria.update({"SERIA_L": pytils.translit.slugify(count_seria.sName)}) seria_nav_dim.append(one_seria) this_return.update({"SERIA_NAV_DIM": seria_nav_dim}) return seria_id, this_return def seria_info_year(seria_id: int = 12) -> dict: """ Возвращает данные для графика распределения сдачи серии в эксплуатацию :param seria_id: int -- id серии для которой нужно получить данные :return: dict -- данные для графика распределения сдачи серии в эксплуатацию типа: {"DATA4GRAPH": [{'YEAR': 1997, 'NUMS': 1, 'CLRS': '99'}, {'YEAR': 1998, 'NUMS': 15, 'CLRS': 'сс'}, {'YEAR': 1998, 'NUMS': 10, 'CLRS': 'a9'} ] } """ seria_in_years = [] query = Seria_Info.objects.raw( f"SELECT oknardia_building_info.iCommissioning_year as id," f" COUNT(oknardia_building_info.iCommissioning_year) AS NumInYear " f"FROM oknardia_building_info" f" INNER JOIN oknardia_seria_info" f" ON oknardia_building_info.kSeria_Link_id = oknardia_seria_info.id " f"WHERE oknardia_seria_info.kRoot_id = {seria_id} " f"GROUP BY oknardia_building_info.iCommissioning_year;" ) max_per_year = 0 graph_color_light = 0xCC # самый светлый цвет на графике (максимальное значение) graph_color_dark = 0x99 # самый темный цвет на графике (минимальное значение) for YearCount in query: if int(YearCount.NumInYear) > max_per_year: max_per_year = int(YearCount.NumInYear) # print("max", MaxPerYear) for YearCount in query: data_of_year = {} try: data_of_year.update({ "YEAR": int(YearCount.id), "NUMS": YearCount.NumInYear, "CLRS": str(hex(int(graph_color_dark + YearCount.NumInYear * ( graph_color_light - graph_color_dark) / max_per_year)))[2:] }) except ValueError: continue seria_in_years.append(data_of_year) # print(seria_in_years) return {"DATA4GRAPH": seria_in_years} def seria_info_geo_code(seria_id: str = '12') -> dict: """ Возвращает массив геокоординат зданий одной серии :param seria_id: str -- id серии для которой нужно получить данные :return: dict -- массив геокоординат зданий серии """ data_return = {} seria_to_geo = [] municipal_m2 = 0 # муниципальный фонд (кв.м) residential_m2 = 0 # жилой фонд (кв.м) government_m2 = 0 # государственные учреждения занимают (кв.м.) residents = 0 # количество жильцов apartments = 0 # число квартиры accounts = 0 # количество лицевых счетов condition_max = 0 # максимальное значение показателя состояния здания condition_min = 1000000 # минимальное значение показателя состояния здания query = Building_Info.objects.raw( f"SELECT" f" oknardia_building_info.id," f" oknardia_seria_info.kRoot_id as SerId," f" oknardia_building_info.sAddress," f" oknardia_building_info.fResidential_Area," f" oknardia_building_info.fMunicipal_Area," f" oknardia_building_info.fGovernment_Area," f" oknardia_building_info.iNum_Residents," f" oknardia_building_info.iNum_Apartments," f" oknardia_building_info.iNum_Accounts," f" oknardia_building_info.fCondition_House," f" oknardia_building_info.fGeoCode_Latitude," f" oknardia_building_info.fGeoCode_Longitude " f"FROM oknardia_building_info" f" INNER JOIN oknardia_seria_info" f" ON oknardia_building_info.kSeria_Link_id = oknardia_seria_info.id " f"WHERE oknardia_seria_info.kRoot_id IN ({seria_id});" ) for count in query: if int(count.fGeoCode_Latitude) != 0 and int(count.fGeoCode_Longitude) != 0: seria_to_geo.append({"LATITUDE": count.fGeoCode_Latitude, "LONGITUDE": count.fGeoCode_Longitude, "ADDR_ID": count.id, "ADDR_LAT": pytils.translit.slugify(count.sAddress), "ADDR_RUS": count.sAddress, "SER_ID": count.SerId }) if count.fMunicipal_Area > 0: municipal_m2 += count.fMunicipal_Area if count.fResidential_Area > 0: residential_m2 += count.fResidential_Area if count.fGovernment_Area > 0: government_m2 += count.fGovernment_Area if count.iNum_Residents > 0: residents += count.iNum_Residents if count.iNum_Residents > 0: residents += count.iNum_Residents if count.iNum_Apartments > 0: apartments += count.iNum_Apartments if count.iNum_Accounts > 0: accounts += count.iNum_Accounts if count.fCondition_House > 0: if count.fCondition_House > condition_max: condition_max = count.fCondition_House if count.fCondition_House < condition_min: condition_min = count.fCondition_House data_return.update({"DATA4GEO": seria_to_geo, "MUNICIPAL_M2": municipal_m2, "RESIDENTIAL_M2": residential_m2, "GOVERNMENT_M2": government_m2, "RESIDENTS": residents, "APARTMENTS": apartments, "ACCOUNTS": accounts, "CONDITION_MAX": condition_max, "CONDITION_MIN": condition_min}) # print(seria_to_geo) return data_return