главный экран и автокомплит при наборе адреса на главной
This commit is contained in:
@@ -1,3 +1,4 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
"""
|
"""
|
||||||
Django settings for oknardia project.
|
Django settings for oknardia project.
|
||||||
|
|
||||||
@@ -47,6 +48,8 @@ INSTALLED_APPS = [
|
|||||||
'django.contrib.sessions',
|
'django.contrib.sessions',
|
||||||
'django.contrib.messages',
|
'django.contrib.messages',
|
||||||
'django.contrib.staticfiles',
|
'django.contrib.staticfiles',
|
||||||
|
|
||||||
|
'oknardia.apps.OknardiaConfig',
|
||||||
'web.apps.WebConfig',
|
'web.apps.WebConfig',
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -65,8 +68,7 @@ ROOT_URLCONF = 'oknardia.urls'
|
|||||||
TEMPLATES = [
|
TEMPLATES = [
|
||||||
{
|
{
|
||||||
'BACKEND': 'django.template.backends.django.DjangoTemplates',
|
'BACKEND': 'django.template.backends.django.DjangoTemplates',
|
||||||
'DIRS': [BASE_DIR / 'templates']
|
'DIRS': [BASE_DIR / 'templates'],
|
||||||
,
|
|
||||||
'APP_DIRS': True,
|
'APP_DIRS': True,
|
||||||
'OPTIONS': {
|
'OPTIONS': {
|
||||||
'context_processors': [
|
'context_processors': [
|
||||||
@@ -98,10 +100,10 @@ LANGUAGE_CODE = 'ru-RU'
|
|||||||
TIME_ZONE = 'Europe/Moscow'
|
TIME_ZONE = 'Europe/Moscow'
|
||||||
USE_I18N = True
|
USE_I18N = True
|
||||||
USE_TZ = True
|
USE_TZ = True
|
||||||
USE_L10N = False # локальный формат дат имеет приоритет
|
|
||||||
FIRST_DAY_OF_WEEK = 1 # 1'st day week -- monday
|
FIRST_DAY_OF_WEEK = 1 # 1'st day week -- monday
|
||||||
SHORT_DATE_FORMAT = '%Y-%m-%d'
|
SHORT_DATE_FORMAT = 'Y-m-d'
|
||||||
SHORT_DATETIME_FORMAT = '%Y-%m-%d %H:%M:%S'
|
SHORT_DATETIME_FORMAT = 'Y-m-d H:M:S'
|
||||||
|
DATETIME_FORMAT = 'Y-m-d H:M:S'
|
||||||
|
|
||||||
# Статические файлы (CSS, JavaScript, Images)
|
# Статические файлы (CSS, JavaScript, Images)
|
||||||
# https://docs.djangoproject.com/en/4.1/howto/static-files/
|
# 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/'
|
STATIC_URL = 'static/'
|
||||||
MEDIA_URL = 'media/'
|
MEDIA_URL = 'media/'
|
||||||
|
|
||||||
#
|
|
||||||
# https://docs.djangoproject.com/en/4.1/ref/settings/#databases
|
|
||||||
|
|
||||||
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': {
|
'default': {
|
||||||
'ENGINE': 'django.db.backends.sqlite3',
|
'ENGINE': "django.db.backends.mysql",
|
||||||
'NAME': BASE_DIR / 'db.sqlite3',
|
'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_HOST = MY_EMAIL_HOST_DEV
|
||||||
EMAIL_PORT = MY_EMAIL_PORT_DEV
|
EMAIL_PORT = MY_EMAIL_PORT_DEV
|
||||||
EMAIL_HOST_USER = MY_EMAIL_HOST_USER_DEV
|
EMAIL_HOST_USER = MY_EMAIL_HOST_USER_DEV
|
||||||
@@ -138,3 +166,93 @@ DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
|
|||||||
# ключи для Google Captha
|
# ключи для Google Captha
|
||||||
CAPTCHA_PUBLIC_KEY = MY_CAPTCHA_PUBLIC_KEY
|
CAPTCHA_PUBLIC_KEY = MY_CAPTCHA_PUBLIC_KEY
|
||||||
CAPTCHA_PRIVATE_KEY = MY_CAPTCHA_PRIVATE_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
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
"""oknardia Конфигурация URL
|
"""oknardia Конфигурация URL
|
||||||
|
|
||||||
Список `urlpatterns` направляет URL-адреса в представления. Дополнительную информацию см.:
|
Список `urlpatterns` направляет URL-адреса в представления. Дополнительную информацию см.:
|
||||||
@@ -14,8 +15,39 @@
|
|||||||
2. Добавьте URL-адрес в urlpatterns: path('blog/', include('blog.urls'))
|
2. Добавьте URL-адрес в urlpatterns: path('blog/', include('blog.urls'))
|
||||||
"""
|
"""
|
||||||
from django.contrib import admin
|
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 = [
|
urlpatterns = [
|
||||||
path('admin/', admin.site.urls),
|
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
93
oknardia/templates/base.html
Executable 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&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
62
oknardia/templates/index.html
Executable 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 %}
|
||||||
|
|
||||||
85
oknardia/templates/popup_index.html
Executable file
85
oknardia/templates/popup_index.html
Executable 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 %}
|
||||||
44
oknardia/web/autocomplete_addr.py
Executable file
44
oknardia/web/autocomplete_addr.py
Executable 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("/")
|
||||||
@@ -1,3 +1,44 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
from django.shortcuts import render
|
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
|
||||||
|
|||||||
Reference in New Issue
Block a user