From 988f8f1e07e90ba7837ae7a74570c3c5bf93275b Mon Sep 17 00:00:00 2001 From: erjemin Date: Sat, 10 Dec 2022 15:49:07 +0300 Subject: [PATCH] =?UTF-8?q?=D0=92=D1=8C=D1=8E=D1=88=D0=BA=D0=B0:=20"=D0=9A?= =?UTF-8?q?=D0=B0=D1=82=D0=B0=D0=BB=D0=BE=D0=B3=20/=20=D0=9E=D0=BA=D0=BE?= =?UTF-8?q?=D0=BD=D0=BD=D1=8B=D0=B5=20=D0=BF=D1=80=D0=BE=D1=84=D0=B8=D0=BB?= =?UTF-8?q?=D0=B8=20/=20=D0=9F=D1=80=D0=BE=D0=B8=D0=B7=D0=B2=D0=BE=D0=B4?= =?UTF-8?q?=D0=B8=D1=82=D0=B5=D0=BB=D1=8C=D1=8C"=20--=20=D0=B3=D0=BE=D1=82?= =?UTF-8?q?=D0=BE=D0=B2=D0=BE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- oknardia/oknardia/urls.py | 9 +- .../catalog_of_profiles_manufacture.html | 131 ++++++++++++++ oknardia/web/add_func.py | 6 +- oknardia/web/catalog.py | 164 ++++++++++++++++-- 4 files changed, 290 insertions(+), 20 deletions(-) create mode 100755 oknardia/templates/catalog/catalog_of_profiles_manufacture.html diff --git a/oknardia/oknardia/urls.py b/oknardia/oknardia/urls.py index 2d13580..8c42c23 100644 --- a/oknardia/oknardia/urls.py +++ b/oknardia/oknardia/urls.py @@ -40,7 +40,7 @@ urlpatterns = [ # Ссылка, по которой пользователь может поменять пароль при утере. URL: /USER_%05d/RESTORE:%s re_path(r'^USER_(?P\d{1,8})/RESTORE:(?P\S+)$', user_manager.restore_password), re_path(r'^change_password$', user_manager.change_password), - # ОБРАБОТЧИКИ СПИСКА ПУБЛИКАЦИЙ И САМИХ ПУБЛИКАЦИЙ БЛОГА + # БЛОГ re_path(r'^blog/*$', blog.blog_list), re_path(r'^blog/P(?P\d+)/*$', blog.blog_list_posts), re_path(r'^blogpost/(?P\d+)/(?P\d+)/\S*/*$', blog.blog_post), @@ -51,12 +51,13 @@ urlpatterns = [ re_path(r'^stat_all[/*]$', diagrams.statistic_menu), re_path(r'^stat/rating[/*]$', report2.ratings), re_path(r'^stat/rating/profiles_rank[/*]$', report2.profiles_rating), - # КАТАЛОГ + # --- Каталог re_path(r'^catalog[/*]$', catalog.catalog_root), re_path(r'^catalog/profile[/*]$', catalog.catalog_profile), re_path(r'^catalog/profile/(?P\d+)-(?P\S*)' - r'/(?P\d+)-(?P\S*)[/*]$', - catalog.catalog_profile_model), + r'/(?P\d+)-(?P\S*)[/*]$', catalog.catalog_profile_model), + re_path(r'^catalog/profile/(?P\d+)-(?P\S*)[/*]$', + catalog.catalog_profile_manufacture), ] diff --git a/oknardia/templates/catalog/catalog_of_profiles_manufacture.html b/oknardia/templates/catalog/catalog_of_profiles_manufacture.html new file mode 100755 index 0000000..59ebc80 --- /dev/null +++ b/oknardia/templates/catalog/catalog_of_profiles_manufacture.html @@ -0,0 +1,131 @@ +{% extends "base.html" %} +{% load static %} + +{% block Title %} Каталог :: Оконные профили производства {{ CATALOG_MANUFACT }}{% endblock %} + +{% block Add_Body_Attribute %} style="padding-top:70px;"{% endblock %} + +{% block Description %}Оконные профили {{ CATALOG_MANUFACT }}{% endblock %} + +{% block Keywords %}{{ CATALOG_MANUFACT }}, оконные профили {{ CATALOG_MANUFACT }}, производитель {{ CATALOG_MANUFACT }}, каталог оконных профилей, каталог производителей оконных профилей, каталог профилей, оконные профили, oknardia, окнардия {{ META_KEYWORDS|default:"" }} {% endblock %} + +{% block Date4Meta %}{{ PUB_DAT|date:"c" }}{% endblock %} + +{% block Last4Meta %}{{ PUB_DAT|date:"c" }}{% endblock %} + +{% block Author4Meta %}: Каталог{% endblock %} + +{% block CopyrightAuthor4Meta %}: Каталог{% endblock %} + +{% block Top_Meta1 %} + + {% if IMG_FOR_BLOG %} + {% else %} + {% endif %} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {% endblock %} + +{% block Top_JS4 %} + + {% endblock %} + +{% block Main_Content %} +
+ {# #}
+
+ +

Оконные профили производства {{ CATALOG_MANUFACT }}

+
+
{# #} +
+
+ + + + + {% for i in PROFILES %} + + + + {% endfor %} + +
Марки профилей {{ CATALOG_MANUFACT }}рейтинг
{{ i.PROFILE_NAME }} {% for Star in i.PROFILE_RATING_STARS %}{% if Star == 0 %}{% else %}{% endif %}{% endfor %} {% if i.PROFILE_RATING > -0.1 %}{{ i.PROFILE_RATING|stringformat:".2f" }}{% endif %}
+

Сравнить компонеты рейтинга профилей можно в разделе Ретинги.

{% if not OFFERS_BY_MAUFACTURE == 0 %} +

Доля предложений окон на основе профилей {{ CATALOG_MANUFACT }} в базе «Окнардия»

+
+
Партнёры «Окнардия» использующие профили производства {{ CATALOG_MANUFACT }} в своих предложениях:
+ + {% endif %}
+
{# --- Описание производителя профилей :: начало --- #} +{{ CONTENT|safe|default:"

Извините, описание производителя профилей ещё не готово.
 
Зайдите позже.

" }} + {# --- Описание производителя профилей :: конец --- #}
+ + +
+ {# --- Баннер: НАЧАЛО --- #} +

{% include "ad/bannet-wide.html" %}
+ {# --- Баннер: конец --- #} +
+{% include "report/report_last_user_visit.html" %} +{% include "report/report_log_user_visit.html" %} +
+
{% endblock %} + + diff --git a/oknardia/web/add_func.py b/oknardia/web/add_func.py index 3a1807f..d5a8361 100644 --- a/oknardia/web/add_func.py +++ b/oknardia/web/add_func.py @@ -88,12 +88,12 @@ def get_rating_set_for_stars(rating: float = 0.) -> list: # return distance -def normalize(val: float, val_max: float = 5., val_min: float = 0.) -> float: +def normalize(val: float, val_max: int = 5, val_min: int = 0) -> float: """ Нормализация значения :param val: float -- значение которое надо нормализовать - :param val_max: float -- максимальное значение в нормализуемом диапазоне - :param val_min: float -- минимальное значение в нормализуемом диапазоне + :param val_max: int -- максимальное значение в нормализуемом диапазоне + :param val_min: int -- минимальное значение в нормализуемом диапазоне :return: float: float -- нормализованное значение """ return float(val - val_min) / float(val_max - val_min) diff --git a/oknardia/web/catalog.py b/oknardia/web/catalog.py index c09abcb..ae49cc9 100644 --- a/oknardia/web/catalog.py +++ b/oknardia/web/catalog.py @@ -1,4 +1,5 @@ # -*- coding: utf-8 -*- +from django.core.exceptions import ObjectDoesNotExist from django.shortcuts import render, redirect from django.http import HttpRequest, HttpResponse from django.utils import timezone @@ -9,6 +10,7 @@ from web.add_func import normalize, get_rating_set_for_stars import time import json import random +import re import pytils @@ -21,13 +23,12 @@ def catalog_root(request: HttpRequest) -> HttpResponse: :return response: HttpResponse -- исходящий http-ответ """ time_start = time.time() - template = "catalog/catalog_root.html" # шаблон # получаем из 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, template, to_template) + response = render(request, "catalog/catalog_root.html", to_template) return response @@ -38,7 +39,6 @@ def catalog_profile(request: HttpRequest) -> HttpResponse: :param request: HttpRequest -- входящий http-запрос :return response: HttpResponse -- исходящий http-ответ """ - template = "catalog/catalog_of_profiles.html" # шаблон time_start = time.time() q_profile = PVCprofiles.objects.raw('SELECT' ' oknardia_pvcprofiles.id,' @@ -112,7 +112,7 @@ def catalog_profile(request: HttpRequest) -> HttpResponse: 'LOG_VISIT': get_last_all_user_visit_list(), 'ticks': float(time.time() - time_start) }) - return render(request, template, to_template) + return render(request, "catalog/catalog_of_profiles.html", to_template) def catalog_profile_model(request: HttpRequest, manufacture_id: int, manufacture_name: str, @@ -128,7 +128,6 @@ def catalog_profile_model(request: HttpRequest, manufacture_id: int, manufacture :return response: HttpResponse -- исходящий http-ответ """ time_start = time.time() - template = "catalog/catalog_of_profiles_model.html" # шаблон manufacture_id = int(manufacture_id) model_id = int(model_id) q_pvc_by_id = PVCprofiles.objects.get(id=model_id) @@ -143,12 +142,12 @@ def catalog_profile_model(request: HttpRequest, manufacture_id: int, manufacture "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: - getted_json = json.loads(q_pvc_by_id.sProfileDescription) + got_json = json.loads(q_pvc_by_id.sProfileDescription) # раскрашиваем кружочки рейтинга напротив характеристик профиля - if KEY_RATING in getted_json: + if KEY_RATING in got_json: # RatingReal = True # Рейтинг реальный (профиль представлен в ценовых предложениях) # кружочки зелёные - rating = getted_json[KEY_RATING] + 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) @@ -165,10 +164,10 @@ def catalog_profile_model(request: HttpRequest, manufacture_id: int, manufacture 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 getted_json: + elif KEY_RATING_VIRTUAL in got_json: # RatingReal = False # Рейтинг виртуальный (профиль представлен в ценовых предложениях) # кружочки серые - rating = getted_json[KEY_RATING_VIRTUAL] + 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) @@ -187,8 +186,8 @@ def catalog_profile_model(request: HttpRequest, manufacture_id: int, manufacture to_template.update({"RANK_PVCP_HEIGHT_COLOR": f"{color},{color},{color}"}) else: pass - if KEY_HTML in getted_json: - to_template.update({"EXTRA_INFO": getted_json[KEY_HTML]}) + if KEY_HTML in got_json: + to_template.update({"EXTRA_INFO": got_json[KEY_HTML]}) except (TypeError, ValueError, KeyError): pass list_other = [] @@ -282,4 +281,143 @@ def catalog_profile_model(request: HttpRequest, manufacture_id: int, manufacture 'LOG_VISIT': get_last_all_user_visit_list(), 'ticks': float(time.time()-time_start) }) - return render(request, template, to_template) + 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)