главный экран и автокомплит при наборе адреса на главной

This commit is contained in:
2022-11-05 19:16:15 +03:00
parent 7b0fc32d69
commit bf5de5b25e
7 changed files with 490 additions and 15 deletions

View File

@@ -1,3 +1,4 @@
# -*- coding: utf-8 -*-
"""
Django settings for oknardia project.
@@ -47,6 +48,8 @@ INSTALLED_APPS = [
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'oknardia.apps.OknardiaConfig',
'web.apps.WebConfig',
]
@@ -65,8 +68,7 @@ ROOT_URLCONF = 'oknardia.urls'
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [BASE_DIR / 'templates']
,
'DIRS': [BASE_DIR / 'templates'],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
@@ -98,10 +100,10 @@ LANGUAGE_CODE = 'ru-RU'
TIME_ZONE = 'Europe/Moscow'
USE_I18N = True
USE_TZ = True
USE_L10N = False # локальный формат дат имеет приоритет
FIRST_DAY_OF_WEEK = 1 # 1'st day week -- monday
SHORT_DATE_FORMAT = '%Y-%m-%d'
SHORT_DATETIME_FORMAT = '%Y-%m-%d %H:%M:%S'
SHORT_DATE_FORMAT = 'Y-m-d'
SHORT_DATETIME_FORMAT = 'Y-m-d H:M:S'
DATETIME_FORMAT = 'Y-m-d H:M:S'
# Статические файлы (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/4.1/howto/static-files/
@@ -109,18 +111,44 @@ SHORT_DATETIME_FORMAT = '%Y-%m-%d %H:%M:%S'
STATIC_URL = 'static/'
MEDIA_URL = 'media/'
#
# https://docs.djangoproject.com/en/4.1/ref/settings/#databases
if DEBUG: # DEBUG: заменяем настройки прода, на настройки девопа
MEDIA_ROOT = MY_MEDIA_ROOT_DEV1 if socket.gethostname() == MY_HOST_HOME1 else MY_MEDIA_ROOT_DEV2
# STATIC_ROOT = MY_STATIC_ROOT_DEV1 if socket.gethostname() == MY_HOST_HOME1 else MY_STATIC_ROOT_DEV2
STATICFILES_DIRS = [
MY_STATIC_ROOT_DEV1 if socket.gethostname() == MY_HOST_HOME1 else MY_STATIC_ROOT_DEV2,
]
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': BASE_DIR / 'db.sqlite3',
'ENGINE': "django.db.backends.mysql",
'HOST': MY_DATABASE_HOST_DEV1 if socket.gethostname() == MY_HOST_HOME1 else MY_DATABASE_HOST_DEV2,
'PORT': MY_DATABASE_PORT_DEV, # Set to "" for default. Not used with sqlite3.
'NAME': MY_DATABASE_NAME_DEV, # Not used with sqlite3.
'USER': MY_DATABASE_USER_DEV, # Not used with sqlite3.
'PASSWORD': MY_DATABASE_PASSWORD_DEV, # Not used with sqlite3.
# 'OPTIONS': { 'autocommit': True, }
}
}
TOUCH_RELOAD = MY_TOUCH_RELOAD_PROD
else:
MEDIA_ROOT = MY_MEDIA_ROOT_PROD
STATIC_ROOT = MY_STATIC_ROOT_PROD
# STATICFILES_DIRS = [MY_STATIC_ROOT_PROD1, ]
DATABASES = {
'default': {
'ENGINE': "django.db.backends.mysql",
'HOST': MY_DATABASE_HOST_PROD, # Set to "" for localhost. Not used with sqlite3.
'PORT': MY_DATABASE_PORT_PROD, # Set to "" for default. Not used with sqlite3.
'NAME': MY_DATABASE_NAME_PROD, # Not used with sqlite3.
'USER': MY_DATABASE_USER_PROD, # Not used with sqlite3.
'PASSWORD': MY_DATABASE_PASSWORD_PROD, # Not used with sqlite3.
# 'OPTIONS': { 'autocommit': True, }
}
}
TOUCH_RELOAD = MY_TOUCH_RELOAD_PROD
#########################################
# настройки для почтового сервера
# настройки для почтового сервера (они одинаковые для DEV и PROD)
EMAIL_HOST = MY_EMAIL_HOST_DEV
EMAIL_PORT = MY_EMAIL_PORT_DEV
EMAIL_HOST_USER = MY_EMAIL_HOST_USER_DEV
@@ -138,3 +166,93 @@ DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
# ключи для Google Captha
CAPTCHA_PUBLIC_KEY = MY_CAPTCHA_PUBLIC_KEY
CAPTCHA_PRIVATE_KEY = MY_CAPTCHA_PRIVATE_KEY
# количество коммерческих предложений во фреме отчета
OFFER_PER_FRAME = 5
OFFER_PER_FRAME_FOR_ONE_FLAP = 10
# папка для хранения изображений
PATH_FOR_IMG = "img"
PATH_FOR_IMG_BLOG = u"img_for_blog/"
PATH_FOR_IMG_AVATAR = u"img_avatar/"
PATH_FOR_IMG_LOGOS = u"logos_img/"
PATH_FOR_IMG_APARTMENT = u"img_apart/"
PATH_FOR_IMG_SERIA = u"img_seria/"
# папка для хранения мини-картинок со схемами открывания внутри PATH_FOR_IMG
PATH_FOR_BIGIMGFLAPCONFIG = "_flap.cfg"
PATH_FOR_IMGFLAPCONFIG = "_miniflap.cfg"
PATH_FOR_JS = "js"
PATH_FOR_JS_MAP = "js/4maps"
SUFFIX_FOR_JS_MAP = "_seria_on_map.js"
SUFFIX_FOR_MINI_JS_MAP = "_seria_on_map.mini.js"
PATH_FOR_SERIA_INFO_HTML_INCLUDE = "SeriaInfo/prepared/"
# переменные
# высота картинки
PICT_H = 500
# высота картинки (без обводки)
PICT_MINIH = 18
# ширина строки на мини картинке (без обводки)
PICT_MINWI = 9
# для рейтинга
RARING_STAR = 5 # ЗВЕЗДОЧЕК В РЕЙТИНГЕ
RARING_SET_MAX = 5.0 # МАКСИМАЛЬНЫЙ РЕЙТИНГ НАБОРА
RARING_SET_MIN = 0.0 # МИНИМАЛЬНЫЙ РЕЙТИНГ НАБОРА
RARING_GLAZING_MAX = 5.0
RARING_GLAZING_MIN = 0.0
RARING_PVC_PROFILE_MAX = 5.0
RARING_PVC_PROFILE_MIN = 0.0
RARING_WEIGHT_PVC_PROFILE_IN_SET = 1.5 # сколько рейтинга (зведочек) набора составляет профиль
RARING_WEIGHT_GLAZING_IN_SET = 1.5 # сколько рейтинга (зведочек) набора составляет стеклопакет
# веса ранкинга (веса ранжирования)
RANK_STEP_SET_MODIFY = 0.75 # Дата последнего обновления цены набора
RANK_STEP_SET_DELIVERY = 2 # Доставка включена в стоимость
RANK_STEP_SET_UNINSTALL_INSTALL = 2 # Демонтаж/Монтаж включен в стоимость
RANK_STEP_SET_SILL = 1.5 # Подоконник включен в стоимость
RANK_STEP_SET_PANES = 1.5 # Водоотлив включен в стоимость
RANK_STEP_SET_SLOPE = 1.5 # Откос включен в стоимость
RANK_STEP_SET_CLIMATE_CONTROL = 0.5 # Климат-контроль включен в стоимость
RANK_STEP_SET_NUM_OFFER = 0.1 # Число предложений включен в стоимость
RANK_STEP_DISCOUNT_FLEX = 1 # Гибкость скидок (число шагов скидки)
RANK_STEP_DISCOUNT_MAX = 1 # Размер скидки (максимальная скидка)
RANK_GLAZ_SOUNDPROOFING = 1.0 # Шумоизоляция СТЕКЛОПАКЕТА
RANK_GLAZ_HEAT_TRANSFER = 1.0 # Теплопередача СТЕКЛОПАКЕТА
RANK_GLAZ_LIGHT_TRANSMISSION = 0.25 # Коэффициент светопропускания СТЕКЛОПАКЕТА
RANK_GLAZ_PASSING_SUN = 0.15 # Коэффициент солнцепропускания СТЕКЛОПАКЕТА
RANK_GLAZ_THICKNESS = 0.1 # Толщина СТЕКЛОПАКЕТА
RANK_GLAZ_CAMERAS_NUM = 0.1 # Число камер СТЕКЛОПАКЕТА
RANK_GLAZ_CAMERAS_NUM_NAME=u"Число камер"
RANK_PVCP_SOUNDPROOFING = 1.0 # Шумоизоляция ПРОФИЛЯ
RANK_PVCP_SOUNDPROOFING_NAME = u"Шумоизоляция"
RANK_PVCP_HEAT_TRANSFER = 1.0 # Теплопередача ПРОФИЛЯ
RANK_PVCP_HEAT_TRANSFER_NAME = u"Теплопередача"
RANK_PVCP_HEIGHT = 0.3 # Высота в световом проеме ПРОФИЛЯ
RANK_PVCP_HEIGHT_NAME = u"Высота в проёме"
RANK_PVCP_RABBET = 0.2 # Высота фальца ПРОФИЛЯ
RANK_PVCP_RABBET_NAME = u"Фальц"
RANK_PVCP_G_THICKNESS = 0.2 # Максимальная толщина стеклопакета ПРОФИЛЯ
RANK_PVCP_G_THICKNESS_NAME = u"Толщина стеклопакета"
RANK_PVCP_THICKNESS = 0.2 # Монтажная ширина ПРОФИЛЯ
RANK_PVCP_THICKNESS_NAME = u"Толщина профиля"
RANK_PVCP_SEALS = 1.2 # Контуров уплотненения ПРОФИЛЯ
RANK_PVCP_SEALS_NAME = u"Уплотнители"
RANK_PVCP_CAMERAS_NUM = 0.1 # Число камер ПРОФИЛЯ
RANK_PVCP_CAMERAS_NUM_NAME = u"Число камер"
RANK_PVCP_CAMERAS_POPULARITY_NAME = u"Популярность"
# бля блогов
NUM_BLOG_TIZER_IN_PAGE = 5 # дисто тизеров (анонсов) блогов на страничке
NUM_PAGE_IN_PAGINATOR = 3 # чисто отображаемых страничек в педжинаторе
# Унифицированные именования ключей для JSON-объектов
KEY_URL = "url"
KEY_NOTE = "note"
KEY_RATING = "RATING"
KEY_RATING_VIRTUAL = "RATING_V"
KEY_DICSOUNT = "%"
KEY_HTML = "html"
# KEY_RATING_VIRTUAL = "reting_v"
# Типы карточек каталога
CATALOG_RECORD_FOR_PROFILE_MODEL = 1
CATALOG_RECORD_FOR_PROFILE_MANUFACTURER = 100
CATALOG_SORTER_MAGIC_NUMBER_ADV = 5
CATALOG_SORTER_MAGIC_NUMBER_TIZER = 1

View File

@@ -1,3 +1,4 @@
# -*- coding: utf-8 -*-
"""oknardia Конфигурация URL
Список `urlpatterns` направляет URL-адреса в представления. Дополнительную информацию см.:
@@ -14,8 +15,39 @@
2. Добавьте URL-адрес в urlpatterns: path('blog/', include('blog.urls'))
"""
from django.contrib import admin
from django.urls import path
from django.urls import path, re_path
from django.conf.urls.static import static
from oknardia.settings import *
from web import views, autocomplete_addr, user_manager
urlpatterns = [
path('admin/', admin.site.urls),
# главная страница
re_path(r'^$', views.main_init),
# обработчик автокомлита (подсказки во время ввода адреса на главной странице)
re_path(r'^autocomplete_addr$', autocomplete_addr.autocomplete_addr),
# ОБРАБОТЧИКИ АВТОРИЗАЦИИ
# Вызов шаблона подгружаем captcha
re_path(r'^captcha', user_manager.captcha),
# Обработчик информации и статусов пользователя и, или подгрузка шаблона login-logout.html
re_path(r'^login-logout', user_manager.menu_login_logout),
# Обработчик форма login-logout-restore. После обработки пере-подгружает шаблон login-logout-after.html
re_path(r'^form-loginout', user_manager.form_user_menu_processing),
# Верификатор email после отправки почты и проверки ее пользователем. URL: /USER_%05d/CONFIRM:%s
re_path(r'^USER_(?P<user_id>\d{1,8})/CONFIRM:(?P<hash_part_12>\S+)$', user_manager.confirm_email),
# Ссылка, по которой пользователь может поменять пароль при утере. URL: /USER_%05d/RESTORE:%s
re_path(r'^USER_(?P<user_id>\d{1,8})/RESTORE:(?P<hash_part_12>\S+)$', user_manager.restore_password),
re_path(r'^change_password$', user_manager.change_password),
]
if DEBUG:
urlpatterns += static(MEDIA_URL, document_root=MEDIA_ROOT)
# ___ ____ _ _____ _ _ _____ _
# | | | | \ ___| |_ _ _ ___ |_ _|___ ___| | |_ ___ ___ | _ |___ ___ ___| |
# |_ | | | | -_| . | | | . | | | | . | . | | . | .'| _| | __| .'| | -_| |
# |_| |____/|___|___|___|_ | |_| |___|___|_|___|__,|_| |__| |__,|_|_|___|_|
# |___|

93
oknardia/templates/base.html Executable file
View File

@@ -0,0 +1,93 @@
<!DOCTYPE html>{% load static %}
<html lang="ru-RU">
<head>
<meta charset="utf-8" />
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta http-equiv="content-language" content="ru" />
<meta http-equiv="Date" content="{% block Date4Meta %}{% now "c" %}{% endblock %}" />
<meta http-equiv="Last-Modified" content="{% block Last4Meta %}{% now "c" %}{% endblock %}" />
<meta http-equiv="Expires" content="{% block Expires4Meta %}{% now "c" %}{% endblock %}" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="description" content="{% block Description %}{{ META_DESCRIPTION|default:"" }}Здесь вы можете узнать все цены и скидки на пластиковые окона для квартиры. Просто введите адрес, укажите планировку квартиры и узнайте размеры проёмов, актуальные предложения и цены на установку окон от ведущих поставщиков. Сравнивайте характеристики стеклопакетов, профилей, схем открывания, цены и условия установки, осблуживания и гарантии.{% endblock %}" />
<meta name="keywords" content="{% block Keywords %}цены на пластиковые окна, скидки на пластиковые окна, окна в квартиру, размеры окон в доме серии, скидки на пластиковые окна, характеристики пластиковых окон{{ META_KEYWORDS|default:"" }}{% endblock %}" />
<meta name="author" content="OKNARDIA.RU{% block Author4Meta %}{% endblock %}" />
<meta name="copyright" lang="ru" content="OKNARDIA.RU{% block CopyrightAuthor4Meta %}{% endblock %}" />
<meta name="robots" content="index,follow" />
<meta name="document-state" content="{{ META_DOCUMENT_STATE|default:"Dynamic" }}" />
<meta name="generator" content="OKNARDIA 0.3β by Python/Django" />
<title>ОКНАРДИЯ: {% block Title %}{% endblock %}</title>
<link rel="alternate" href="https://oknardia.ru" hreflang="ru-ru" />
<link href="{% static 'css/bootstrap.min.css' %}" rel="stylesheet" type="text/css" />{# <link href="//maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" rel="stylesheet" type="text/css" />#}
<link href="{% static 'css/bootstrap-theme.min.css' %}" rel="stylesheet" type="text/css" />{# <link href="//maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap-theme.min.css" rel="stylesheet" type="text/css" />#}
<link href="{% static 'css/oknardia1.css' %}" rel="stylesheet" type="text/css" />{% block Top_CSS1 %}{% endblock %}{% block Top_CSS2 %}{% endblock %}{% block Top_CSS3 %}{% endblock %}
<script src="{% static 'js/jquery-2.1.1.min.js' %}" type="text/javascript"></script>{# <script src="//ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js" type="text/javascript"></script>#}
<script src="{% static 'js/bootstrap.min.js' %}" type="text/javascript"></script>{# <script src="//maxcdn.bootstrapcdn.com/bootstrap/3.3.6/js/bootstrap.min.js" type="text/javascript"></script>#}{% block Top_JS1 %}{% endblock %}{% block Top_JS2 %}{% endblock %}{% block Top_JS3 %}{% endblock %}{% block Top_JS4 %}{% endblock %}{% block Top_JS5 %}{% endblock %}{% block Top_Meta1 %}{% endblock %}
<script type="text/javascript">$(document).ready(function(){ $('#login-logout').load('/login-logout' ); })</script>
</head>
<body{% block Add_Body_Attribute %}{% endblock %}>
{# Контент НАЧАЛО #}<!--- Контент НАЧАЛО --->
{% block Main_Content %}{% endblock %}
{# Контент КОНЕЦ #}<!---/ Контент КОНЕЦ --->
{# ######################################## Верхнее меню НАЧАЛО ######################################## #}
{% block Top_Nav_Bar %}<nav class="navbar navbar-fixed-top navbar-default" role="navigation" id="header">
<div class="container-fluid">
<div class="navbar-header">
<a class="navbar-brand" href="/"><nobr><img src="{% static 'img/oknardia_logo.svg' %}" onerror="this.onerror=null;this.src='{% static 'img/oknardia_logo.gif' %}';this.width=290;this.height=34" title="Перейти на гравную сраницу «Окнардия»" alt="Логотип «Окнардия — оконный агрегатор»" ></nobr></a>
</div>
<ul class="nav navbar-nav navbar-right">
<li><a href="/catalog">Каталог</a></li>
<li><a href="/stat/rating/">Рейтинги</a></li>
<li><a href="/blog">Блог</a></li>
<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown" rel="nofollow">О проекте <b class="caret"></b></a>
<ul class="dropdown-menu">
<li><a href="/stat_all">Статистика</a></li>
<li role="separator" class="divider"></li>
<li><a href="/contact">Контакты</a></li>
<li><a href="/blogpost/2/My_zhdem_vashi_prajs-listy!">Сотрудничество</a></li>
<li><a href="/tariff">Услуги и тарифы</a></li>
<!-- li class="divider"></li>
<li><a href="#" rel="nofollow">Обратная связь</a></li -->
</ul>
</li>
<li class="dropdown" id="login-logout"><!--- Сюда подгружают AJAX-ом блок login-logout ---><small><br />Авторизации.<noscript style="color:red;">Для авторизации необходимо включить JavaScript.</noscript></small></li>
</ul>
</div>
</nav>{% endblock %}
{# ######################################## Верхнее меню КОНЕЦ ######################################## #}
{# ######################################## Нижнее меню-футер НАЧАЛО ######################################## #}
{% block Bottom_Nav_Bar %}
<div class="row panel-footer">
<div class="col-xs-12">
<span style="top:-200px;left:-8000px;position: absolute;"><script type="text/javascript">
{# <!-- Google Analylics --> #}(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)})(window,document,'script','//www.google-analytics.com/analytics.js','ga');
ga('create', 'UA-9116991-5', 'auto'); ga('send', 'pageview');
{# <!-- Rating@Mail.ru counter --> #}var _tmr=_tmr||[];_tmr.push({id:"2018432",type:"pageView",start:(new Date()).getTime()});(function (d,w,id){if(d.getElementById(id))return;var ts=d.createElement("script");ts.type="text/javascript";ts.async=true;ts.id=id;ts.src=(d.location.protocol=="https:"?"https:":"http:")+"//top-fwz1.mail.ru/js/code.js";var f=function(){var s=d.getElementsByTagName("script")[0];s.parentNode.insertBefore(ts, s);};if(w.opera=="[object Opera]"){ d.addEventListener("DOMContentLoaded",f,false);}else{f();}})(document,window,"topmailru-code");
</script><noscript><div style="position:absolute;left:-10000px;">
{# <!-- Rating@Mail.ru nosript --> #}<img src="//top-fwz1.mail.ru/counter?id=2018432;js=na" style="border:0;height:1px;width:1px" alt="" />
{# <!-- Yandex.Metrika counter --> #}<img src="//mc.yandex.ru/watch/32997984" style="border:0;height:1px;width:1px" alt="" />{# <!-- /Yandex.Metrika counter --> #}
</div></noscript>
{#<!-- Rating@Mail.ru logo -->#}<a target="_blank" href="http://top.mail.ru/jump?from=2018432"><img src="//top-fwz1.mail.ru/counter?id=2018432;t=216;l=1" style="border:0;padding-top:8px;" rel="nofollow" alt="Рейтинг@Mail.ru"></a>{#<!-- //Rating@Mail.ru logo -->#}
{# <!-- Yandex.Metrika informer --> #}<a href="https://metrika.yandex.ru/stat/?id=32997984&amp;from=informer" target="_blank" rel="nofollow"><img src="https://informer.yandex.ru/informer/32997984/3_0_E0E0E0FF_C0C0C0FF_0_pageviews" style="width:88px; height:31px; border:0;" alt="Яндекс.Метрика" title="Яндекс.Метрика: данные за сегодня (просмотры, визиты и уникальные посетители)" onclick="try{Ya.Metrika.informer({i:this,id:32997984,lang:'ru'});return false}catch(e){}" /></a>{# <!-- /Yandex.Metrika informer --> #}
{# <!-- begin of Top100 code --> #}<span id="rambler"><script id="top100Counter" type="text/javascript" src="//counter.rambler.ru/top100.jcn?3148853"></script><noscript><a href="http://top100.rambler.ru/navi/3148853/"><img src="http://counter.rambler.ru/top100.cnt?3148853" alt="Rambler's Top100" border="0"/></a></noscript></span>{# <!-- end of Top100 code --> #}
<script type="text/javascript"><!--
{#<!--LiveInternet counter-->#}document.write("<a href='//www.liveinternet.ru/click' target=_blank><img src='//counter.yadro.ru/hit?t50.2;r"+escape(document.referrer)+((typeof(screen)=="undefined")?"":";s"+screen.width+"*"+screen.height+"*"+(screen.colorDepth?screen.colorDepth:screen.pixelDepth))+";u"+escape(document.URL)+";"+Math.random()+"' alt='' title='LiveInternet' style='border:0;padding-top:8px;'><\/a>");
{# <!-- Yandex.Metrika counter --> #}(function(d,w,c){(w[c]=w[c]||[]).push(function(){try{w.yaCounter32997984=new Ya.Metrika({id:32997984,clickmap:true,trackLinks:true,accurateTrackBounce:true,webvisor:true,trackHash:true});}catch(e){}});var n=d.getElementsByTagName("script")[0],s=d.createElement("script"),f=function(){n.parentNode.insertBefore(s,n);};s.type="text/javascript";s.async=true;s.src="https://mc.yandex.ru/metrika/watch.js";if(w.opera=="[object Opera]"){d.addEventListener("DOMContentLoaded",f,false);}else{ f();}})(document,window,"yandex_metrika_callbacks");
//--></script>{# <!--/LiveInternet--> #}
</span>
<small>© oknardia.ru, 2015-{% now "Y" %}. <a href="/blogpost/18/Ob-avtorskih-pravah">Все права защищены</a>.<!--- Время отработки скрипта: {{ ticks }}{{ TAU }} сек---></small>
</div>
</div>{% endblock %}
{# ######################################## Нижнее меню-футер КОНЕЦ ######################################## #}
{# Модальное окно SOCIAL LOGIN НАЧАЛО #}
{% block Modal_Login %}{% endblock %}
{# Модальное окно SOCIAL LOGIN КОНЕЦ #}
</body>
</html>

62
oknardia/templates/index.html Executable file
View File

@@ -0,0 +1,62 @@
{% extends "base.html" %}
{% load static %}
{% block Title %}: выбор пластиковых окон в квартиру. Поставщики, цены, описания, характеристики, отзывы.{% endblock %}
{% block Description %}Окнардия: Здесь собраны цены на установку пластиковых окон. Просто введите адрес и получите актуальные предложения от ведущих поставщиков окон, подробные характеристики профилей и стеклопакетов, информацию о скидках. Никаких предварительных замеров! Мы уже знаем размеры проёмов в квартире, рекомендованные схемы открывания, требования к стеклопакетам, профилю и многое другое. Замена пластиковых окон — ответственное мероприятие. Мы помогаем сделать объективный выбор.{% endblock %}
{% block Keywords %}Цены на окна, цены на пластиковые окна, стоимость замены окон, пластиковые окна в квартиру, скидки на пластиковые окна, окна в квартиру, размеры окон, скидки на пластиковые окна, характеристики пластиковых окон, окна в панельный дом, окна в блочный дом.{% endblock %}
{% block Top_JS1 %}{# comment #}
<!-- script src="{% static 'js/gears_init.js' %}" type="text/javascript"></script>
<script src="{% static 'js/geo.js' %}" type="text/javascript"></script>
<script src="http://maps.google.com/maps/api/js?sensor=false" type="text/javascript"></script -->{# endcomment #}
<script src="//api-maps.yandex.ru/2.1/?lang=ru_RU" type="text/javascript"></script>
<script src="{% static 'js/jquery-ui.min.js' %}" type="text/javascript"></script>
{% endblock %}
{% block Top_CSS2 %}
<link href="{% static 'css/jquery-ui.min.css' %}" rel="stylesheet" type="text/css" />
{% endblock %}
{% block Main_Content %}
<script type="text/javascript">
// Дождёмся загрузки API и готовности DOM.
ymaps.ready(init);
function init () {
// Создание экземпляра карты и его привязка к контейнеру с заданным id ("map").
myMap = new ymaps.Map('map', {
center: [55.68, 37.77], // Москва, Люблино
zoom: 15, // коэффициент масштабирования
controls: [] // выключить кнопки, формы и пр.
});
myMap.behaviors.disable('scrollZoom');
}
{# // подгружаем центральный popup #box #}
{# {% if not CONFIRM_OK %} #}
{# $(document).ready( function(){ $('#box').load('/center_popup_main'); } ); #}
{# {% endif %} #}
</script>
<div id="map"></div>
<div id="ton"></div>
<div id="box" class="col-md-9 col-md-offset-2"><!--- Сюда подгружаем центральный popup --->
{% if not CONFIRM_OK %}
{% include "popup_index.html" %}
{% elif CONFIRM_OK == "YES" %}
{% include "user_manager/popup_cofirm_email_ok.html" %}
{% elif CONFIRM_OK == "NO" %}
{% include "user_manager/popup_confirm_email_or_restore_password_bad.html" %}
{% elif CONFIRM_OK == "CHANGE_PWD" %}
{% include "user_manager/popup_restore_pasword_form.html" %}
{% endif %}</div>
{% endblock %}
{% comment %}
{% block Top_Nav_Bar %}
{# ОТЛАДКА, ГАСИМ ВЕРХНЕЕ МЕНЮ #}
{% endblock %}
{% endcomment %}

View File

@@ -0,0 +1,85 @@
{% load static %}
{% with APP_INVITATION_STRING_IN_FORM="Город, улица, дом" %}
<script type="text/javascript">
function set_filter(s) {
// переинициализируем autocomplete
$('#addr').autocomplete("option", "source", "/autocomplete_addr?csrfmiddlewaretoken={{ csrf_token }}&use_filter=" + s);
}
$(document).ready(function () {
$('#input_address').submit(function () {
try {
yaCounter32997984.reachGoal('FIND');
ga('send', 'event', 'CLICK', 'ClickSearch', 'SearchAddress');
_tmr.push({id: '2018432', type: 'reachGoal', goal: 'ClcSrh'});
}
catch (e) {
}
if ($("#addr").val() != "{{ APP_INVITATION_STRING_IN_FORM }}") {
$.ajax({
url: "/get_address", //Адрес подгружаемой страницы
type: "POST", //Тип запроса
dataType: "html", //Тип данных
data: $("#input_address").serialize(),
success: function (html) {
$("#box").html(html)
}
});
return false;
}
});
$('#addr').autocomplete({ // автозаполнение
source: "/autocomplete_addr?csrfmiddlewaretoken={{ csrf_token }}&use_filter=only_known", // Страница для обработки запросов автозаполнения
minLength: 4, // Минимальная длина запроса для срабатывания автозаполнения
delay: 160 // Задержка срабатывания автозаполнения
});
$.fn.fade_obj = function (ops) {
var $elem = this;
var res = $.extend({delay: 670, speed: 890}, ops);
for (var i = 0, pause = 0, l = $elem.length; i < l; i++, pause += res.delay) {
$elem.eq(i).delay(pause).fadeIn(res.speed);
}
return $elem;
};
$('.show_delayed').fade_obj();
});
</script>
<h1>Выбирайте окна в квартиру<!-- ({{ NV }})-->:</h1>
{% if NV <= 1 %}
<ol>
<li class="show_delayed">Вводите адрес дома или выберите его из подсказки,</li>
<li class="show_delayed">укажите тип квартиры,</li>
<li class="show_delayed">получите актуальные цены и сравнивайте характеристики предложений.</li>
</ol>
{% endif %}
<form class="show_delayed" method="post" id="input_address">
{% csrf_token %}
<div class="btn-group" data-toggle="buttons" style="margin:-1em 0 1ex 0;width: 100%;">
<label class="btn btn-default btn-xs active" onclick="set_filter('only_known');" style="float:right;">
<input type="radio" name="sw-in1" value="notall" checked> с ценами
</label>
<label class="btn btn-default btn-xs" onclick="set_filter('all');" style="float:right;">
<input type="radio" name="sw-in" value="all"> все
</label>
<span style="padding:2px 5px;font-size:12px;line-height:1.5;float:right;">Подсказывать адреса:</span>
</div>
<div class="input-group stylish-input-group">
<input type="text" class="form-control" value="{{ APP_INVITATION_STRING_IN_FORM }}"
id="addr" autocomplete="on" name="address" data-provide="typeahead"
onfocus="if(this.value=='{{ APP_INVITATION_STRING_IN_FORM }}'){this.value='';this.style.color='#000';}"
onblur= "if(this.value==''){this.value='{{ APP_INVITATION_STRING_IN_FORM }}';this.style.color='#777';}" />
<span class="input-group-addon">
<span class="glyphicon glyphicon-search"></span>
</span>
<span class="input-group-btn">
<button type="submit" class="btn btn-primary btn-add">Найти</button>
</span>
</div>
{% if LAST_VISIT %}<div><h5>Ваши последние просмотры:</h5>
<ul style="font-size:small">{% for ITEM in LAST_VISIT %}
<li><a href="{{ ITEM.LastURL }}">{{ ITEM.LastApart }} <small>({{ ITEM.LastAddress }})</small></a> <small style="font-size: xx-small;">{{ ITEM.Time }}</small></li>{% endfor %}
</ul>
</div>{% endif %}
</form>
<p></p>{% endwith %}

View File

@@ -0,0 +1,44 @@
# -*- coding: utf-8 -*-
__author__ = 'Sergei Erjemin'
from django.http import HttpResponse
from django.shortcuts import HttpResponseRedirect
from django.http import HttpRequest, HttpResponse
from oknardia.models import Building_Info
# from time import clock
import re
import urllib
def autocomplete_addr(request: HttpRequest) -> HttpResponse:
""" Функция для автозаполнения формы выбора адреса. Получает методом GET переменную "term" и по ее образцу
ищет доступные адреса в базе адреса из таблицы Building_Info
:param request: входящий http-запрос
:return response: исходящий http-ответ
"""
# Для автозаполнения используется JQuery_UI: http://jqueryui.com/
# Пример и инструкции по использованию: http://professorweb.ru/my/javascript/jquery/level4/4_5.php
#
# ВНИМАНИЕ ТЕХНИЧЕСКИЙ ДОЛГ,: Более навороченный, по описанию лучше подходящий компонент автозаполнения
# https://www.devbridge.com/sourcery/components/jquery-autocomplete/ не заработал. Ну и хрен с ним!
#
# ВНИМАНИЕ ТЕХНИЧЕСКИЙ ДОЛГ: возможен "перегрев" при частом обращении -- [Errno 10053]
# Предположительно из-за отсутсвия csrfmiddlewaretoken-серилизации Django. Проблема пофикусена(?) 2014-11-14
# tStart = clock()
if request.method == 'GET' and 'term' in request.GET:
part_blocks = re.split(r"[,/;\s.\\:]+", str(request.GET['term']))
if request.GET['use_filter'] == "only_known":
q_autocomplete = Building_Info.objects.filter(kSeria_Link__kRoot_id__isnull=False)
else:
q_autocomplete = Building_Info.objects
for i in part_blocks:
q_autocomplete = q_autocomplete.filter(sAddress__icontains=i)
q_autocomplete = q_autocomplete.all().order_by('sAddress')
to_response = ""
for i in q_autocomplete[:10]:
to_response += '"' + i.sAddress + u'",'
to_response = '[' + to_response[0:-1] + ']' # Убираем последнюю запятую
return HttpResponse(to_response)
else:
return HttpResponseRedirect("/")

View File

@@ -1,3 +1,44 @@
# -*- coding: utf-8 -*-
from django.shortcuts import render
from django.http import HttpRequest, HttpResponse
import json
import datetime
# Create your views here.
# from django.core.context_processors import csrf
def main_init(request: HttpRequest) -> HttpResponse:
""" Главная страница (статичная, только с проверками куков)
:param request: входящий http-запрос
:return response: исходящий http-ответ
"""
to_template = {} # словарь, для передачи шаблону
num_viz = 0 # как будто первый визит
template = "index.html" # шаблон
# проверяем куки числа визита
if "NumVisit" in request.COOKIES:
# стоят куки, и это не первый визит
num_viz = request.COOKIES["NumVisit"] # читаем число визитов
num_viz = int(num_viz) + 1 # увеличиваем порядковый номер визитов
# ПРОВЕРЯЧЕМ КУКИ ПРОСМОТРЕ ЦЕНОВЫХ ПРЕДЛОЖЕНИЙ
if "LastVisit" in request.COOKIES:
# стоят куки
last_visit = json.loads(request.COOKIES["LastVisit"])
last_visit2 = []
for i in last_visit:
last_visit2.append({
"Time": datetime.datetime.fromtimestamp(i["Time"]),
"LastURL": i["LastURL"],
"LastAddress": i["LastAddress"],
"LastApart": i["LastApart"]
})
to_template.update({'LAST_VISIT': last_visit2[:3]})
else:
to_template.update({'LAST_VISIT': None})
to_template.update({'META_DOCUMENT_STATE': u"Static"}) # Эта страничка статичная (в шаблон)
to_template.update({'NV': num_viz})
# to_template.update(csrf(request)) # токен, для метода POST и GET
response = render(request, template, to_template)
response.set_cookie("NumVisit", num_viz, max_age=604800) # ставим или перезаписываем куки (неделя)
return response