Вьюшка: "Каталог / Типовые серии зданий / Информация по серии" -- готово
This commit is contained in:
@@ -28,10 +28,10 @@ SECRET_KEY = 'django-insecure-pd&1$j6z*1w#(j*16b+(@@#&2)+@x^^ot4)zqt-e67*1+$^qch
|
|||||||
# SECURITY WARNING: don't run with debug turned on in production!
|
# SECURITY WARNING: don't run with debug turned on in production!
|
||||||
# ПРЕДУПРЕЖДЕНИЕ БЕЗОПАСНОСТИ: не работайте в режиме DEBUG в продашене!
|
# ПРЕДУПРЕЖДЕНИЕ БЕЗОПАСНОСТИ: не работайте в режиме DEBUG в продашене!
|
||||||
if socket.gethostname() in MY_HOST_DEV:
|
if socket.gethostname() in MY_HOST_DEV:
|
||||||
DEBUG = True
|
DEBUG = TEMPLATE_DEBUG = True
|
||||||
else:
|
else:
|
||||||
# Все остальные хосты (подразумевается продакшн)
|
# Все остальные хосты (подразумевается продакшн)
|
||||||
DEBUG = False
|
DEBUG = TEMPLATE_DEBUG = False
|
||||||
|
|
||||||
ALLOWED_HOSTS = MY_ALLOWED_HOSTS
|
ALLOWED_HOSTS = MY_ALLOWED_HOSTS
|
||||||
|
|
||||||
@@ -181,11 +181,11 @@ OFFER_PER_FRAME = 5
|
|||||||
OFFER_PER_FRAME_FOR_ONE_FLAP = 10
|
OFFER_PER_FRAME_FOR_ONE_FLAP = 10
|
||||||
# папка для хранения изображений
|
# папка для хранения изображений
|
||||||
PATH_FOR_IMG = "img"
|
PATH_FOR_IMG = "img"
|
||||||
PATH_FOR_IMG_BLOG = u"img_for_blog/"
|
PATH_FOR_IMG_BLOG = "img_for_blog/"
|
||||||
PATH_FOR_IMG_AVATAR = u"img_avatar/"
|
PATH_FOR_IMG_AVATAR = "img_avatar/"
|
||||||
PATH_FOR_IMG_LOGOS = u"logos_img/"
|
PATH_FOR_IMG_LOGOS = "logos_img/"
|
||||||
PATH_FOR_IMG_APARTMENT = u"img_apart/"
|
PATH_FOR_IMG_APARTMENT = "img_apart/"
|
||||||
PATH_FOR_IMG_SERIA = u"img_seria/"
|
PATH_FOR_IMG_SERIA = "img_seria/"
|
||||||
|
|
||||||
# папка для хранения мини-картинок со схемами открывания внутри PATH_FOR_IMG
|
# папка для хранения мини-картинок со схемами открывания внутри PATH_FOR_IMG
|
||||||
PATH_FOR_BIGIMGFLAPCONFIG = "_flap.cfg"
|
PATH_FOR_BIGIMGFLAPCONFIG = "_flap.cfg"
|
||||||
@@ -195,7 +195,7 @@ PATH_FOR_JS = "js"
|
|||||||
PATH_FOR_JS_MAP = "js/4maps"
|
PATH_FOR_JS_MAP = "js/4maps"
|
||||||
SUFFIX_FOR_JS_MAP = "_seria_on_map.js"
|
SUFFIX_FOR_JS_MAP = "_seria_on_map.js"
|
||||||
SUFFIX_FOR_MINI_JS_MAP = "_seria_on_map.mini.js"
|
SUFFIX_FOR_MINI_JS_MAP = "_seria_on_map.mini.js"
|
||||||
PATH_FOR_SERIA_INFO_HTML_INCLUDE = "SeriaInfo/prepared/"
|
PATH_FOR_SERIA_INFO_HTML_INCLUDE = "seria_info/prepared/"
|
||||||
|
|
||||||
# переменные
|
# переменные
|
||||||
# высота картинки
|
# высота картинки
|
||||||
|
|||||||
@@ -61,6 +61,7 @@ urlpatterns = [
|
|||||||
catalog.catalog_profile_manufacture),
|
catalog.catalog_profile_manufacture),
|
||||||
# --- --- Каталог серий типового строительства
|
# --- --- Каталог серий типового строительства
|
||||||
re_path(r'^catalog/seria[/*]$', catalog.catalog_seria),
|
re_path(r'^catalog/seria[/*]$', catalog.catalog_seria),
|
||||||
|
re_path(r'^catalog/seria/(?P<seria_name_translit>[^/]*)/all(?P<seria_id>\d+)[/*]$', catalog.catalog_seria_info),
|
||||||
|
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|||||||
18
oknardia/templates/report/show_big_flap_pictures.html
Executable file
18
oknardia/templates/report/show_big_flap_pictures.html
Executable file
@@ -0,0 +1,18 @@
|
|||||||
|
{# Отрисовка больших картинок с проемами и схамаи открывания #}{% load static %}{% if WIN_DIM %}
|
||||||
|
{% for I_WIN_DIM in FLAP_DIM %}
|
||||||
|
<div class="win_discr pull-left" id="flap{{ forloop.counter0 }}">
|
||||||
|
<div><img src="{% static I_WIN_DIM.url2img %}" alt="{{ I_WIN_DIM.sDescription }}. Размер {{ I_WIN_DIM.iWinWidth|stringformat:".0f" }}0x{{ I_WIN_DIM.iWinHight|stringformat:".0f" }}0 (Ш х В, мм.). Типовая схема открывания." title="{{ I_WIN_DIM.sDescription }}. Размер {{ I_WIN_DIM.iWinWidth|stringformat:".0f" }}0x{{ I_WIN_DIM.iWinHight|stringformat:".0f" }}0 (Ш х В, мм.). Типовая схема открывания." itemprop="image" /></div>
|
||||||
|
<div class="caption" style="width:{{ I_WIN_DIM.W }}px;min-width:13ex;">
|
||||||
|
<nobr>{{ I_WIN_DIM.iWinWidth|stringformat:".0f" }}0×{{ I_WIN_DIM.iWinHight|stringformat:".0f" }}0 мм.</nobr><br />{% if not I_WIN_DIM.iQuantity == 0 %}
|
||||||
|
<nobr><b>{{ I_WIN_DIM.iQuantity }} шт.</b>{% for I_II in I_WIN_DIM.qStr %}<span class="color-bullet" style="background-image:url('{% static 'img/svg/mark' %}{{ I_II }}.svg');"></span>{% endfor %}</nobr><br />{% endif %}
|
||||||
|
{{ I_WIN_DIM.sDescription }}{% if not I_WIN_DIM.iQuantity == 0 %}<br />
|
||||||
|
<a href="/tsena-odnogo-okna/{{ I_WIN_DIM.iWinWidth|stringformat:".0f" }}0x{{ I_WIN_DIM.iWinHight|stringformat:".0f" }}0mm/tip{{ I_WIN_DIM.id }}">цены только этого типового окна</a>{% endif %}
|
||||||
|
</div>
|
||||||
|
</div>{% endfor %}{% comment %}
|
||||||
|
<script type="text/javascript">
|
||||||
|
$(document).ready(function(){
|
||||||
|
var maxHeight = 0;
|
||||||
|
{% for I_WIN_DIM in FLAP_DIM %}if (maxHeight < $('#flap{{ forloop.counter0 }}').height()) maxHeight = $('#flap{{ forloop.counter0 }}').height();
|
||||||
|
{% endfor %}{% for I_WIN_DIM in FLAP_DIM %}$('#flap{{ forloop.counter0 }}').height(maxHeight-240);{% endfor %}
|
||||||
|
});
|
||||||
|
</script>{% endcomment %}{% else %}<h1>Нет данных о проемах и рекомендованных схемах открывания окон</h1>{% endif %}
|
||||||
120
oknardia/templates/seria_info/all_seria_info_pre_light.html
Executable file
120
oknardia/templates/seria_info/all_seria_info_pre_light.html
Executable file
@@ -0,0 +1,120 @@
|
|||||||
|
{% extends "base.html" %}
|
||||||
|
{% load static %}
|
||||||
|
{% load filters %}
|
||||||
|
{% load humanize %}
|
||||||
|
|
||||||
|
{% block Title %}серия {{ THIS_SERIA_NAME }} — типовые проёмы, размеры окон, схемы открывания, планировки, здания на карте, история и статистика{% endblock %}
|
||||||
|
|
||||||
|
{% block Add_Body_Attribute %} style="padding-top:70px;"{% endblock %}
|
||||||
|
|
||||||
|
{% block Date4Meta %}{{ META_DATA_PUBLISH|date:"c" }}{% endblock %}
|
||||||
|
|
||||||
|
{% block Last4Meta %}{{ META_DATA_PUBLISH|date:"c" }}{% endblock %}
|
||||||
|
|
||||||
|
{% block Description %}Информация по зданиям серии {{ THIS_SERIA_NAME }} и установке окон в них{% endblock %}
|
||||||
|
|
||||||
|
{% block Keywords %}серии {{ THIS_SERIA_NAME }}, серия {{ THIS_SERIA_NAME }}, проект {{ THIS_SERIA_NAME }}, года простойки, размеры окон, размеры проемов, оконные проемы, {{ THIS_SERIA_NAME }} на карте, установка окон, цены на пластиковые окна{% endblock %}
|
||||||
|
|
||||||
|
{% block Top_JS1 %}
|
||||||
|
<script type="text/javascript">
|
||||||
|
$(window).load(function () {
|
||||||
|
var images = $('.half');
|
||||||
|
images.each(function (i) {
|
||||||
|
$(this).width($(this).width() / 2);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>{% endblock %}
|
||||||
|
|
||||||
|
{% block Main_Content %}<div class="container-fluid">
|
||||||
|
{# <!--- Хлебные крошки: НАЧАЛО --> #}<div class="row">
|
||||||
|
<div class="col-md-11 col-xs-12">
|
||||||
|
<ol class="breadcrumb">
|
||||||
|
<li><a href="/">Главная</a></li>
|
||||||
|
<li><a href="/catalog/">Каталог</a></li>
|
||||||
|
<li><a href="/catalog/seria/">Типовые серии домов</a></li>
|
||||||
|
<li>Серия {{ THIS_SERIA_NAME }}</li>
|
||||||
|
</ol>
|
||||||
|
<h1>СЕРИЯ {{ THIS_SERIA_NAME }}</h1>
|
||||||
|
</div>
|
||||||
|
</div>{# <!--- Хлебные крошки: КОНЕЦ ---> #}
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-12">{{ THIS_SERIA_DESCRIPTION|safe }}</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-lg-10">
|
||||||
|
<h2 class="header">Окна <nobr>в серии {{ THIS_SERIA_NAME }}</nobr>: типовые размеры и схемы открывания</h2>
|
||||||
|
</div>
|
||||||
|
<div class="col-lg-12" style="padding:1em 0 0 0;margin-left:-1em">
|
||||||
|
{% include 'report/show_big_flap_pictures.html' %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-lg-8 col-xs-12 col-md-offset-1">
|
||||||
|
<h3 class="header">Оконные проёмы в типовых квартирах <nobr>серии {{ THIS_SERIA_NAME }}</nobr></h3>
|
||||||
|
</div>
|
||||||
|
<div class="col-lg-8 col-xs-12 col-md-offset-1">
|
||||||
|
<!--- прешаблон начало ---><table style="padding:2px;">{% templatetag openblock %} for row in TABLE_OF_WINDOWS {% templatetag closeblock %}
|
||||||
|
<tr class="tr2">
|
||||||
|
<td>{% templatetag openvariable %} row.APART_NAME|safe {% templatetag closevariable %}</td>{% templatetag openblock %} for col in row.WIN_IN_APART {% templatetag closeblock %}
|
||||||
|
<td class="cntr">{% templatetag openblock %} if col.WIN_ID {% templatetag closeblock %}<nobr title="{% templatetag openvariable %} col.WIN_Q {% templatetag closevariable %} × {% templatetag openvariable %} col.WIN_DESCRIPTION {% templatetag closevariable %}: {% templatetag openvariable %} col.WIN_WIDTH {% templatetag closevariable %}шт.: {% templatetag openvariable %} col.WIN_HEIGHT {% templatetag closevariable %} (Ш×В, см.). Схема открывания: {% templatetag openvariable %} col.WIN_FLAPCFG {% templatetag closevariable %}">{% templatetag openblock %} for I_II in col.WIN_NUM {% templatetag closeblock %}<span style="background-image:url('{% static 'img/svg/mark' %}{% templatetag openvariable %} I_II {% templatetag closevariable %}.svg');"> </span>{% templatetag openblock %} endfor {% templatetag closeblock %}</nobr>{% templatetag openblock %} else {% templatetag closeblock %}—{% templatetag openblock %} endif {% templatetag closeblock %}</td>{% templatetag openblock %} endfor {% templatetag closeblock %}
|
||||||
|
<td style="background:#f9f9f9;"><a href="#{% templatetag openvariable %} row.APART_ID {% templatetag closevariable %}" class="badge" title="Оконных предложений для квартиры: {% templatetag openvariable %} row.NUM_OFFERS {% templatetag closevariable %}"><small class="glyphicon glyphicon-tags" aria-hidden="true"></small> {% templatetag openvariable %} row.NUM_OFFERS {% templatetag closevariable %}</a></td>
|
||||||
|
</tr>{% templatetag openblock %} endfor {% templatetag closeblock %}
|
||||||
|
<tr class="trZ">
|
||||||
|
<td style="font-size: xx-small;vertical-align:text-top">© 2015-{% now "Y" %}, данные: oknardia.ru</td>{% templatetag openblock %} for i in WIN_OFFER_AND_MERCHANT {% templatetag closeblock %}
|
||||||
|
<td class="cntr" style="background:#f9f9f9;"><a href="/tsena-odnogo-okna/{% templatetag openvariable %} i.WIN_W|floatformat:0 {% templatetag closevariable %}0x{% templatetag openvariable %} i.WIN_H|floatformat:0 {% templatetag closevariable %}0mm/tip{% templatetag openvariable %} i.WIN_ID {% templatetag closevariable %}" class="badge" title="Ценовых предложений для окна: {% templatetag openvariable %} i.WIN_OFFER {% templatetag closevariable %}"><small class="glyphicon glyphicon-tags" aria-hidden="true"></small> {% templatetag openvariable %} i.WIN_OFFER {% templatetag closevariable %}</a></td>{% templatetag openblock %} endfor {% templatetag closeblock %}
|
||||||
|
<td></td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
<!--- прешаблон конец ---></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-9"><a name="s_graph"></a>
|
||||||
|
<h2 class="header">Серия {{ THIS_SERIA_NAME }}: ввод в эксплуатацию по годам</h2>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-9 col-md-offset-1" style="height:300px;font-size:large;">
|
||||||
|
{% include 'seria_info/yaer_graph.html' %}
|
||||||
|
</div>
|
||||||
|
<div class="col-md-9 col-md-offset-1">
|
||||||
|
<div style="font-size: xx-small;float: right">© 2015-{% now "Y" %}, данные: oknardia.ru</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-7"><a name="s_map"></a>
|
||||||
|
<h2 class="header">Серия {{ THIS_SERIA_NAME }}: жилой фонд проекта на карте</h2>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-7 col-lg-offset-1">
|
||||||
|
<p><small>Чтобы посмотреть цены на установку и замену окон от партнёров «Окнардия» в своей квартире: найдите дом на карте; кликните на него; перейдите по ссылке «Смотреть коммерческие предложения». При необходимости смените типовую планировку квартиры (на странице ценовой выдачи, справа от изображения типовых проёмов и схем открывания).</small></p>
|
||||||
|
<div style="height:350px;">{% include 'seria_info/geo_map.html' %}</div>
|
||||||
|
<div style="font-size: xx-small;float: right">© 2015-{% now "Y" %}, данные: oknardia.ru</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<diV class="col-md-4">
|
||||||
|
<h3 class="header">Статистика <nobr>серии {{ THIS_SERIA_NAME }}</nobr></h3>
|
||||||
|
<p>Совокупно во всех зданиях типового проекта:</p>
|
||||||
|
<ul>
|
||||||
|
<li><strong>{{ ACCOUNTS|price_format }}</strong> квартир.</li>
|
||||||
|
<li>Проживает <strong>{{ APARTMENTS|price_format }}</strong> семей <small>(<strong>{{ RESIDENTS|price_format }}</strong> человек)</small>.</li>
|
||||||
|
<li><strong>{{ RESIDENTIAL_M2|stringformat:".1f"|price_format }} м²</strong> жилых помещений.</li>
|
||||||
|
<li><strong>{{ MUNICIPAL_M2|stringformat:".1f"|price_format }} м²</strong> — муниципальное жильё.</li>
|
||||||
|
<li><strong>{{ GOVERNMENT_M2|stringformat:".1f"|price_format }} м²</strong> занимают государственные и городские службы, учреждения бытового обслуживания, магазины, офисы и тому подобное.</li>
|
||||||
|
<li>Максимальный износ жилого фонда серии {{ THIS_SERIA_NAME }} — <strong>{{ CONDITION_MAX|stringformat:".2f" }} %</strong>. Минимальный — <strong>{{ CONDITION_MIN|stringformat:".2f" }} %</strong>. </li>
|
||||||
|
</ul>
|
||||||
|
</diV>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-4 col-lg-offset-8" style="margin-top: 1em;">{# <div class="col-md-4"> #}
|
||||||
|
<h5>Информация о других, отличных от {{ THIS_SERIA_NAME }}, типовых сериях в базе «Окнардия», типовых планировках квартир и оконных проёмах в них, а также рекомендации по замене окон:</h5>
|
||||||
|
<div class="href_d">{% include 'seria_info/seria_nav.html' %}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
{% templatetag openblock %}include "report/report_last_user_visit.html" {% templatetag closeblock %}
|
||||||
|
{% templatetag openblock %} include "report/report_log_user_visit.html" {% templatetag closeblock %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
||||||
56
oknardia/templates/seria_info/geo_map.html
Executable file
56
oknardia/templates/seria_info/geo_map.html
Executable file
@@ -0,0 +1,56 @@
|
|||||||
|
{# Скрипт Yandex.Chart для отображения клястеров на карте #}{% load static %}
|
||||||
|
{% block Top_JS5 %}<script src="https://api-maps.yandex.ru/2.1/?lang=ru_RU" type="text/javascript"></script>
|
||||||
|
{% if MAP_JS %}<script src="{% static '' %}{{ MAP_JS }}" charset="utf-8" type="text/javascript"></script>{% else %}<script type="text/javascript">
|
||||||
|
let points = [{% for count in DATA4GEO %}{% if forloop.last %}[{{ count.LONGITUDE|stringformat:"f" }},{{ count.LATITUDE|stringformat:"f" }}]{% else %}[{{ count.LONGITUDE|stringformat:"f" }},{{ count.LATITUDE|stringformat:"f" }}],{% endif %}{% endfor %}];
|
||||||
|
let forURL = [{% for count in DATA4GEO %}{{ count.ADDR_ID }}{# ,rus: '{{ count.ADDR_RUS }}',lat: '{{ count.ADDR_LAT }}' #}{% if not forloop.last %},{% endif %}{% endfor %}];
|
||||||
|
|
||||||
|
|
||||||
|
ymaps.ready(function () {
|
||||||
|
var myMap = new ymaps.Map('SeriaMap', {
|
||||||
|
center: [55.75, 37.57],
|
||||||
|
zoom: 10,
|
||||||
|
behaviors: ['default', 'scrollZoom'],
|
||||||
|
controls: [ 'rulerControl', 'zoomControl', 'geolocationControl', 'fullscreenControl' ]
|
||||||
|
});
|
||||||
|
// Создадим кластеризатор, вызвав функцию-конструктор.
|
||||||
|
clusterer = new ymaps.Clusterer({
|
||||||
|
preset: 'islands#invertedGrayClusterIcons',
|
||||||
|
groupByCoordinates: false,
|
||||||
|
hasHint: false,
|
||||||
|
viewportMargin: 0,
|
||||||
|
zoomMargin: 16,
|
||||||
|
clusterDisableClickZoom: false,
|
||||||
|
gridSize: 80
|
||||||
|
});
|
||||||
|
geoObjects = [];
|
||||||
|
add_str1 = '<a href="/';
|
||||||
|
add_str2 = '/0/">Смотреть коммерческие предложения</a>';
|
||||||
|
add_str3 = '<b>Здание серии {{ THIS_SERIA_NAME }}</b>';
|
||||||
|
// Данные передаются в конструктор метки.
|
||||||
|
for(var i = 0, len = points.length; i < len; i++) {
|
||||||
|
geoObjects[i] = new ymaps.Placemark( points[i],
|
||||||
|
{ // Содержимое иконки, балуна и хинта.
|
||||||
|
balloonContent: add_str1 + forURL[i] + add_str2,
|
||||||
|
hintContent: add_str3
|
||||||
|
},
|
||||||
|
{ preset:'islands#circleIcon',iconColor: 'silver'} );
|
||||||
|
geoObjects[i].events
|
||||||
|
.add('mouseenter', function (e) {
|
||||||
|
e.get('target').options.set('preset', 'islands#yellowCircleIcon');
|
||||||
|
})
|
||||||
|
.add('mouseleave', function (e) {
|
||||||
|
e.get('target').options.set('preset', 'islands#grayCircleIcon');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
// Добавляем метки в кластеризатор.
|
||||||
|
clusterer.add(geoObjects);
|
||||||
|
myMap.geoObjects.add(clusterer);
|
||||||
|
// позиционирование карты так, чтобы на ней были видны все объекты кластера.
|
||||||
|
myMap.setBounds(clusterer.getBounds(), { checkZoomRange: true });
|
||||||
|
});
|
||||||
|
</script>{% endif %}{% endblock %}
|
||||||
|
<div id="SeriaMap" style="height:100%;width:100%;">
|
||||||
|
<noscript>
|
||||||
|
<p>Для отображения картографических данных по серии {{ THIS_SERIA_NAME }} с помощью «Яндекс.Карт» нужно включить поддержку JavaScript.</p>
|
||||||
|
</noscript>
|
||||||
|
</div>
|
||||||
1
oknardia/templates/seria_info/seria_nav.html
Executable file
1
oknardia/templates/seria_info/seria_nav.html
Executable file
@@ -0,0 +1 @@
|
|||||||
|
{# Выводит навигацию по сериям домов #}{% for CountSeria in SERIA_NAV_DIM %}{% if CountSeria.SERIA_L == "" %}<span style="background-color:cornsilk;"><nobr>{{ CountSeria.SERIA_R }}</nobr></span>{% else %}<span><a href="/catalog/seria/{{ CountSeria.SERIA_L }}/all{{ CountSeria.ID2URL }}/"><nobr>{{ CountSeria.SERIA_R }}</nobr></a></span>{% endif %}{% endfor %}
|
||||||
58
oknardia/templates/seria_info/yaer_graph.html
Executable file
58
oknardia/templates/seria_info/yaer_graph.html
Executable file
@@ -0,0 +1,58 @@
|
|||||||
|
{# Скрипт Google.Chart для рисования графика #}{% block Top_JS3 %}
|
||||||
|
<script type="text/javascript" src="https://www.google.com/jsapi" type="text/javascript"></script>{# <script type="text/javascript" src="https://www.gstatic.com/charts/loader.js" type="text/javascript"></script> #}
|
||||||
|
<script type="text/javascript">
|
||||||
|
// google.charts.load('current', {'packages':['bar']});
|
||||||
|
// google.charts.setOnLoadCallback(drawChart);
|
||||||
|
google.load("visualization", "1", {packages:["corechart"]});
|
||||||
|
google.setOnLoadCallback(drawChart);
|
||||||
|
function drawChart() {
|
||||||
|
let data = google.visualization.arrayToDataTable([
|
||||||
|
["Год", "Введено в эксплуатацию", {role:'style'}],{% for row in DATA4GRAPH %}
|
||||||
|
["{{ row.YEAR }}",{{ row.NUMS }},"color: #99{{ row.CLRS }}99"]{% if not forloop.last %},{% endif %}{% endfor %}
|
||||||
|
]);
|
||||||
|
let view = new google.visualization.DataView(data);
|
||||||
|
view.setColumns([0, 1,
|
||||||
|
{ calc: "stringify",
|
||||||
|
sourceColumn: 1,
|
||||||
|
type: "string",
|
||||||
|
role: "annotation" },
|
||||||
|
2
|
||||||
|
]);
|
||||||
|
let options = {
|
||||||
|
animation:{
|
||||||
|
duration: 1500,
|
||||||
|
easing: 'in',
|
||||||
|
startup: true
|
||||||
|
},
|
||||||
|
backgroundColor: "#EEEEEE",
|
||||||
|
bar: {groupWidth: "76.4%"},
|
||||||
|
chartArea: {left: "2%", top: "5%", width: '96%', height: '85%'},
|
||||||
|
dataOpacity: 0.76,
|
||||||
|
explorer:{
|
||||||
|
maxZoomIn: 0.20,
|
||||||
|
maxZoomOut: 32 },
|
||||||
|
vAxis: {
|
||||||
|
baselineColor:'grey',
|
||||||
|
gridlines:{color: 'silver', count: 7},
|
||||||
|
minorGridlines:{color: '#dddddd', count: 3},
|
||||||
|
textPosition: 'in',
|
||||||
|
textStyle: {fontSize: 10}
|
||||||
|
},
|
||||||
|
hAxis: { textStyle: {fontSize: 10} },
|
||||||
|
isStacked: true,
|
||||||
|
tooltip: {
|
||||||
|
textStyle:{color: 'grey', fontSize: 10 },
|
||||||
|
trigger: 'selection'
|
||||||
|
},
|
||||||
|
annotations: {textStyle: { fontSize: 8, bold: true, color: 'black', opacity: 0.8 }},
|
||||||
|
legend: { position: "none" }
|
||||||
|
};
|
||||||
|
let chart = new google.visualization.ColumnChart(document.getElementById("graph"));
|
||||||
|
chart.draw(data, options);
|
||||||
|
}
|
||||||
|
</script>{% endblock %}
|
||||||
|
<div id="graph" style="width:100%;height:100%">
|
||||||
|
<p>Для отображения гистограммы ввода в эксплуатацию зданий серии {{ THIS_SERIA_NAME }} нужна поддержка SVG.</p>
|
||||||
|
<noscript>
|
||||||
|
<p>Для визуализации отображения картографической информации с помощью Google.Charts нужно включить поддержку JavaScript.</p>
|
||||||
|
</noscript></div>
|
||||||
@@ -1,7 +1,10 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
__author__ = 'Sergei Erjemin'
|
__author__ = 'Sergei Erjemin'
|
||||||
# from transliterate import translit
|
# from transliterate import translit
|
||||||
|
from PIL import Image, ImageDraw
|
||||||
from oknardia.settings import *
|
from oknardia.settings import *
|
||||||
|
|
||||||
|
import os
|
||||||
import re
|
import re
|
||||||
import math
|
import math
|
||||||
|
|
||||||
@@ -97,3 +100,298 @@ def normalize(val: float, val_max: int = 5, val_min: int = 0) -> float:
|
|||||||
:return: float: float -- нормализованное значение
|
:return: float: float -- нормализованное значение
|
||||||
"""
|
"""
|
||||||
return float(val - val_min) / float(val_max - val_min)
|
return float(val - val_min) / float(val_max - val_min)
|
||||||
|
|
||||||
|
|
||||||
|
def get_flaps_for_big_pictures(query_set) -> dict:
|
||||||
|
""" Возвращает словарь с размерами картинок для больших картинок.
|
||||||
|
|
||||||
|
:param query_set: QuerySet -- QuerySet с объектами
|
||||||
|
:return: dict: dict -- словарь с размерами картинок для больших картинок
|
||||||
|
"""
|
||||||
|
result = {}
|
||||||
|
mount_max_h = 0 # максимальная высота оконного проема в квартире
|
||||||
|
door_h = 0 # высота двери
|
||||||
|
for i in query_set: # найдём максимальную высоту проёма окна и двери
|
||||||
|
if i.iWinHight >= mount_max_h:
|
||||||
|
mount_max_h = i.iWinHight
|
||||||
|
if i.bIsDoor >= door_h:
|
||||||
|
door_h = i.iWinHight
|
||||||
|
# Проверяем есть ли папка для хранения картинки конфигурации проема и схемы открывания для данной серии.
|
||||||
|
if not os.path.exists(f"{STATIC_BASE_PATH}/{PATH_FOR_IMG}/{PATH_FOR_BIGIMGFLAPCONFIG}"):
|
||||||
|
# создаем такую папку если ее нет
|
||||||
|
os.makedirs(f"{STATIC_BASE_PATH}/{PATH_FOR_IMG}/{PATH_FOR_BIGIMGFLAPCONFIG}")
|
||||||
|
flaps_dim = [] # список словарей, через который будут передаваться данные в шаблон
|
||||||
|
mount_bulk = 0 # размещение дверной перемычки
|
||||||
|
i_through = -1
|
||||||
|
for i in query_set:
|
||||||
|
img_file_name = "%03dx%03dH%03d" % (i.iWinWidth, i.iWinHight, mount_max_h)
|
||||||
|
# img_file_name = f"{i.iWinWidth:03d}x{i.iWinHight:03d}H{mount_max_h:03d}"
|
||||||
|
if i.bIsDoor:
|
||||||
|
img_file_name += u"D" # добавляем букву D если это дверь
|
||||||
|
else:
|
||||||
|
img_file_name += u"W" # добавляем букву W если это окно
|
||||||
|
if i.bIsNearDoor:
|
||||||
|
img_file_name += u"N" # добавляем букву N если это окно рядом с дверью
|
||||||
|
mount_bulk = i.iWinHight # размещение дверной перемычки
|
||||||
|
else:
|
||||||
|
img_file_name += u"-" # добавляем символ отдельное окно (не рядом с дверью)
|
||||||
|
# маскируем символы схемы открывания, которые не допустимы в названии файлов
|
||||||
|
img_file_name += i.sFlapConfig
|
||||||
|
img_file_name = img_file_name.replace(">", "G")
|
||||||
|
img_file_name = img_file_name.replace("<", "L")
|
||||||
|
img_file_name = img_file_name.replace("[", "(")
|
||||||
|
img_file_name = img_file_name.replace("]", ")")
|
||||||
|
img_file_name = img_file_name.replace("|", "I")
|
||||||
|
img_file_name = f"{PATH_FOR_BIGIMGFLAPCONFIG}/{img_file_name}.png"
|
||||||
|
# проверяем, есть ли файл с нужной картинкой схемам открывания?
|
||||||
|
if not os.path.isfile(f"{STATIC_BASE_PATH}/{PATH_FOR_IMG}/{img_file_name}"):
|
||||||
|
# картинки нет, вызываем функцию для ее создания
|
||||||
|
make_big_img_win_flap(f"{STATIC_BASE_PATH}/{PATH_FOR_IMG}/{img_file_name}", i.iWinWidth, i.iWinHight,
|
||||||
|
i.bIsDoor, i.sFlapConfig, mount_max_h, mount_bulk, door_h)
|
||||||
|
# чтобы получить разноцветные маркеры меток количества проемов
|
||||||
|
# получаем последовательность тип: AB, CD, E, FG, H
|
||||||
|
q_local = ""
|
||||||
|
for i_local in range(0, i.iQuantity):
|
||||||
|
i_through += 1
|
||||||
|
q_local += chr(65 + i_through) # 65 -- код "A"
|
||||||
|
flaps_dim.append({
|
||||||
|
'url2img': f"img/{img_file_name}",
|
||||||
|
'iWinWidth': i.iWinWidth,
|
||||||
|
'iWinHight': i.iWinHight,
|
||||||
|
'iWinDepth': i.iWinDepth,
|
||||||
|
'iQuantity': i.iQuantity,
|
||||||
|
'sDescription': i.sDescripion,
|
||||||
|
'id': i.id,
|
||||||
|
'qStr': q_local,
|
||||||
|
'W': int((i.iWinWidth*250) / mount_max_h)
|
||||||
|
})
|
||||||
|
result.update({'FLAP_DIM': flaps_dim,
|
||||||
|
'WIN_DIM': query_set})
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
def make_big_img_win_flap(img_file_name_with_path: str, width: int, height: int, is_door: bool,
|
||||||
|
flap_config: str, height_max: int, height_mount_bulk: int, height_door: int) -> None:
|
||||||
|
"""
|
||||||
|
Функция создает png-картинку схемы открывания окна или двери
|
||||||
|
:param img_file_name_with_path: str -- полное имя файла картинки
|
||||||
|
:param width: int -- ширина окна или двери (см.)
|
||||||
|
:param height: int -- высота окна или двери
|
||||||
|
:param is_door: bool -- True - дверь, False - окно
|
||||||
|
:param flap_config: str -- схема открывания
|
||||||
|
:param height_max: int -- максимальная высота окна или двери (высота картинки)
|
||||||
|
:param height_mount_bulk: int -- высота расположения дверной перемычки
|
||||||
|
:param height_door: int -- высота дверного проема
|
||||||
|
:return: None
|
||||||
|
"""
|
||||||
|
# создаем картинку с нужными размерами
|
||||||
|
img = Image.new("RGBA", (width * PICT_H / height_max, PICT_H), (255, 255, 255, 0))
|
||||||
|
# print(img_file_name_with_path)
|
||||||
|
# находим крайние точки периметра (если окно -- выравнено вверх; если дверь -- вниз)
|
||||||
|
top = 0
|
||||||
|
left = 0
|
||||||
|
bottom = img.size[1]
|
||||||
|
right = img.size[0]
|
||||||
|
draw = ImageDraw.Draw(img)
|
||||||
|
draw.rectangle((left, top, right-1, bottom-1), fill=(200, 200, 200, 50), outline=None)
|
||||||
|
if is_door: # это дверь. Выравнивание по нижней кромке
|
||||||
|
top = bottom - (height * PICT_H / height_max)
|
||||||
|
else: # это не дверь... Выравниваем по верхней кромке
|
||||||
|
if height < height_door:
|
||||||
|
top = bottom - (height_door * PICT_H / height_max)
|
||||||
|
bottom = top + (height * PICT_H / height_max)
|
||||||
|
flap_h = bottom - top
|
||||||
|
# рисуем внешнюю рамку
|
||||||
|
draw.line((left, bottom, right, bottom), fill=(125, 125, 125), width=25)
|
||||||
|
draw.line((left, top, right, top), fill=(125, 125, 125), width=25)
|
||||||
|
draw.line((left, top, left, bottom), fill=(125, 125, 125), width=25)
|
||||||
|
draw.line((right, top, right, bottom-6), fill=(125, 125, 125), width=25)
|
||||||
|
|
||||||
|
dim_flap = flap_analiz(flap_config)
|
||||||
|
|
||||||
|
############################################################
|
||||||
|
# НАЧИНАЕМ ОТРИСОВКУ СТВОРОК ОКНА НА КРТИНКУ
|
||||||
|
############################################################
|
||||||
|
v_ratio_max = 0 # число всех долей (частей) для построения пропорций по вертикали
|
||||||
|
for i in dim_flap: # цикл по рядам створок
|
||||||
|
v_ratio_max += i["vRatio"]
|
||||||
|
local_top = top
|
||||||
|
local_bottom = top
|
||||||
|
for i in dim_flap: # цикл по рядам створок
|
||||||
|
local_bottom += i["vRatio"]*flap_h/v_ratio_max
|
||||||
|
h_ratio_max = 0 # число всех долей (частей) для построения пропорций по горизонтали
|
||||||
|
for j in i["row"]:
|
||||||
|
h_ratio_max += j["hRatio"]
|
||||||
|
local_right = 0
|
||||||
|
local_left = 0
|
||||||
|
for j in i["row"]:
|
||||||
|
local_right += j["hRatio"] * right / h_ratio_max
|
||||||
|
# отрисовка схему открывания створки
|
||||||
|
if "M" in j["flap"] or "m" in j["flap"] or "м" in j["flap"] or "М" in j["flap"]: # москитная сетка
|
||||||
|
for k in range(local_left + 3, local_right - 3, 12):
|
||||||
|
draw.line((k, local_top + 7, k, local_bottom - 7), fill=(225, 225, 225, 255), width=2)
|
||||||
|
for k in range(local_top + 3, local_bottom - 3, 12):
|
||||||
|
draw.line((local_left + 7, k, local_right - 7, k), fill=(225, 225, 225), width=2)
|
||||||
|
if is_door: # Это дверь. Выравнивание по нижней кромке
|
||||||
|
top = bottom - (height * PICT_H / height_max)
|
||||||
|
# рисуем серединную перегородку =
|
||||||
|
draw.line((left, top + (height_mount_bulk * PICT_H / height_max) - 8,
|
||||||
|
right - 2, top + (height_mount_bulk * PICT_H / height_max) - 8),
|
||||||
|
fill=(125, 125, 125), width=8)
|
||||||
|
draw.line((left + 6, top + (height_mount_bulk * PICT_H / height_max) - 4,
|
||||||
|
right - 12, bottom - 12), fill=(125, 125, 125), width=3)
|
||||||
|
draw.line((right - 6, top + (height_mount_bulk * PICT_H / height_max) - 4,
|
||||||
|
left + 12, bottom - 12), fill=(125, 125, 125), width=3)
|
||||||
|
if "|" in j["flap"]: # вертикальная перегородка |
|
||||||
|
for k in range(j["flap"].count("|") + 1):
|
||||||
|
draw.line((local_left + k * (local_right - local_left) / (j["flap"].count("|") + 1), local_top,
|
||||||
|
local_left + k * (local_right - local_left) / (j["flap"].count("|") + 1), local_bottom),
|
||||||
|
fill=(125, 125, 125), width=4)
|
||||||
|
if "=" in j["flap"]: # горизонтальная перегородка =
|
||||||
|
for k in range(j["flap"].count("=") + 1):
|
||||||
|
draw.line((local_left, local_top + k * (local_bottom - local_top) / (j["flap"].count("=") + 1),
|
||||||
|
local_right, local_top + k * (local_bottom - local_top) / (j["flap"].count("=") + 1)),
|
||||||
|
fill=(125, 125, 125), width=4)
|
||||||
|
if "V" in j["flap"]: # откидное открывание V
|
||||||
|
draw.line((local_right - 12, local_bottom - 12, (local_right + local_left) / 2, local_top + 12),
|
||||||
|
fill=(225, 125, 125), width=1)
|
||||||
|
draw.line((local_left + 12, local_bottom - 12, (local_right + local_left) / 2, local_top + 12),
|
||||||
|
fill=(225, 125, 125), width=1)
|
||||||
|
if ">" in j["flap"] or "G" in j["flap"]: # поворотное влево >
|
||||||
|
draw.line((local_left + 12, local_top + 12, local_right - 12, (local_bottom + local_top) / 2),
|
||||||
|
fill=(225, 125, 125), width=1)
|
||||||
|
draw.line((local_left + 12, local_bottom - 12, local_right - 12, (local_bottom + local_top) / 2),
|
||||||
|
fill=(225, 125, 125), width=1)
|
||||||
|
if "<" in j["flap"] or "L" in j["flap"]: # поворотное вправо <
|
||||||
|
draw.line((local_right - 12, local_bottom - 12, local_left + 12, (local_bottom + local_top) / 2),
|
||||||
|
fill=(225, 125, 125), width=1)
|
||||||
|
draw.line((local_right - 12, local_top + 12, local_left + 12, (local_bottom + local_top) / 2),
|
||||||
|
fill=(225, 125, 125), width=1)
|
||||||
|
if "X" in j["flap"] or "x" in j["flap"] or "х" in j["flap"] or "Х" in j["flap"] or \
|
||||||
|
"+" in j["flap"]: # глухое окно +
|
||||||
|
draw.line(((local_right + local_left) / 2 - 11, (local_bottom + local_top) / 2,
|
||||||
|
(local_right + local_left) / 2 + 11, (local_bottom + local_top) / 2),
|
||||||
|
fill=(225, 125, 125), width=2)
|
||||||
|
draw.line(((local_right + local_left) / 2, (local_bottom + local_top) / 2 - 11,
|
||||||
|
(local_right + local_left) / 2, (local_bottom + local_top) / 2 + 11),
|
||||||
|
fill=(225, 125, 125), width=2)
|
||||||
|
if u"Z" in j["flap"] or "z" in j["flap"] or "S" in j["flap"] or "s" in j["flap"]: # РАСШИРИТЕЛЬ (спейсер)
|
||||||
|
draw.line(((local_left * 3 + local_right) / 4, (local_top * 3 + local_bottom) / 4,
|
||||||
|
(local_right * 3 - local_left) / 4, (local_top * 3 + local_bottom) / 4),
|
||||||
|
fill=(225, 125, 125), width=4)
|
||||||
|
draw.line(((local_left * 3 + local_right) / 4, (local_bottom * 3 + local_top) / 4,
|
||||||
|
(local_right * 3 - local_left) / 4, (local_bottom * 3 + local_top) / 4),
|
||||||
|
fill=(225, 125, 125), width=4)
|
||||||
|
draw.line(((local_left * 3 + local_right) / 4, (local_top * 3 + local_bottom) / 4,
|
||||||
|
(local_right * 3 - local_left) / 4, (local_bottom * 3 + local_top) / 4),
|
||||||
|
fill=(225, 125, 125), width=4)
|
||||||
|
# Отрисовка створки. ПЕРИМЕТР.
|
||||||
|
draw.line((local_left, local_bottom, local_right, local_bottom), fill=(125, 125, 125), width=18)
|
||||||
|
draw.line((local_left, local_top, local_right, local_top), fill=(125, 125, 125), width=18)
|
||||||
|
draw.line((local_left, local_top, local_left, local_bottom), fill=(125, 125, 125), width=18)
|
||||||
|
draw.line((local_right, local_top, local_right, local_bottom), fill=(125, 125, 125), width=18)
|
||||||
|
|
||||||
|
local_left = local_right
|
||||||
|
local_top = local_bottom
|
||||||
|
# второй проход -- рисуем тоненькую рамочку внутри толстых линий
|
||||||
|
local_top = top
|
||||||
|
local_bottom = top
|
||||||
|
for i in dim_flap: # цикл по рядам створок
|
||||||
|
local_bottom += i["vRatio"] * flap_h / v_ratio_max
|
||||||
|
h_ratio_max = 0 # число всех долей (частей) для построения пропорций по горизонтали
|
||||||
|
for j in i["row"]:
|
||||||
|
h_ratio_max += j["hRatio"]
|
||||||
|
local_right = 0
|
||||||
|
local_left = 0
|
||||||
|
for j in i["row"]:
|
||||||
|
local_right += j["hRatio"]*right/h_ratio_max
|
||||||
|
# Отрисовка створки. ПЕРИМЕТР
|
||||||
|
draw.rectangle((local_left, local_top, local_right, local_bottom), fill=None, outline=(0, 0, 0))
|
||||||
|
local_left = local_right
|
||||||
|
local_top = local_bottom
|
||||||
|
# рисуем крест-на-крест перечеркивание всего проема (просто так, для отладки)
|
||||||
|
# draw.line((left+6, top+6, right-6, bottom-6), fill=(200,200,200), width=1)
|
||||||
|
# draw.line((left+6, bottom-6, right-6, top+6), fill=(200,200,200), width=1)
|
||||||
|
# для оконо ниже чем самый высокий проем рисуем прямоугольник под подоконником
|
||||||
|
draw.rectangle((left, top + (height * PICT_H / height_max), right - 1, PICT_H),
|
||||||
|
fill=(255, 255, 255, 0), outline=None)
|
||||||
|
# для окон ниже чем дверь рисуем прямоугольник над проемом
|
||||||
|
draw.rectangle((left, 0, right - 1, top), fill=(255, 255, 255, 0), outline=None)
|
||||||
|
if is_door: # Это дверь. Надо нарисовать сверху прямоугольник, на случай если есть очень высокое окно
|
||||||
|
draw.rectangle((left, 0, right - 1, (height_max - height) * PICT_H / height_max),
|
||||||
|
fill=(255, 255, 255, 0), outline=None)
|
||||||
|
# рисуем внешнюю тоненькую окантовку
|
||||||
|
draw.rectangle((left, top, right-1, bottom-1), fill=None, outline=(0, 0, 0))
|
||||||
|
del draw
|
||||||
|
# сохраняем картинку
|
||||||
|
# img.info = {"Comment": "123456"}
|
||||||
|
img.save(img_file_name_with_path)
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
|
def flap_analiz(flap_config: str) -> list:
|
||||||
|
# анализ схем открывания.
|
||||||
|
dim_flap = [] # массив для хранения полной схемы открывания
|
||||||
|
i_end = len(flap_config)
|
||||||
|
j = -1 # счётчик горизонтальных рядов (формула, оконный блок)
|
||||||
|
k = -1 # счётчик вертикальных рядов внутри горизонтальных (створки)
|
||||||
|
in_flap = False # признак, где идёт разбор: внутри ли сворки или снаружи (схемы открывания или описания рядов)
|
||||||
|
# начинаем разбор
|
||||||
|
for i in range(0, i_end):
|
||||||
|
# посимвольный разбор строки
|
||||||
|
if i == 0 or flap_config[i - 1] == ".":
|
||||||
|
dim_flap.append({}) # надо создать новый ряд (фрамуги или ряд створок)
|
||||||
|
j += 1
|
||||||
|
k = -1
|
||||||
|
dim_flap[j].update({"row": []}) # добавляем в ряд пустой список створок
|
||||||
|
dim_flap[j].update({"vRatio": 1}) # добавляем число характеризующее пропорцию ряда относительно других
|
||||||
|
if not in_flap and (flap_config[i].isdigit() and flap_config[i - 1].isdigit()):
|
||||||
|
dim_flap[j].update({"vRatio": dim_flap[j]["vRatio"] * 10 + int(flap_config[i])})
|
||||||
|
continue
|
||||||
|
if not in_flap and flap_config[i].isdigit():
|
||||||
|
dim_flap[j].update({"vRatio": int(flap_config[i])})
|
||||||
|
continue
|
||||||
|
# получен символ начала описания створки
|
||||||
|
if flap_config[i] == "[" and not in_flap:
|
||||||
|
in_flap = True
|
||||||
|
dim_flap[j]["row"].append({})
|
||||||
|
k += 1
|
||||||
|
dim_flap[j]["row"][k].update({"flap": ""})
|
||||||
|
dim_flap[j]["row"][k].update({"hRatio": 1})
|
||||||
|
continue
|
||||||
|
# получен символ окончание описания створки
|
||||||
|
if in_flap and flap_config[i] == "]":
|
||||||
|
in_flap = False
|
||||||
|
continue
|
||||||
|
# символ увеличения пропорции
|
||||||
|
if in_flap and (flap_config[i] == "-" or flap_config[i] == "_"): # для управления пропорциями створок
|
||||||
|
dim_flap[j]["row"][k]["hRatio"] += 1
|
||||||
|
continue
|
||||||
|
if in_flap and (flap_config[i].isdigit() and flap_config[i - 1].isdigit()):
|
||||||
|
dim_flap[j]["row"][k].update({"hRatio": dim_flap[j]["row"][k]["hRatio"]*10 + int(flap_config[i])})
|
||||||
|
continue
|
||||||
|
if in_flap and flap_config[i].isdigit():
|
||||||
|
dim_flap[j]["row"][k].update({"hRatio": int(flap_config[i])})
|
||||||
|
continue
|
||||||
|
if in_flap and (flap_config[i] == "V" # откидное открывание
|
||||||
|
or flap_config[i] == ">" # поворотное влево
|
||||||
|
or flap_config[i] == "G" # ^
|
||||||
|
or flap_config[i] == "L" # поворотное вправо
|
||||||
|
or flap_config[i] == "<" # ^
|
||||||
|
or flap_config[i] == "|" # вертикальная перегородка
|
||||||
|
or flap_config[i] == "=" # горизонтальная перегородка
|
||||||
|
or flap_config[i] == "X" # глухое окно
|
||||||
|
or flap_config[i] == "x" # ^
|
||||||
|
or flap_config[i] == u"х" # ^
|
||||||
|
or flap_config[i] == u"Х" # ^
|
||||||
|
or flap_config[i] == "+" # ^
|
||||||
|
or flap_config[i] == "M" # москитная сетка
|
||||||
|
or flap_config[i] == "m" # ^
|
||||||
|
or flap_config[i] == "м" # ^
|
||||||
|
or flap_config[i] == "М" # ^
|
||||||
|
or flap_config[i] == "Z" # расширитель (спейсер)
|
||||||
|
or flap_config[i] == "S" # ^
|
||||||
|
or flap_config[i] == "z" # ^
|
||||||
|
or flap_config[i] == "s"): # ^
|
||||||
|
dim_flap[j]["row"][k].update({"flap": dim_flap[j]["row"][k]["flap"] + flap_config[i]})
|
||||||
|
return dim_flap
|
||||||
|
|||||||
@@ -2,15 +2,18 @@
|
|||||||
from django.core.exceptions import ObjectDoesNotExist
|
from django.core.exceptions import ObjectDoesNotExist
|
||||||
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.template.loader import render_to_string
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
from oknardia.settings import *
|
from oknardia.settings import *
|
||||||
from oknardia.models import PVCprofiles, Seria_Info
|
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.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
|
from web.add_func import normalize, get_rating_set_for_stars, get_flaps_for_big_pictures
|
||||||
import time
|
import time
|
||||||
import json
|
import json
|
||||||
import random
|
import random
|
||||||
import re
|
import re
|
||||||
|
import os
|
||||||
|
import math
|
||||||
import pytils
|
import pytils
|
||||||
|
|
||||||
|
|
||||||
@@ -460,3 +463,349 @@ def catalog_seria(request: HttpRequest) -> HttpResponse:
|
|||||||
'ticks': float(time.time() - time_start)
|
'ticks': float(time.time() - time_start)
|
||||||
})
|
})
|
||||||
return render(request, "catalog/catalog_seria.html", to_template)
|
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
|
||||||
|
|||||||
@@ -3,14 +3,15 @@ from django.shortcuts import render
|
|||||||
from django.http import HttpRequest, HttpResponse
|
from django.http import HttpRequest, HttpResponse
|
||||||
from django.core.exceptions import ObjectDoesNotExist
|
from django.core.exceptions import ObjectDoesNotExist
|
||||||
from time import time
|
from time import time
|
||||||
from oknardia.models import Seria_Info
|
|
||||||
from oknardia.settings import *
|
from oknardia.settings import *
|
||||||
|
from oknardia.models import Seria_Info
|
||||||
|
# from oknardia.catalog import all_seria_nav
|
||||||
import math
|
import math
|
||||||
import os
|
import os
|
||||||
import pytils # вместо Rus2Lat(smth) --> pytils.translit.slugify(smth).lower()
|
import pytils # вместо Rus2Lat(smth) --> pytils.translit.slugify(smth).lower()
|
||||||
|
|
||||||
|
|
||||||
# возвращает корректный SeriaID и кортеж для построения навигации по сериям дома
|
# возвращает корректный seria_id и кортеж для построения навигации по сериям дома
|
||||||
def seria_nav(i_seria_id: int = 12) -> (int, dict):
|
def seria_nav(i_seria_id: int = 12) -> (int, dict):
|
||||||
query_seria = Seria_Info.objects.raw(
|
query_seria = Seria_Info.objects.raw(
|
||||||
'SELECT oknardia_seria_info.id,'
|
'SELECT oknardia_seria_info.id,'
|
||||||
@@ -27,7 +28,7 @@ def seria_nav(i_seria_id: int = 12) -> (int, dict):
|
|||||||
error_seria = False
|
error_seria = False
|
||||||
break
|
break
|
||||||
if error_seria:
|
if error_seria:
|
||||||
# Ошибочный SeriaID. Такой базовой серии нет и надо ее найти.
|
# Ошибочный seria_id. Такой базовой серии нет и надо ее найти.
|
||||||
try:
|
try:
|
||||||
query = Seria_Info.objects.get(id=int(i_seria_id))
|
query = Seria_Info.objects.get(id=int(i_seria_id))
|
||||||
if query.kRoot_id is None:
|
if query.kRoot_id is None:
|
||||||
@@ -45,21 +46,8 @@ def seria_nav(i_seria_id: int = 12) -> (int, dict):
|
|||||||
i_seria_id = min_id
|
i_seria_id = min_id
|
||||||
except ObjectDoesNotExist:
|
except ObjectDoesNotExist:
|
||||||
i_seria_id = query_seria[0].id
|
i_seria_id = query_seria[0].id
|
||||||
# print("-->", SeriaID, "<--")
|
# print(f"-->{seria_id}<--")
|
||||||
seria_nav_dim = []
|
return all_seria_nav(i_seria_id, query_seria)
|
||||||
this_return = {}
|
|
||||||
for count_seria in query_seria:
|
|
||||||
one_seria = {}
|
|
||||||
one_seria.update({"SERIA_R": count_seria.sName, "ID2URL": count_seria.id})
|
|
||||||
if count_seria.id == i_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 i_seria_id, this_return
|
|
||||||
|
|
||||||
|
|
||||||
def statistic_menu(request: HttpRequest) -> HttpResponse:
|
def statistic_menu(request: HttpRequest) -> HttpResponse:
|
||||||
|
|||||||
Reference in New Issue
Block a user