1328: Этап №3 - Статистика разделов

Seems to be done. Tested localy.
remotes/origin/search
Alexander Burdeiny 10 years ago
parent e99456175f
commit a96fc8ad63
  1. 54
      conference/admin.py
  2. 3
      conference/models.py
  3. 23
      conference/urls.py
  4. 22
      conference/views.py
  5. 51
      exposition/admin.py
  6. 3
      exposition/models.py
  7. 29
      exposition/urls.py
  8. 33
      exposition/views.py
  9. 10
      functions/admin_views.py
  10. 12
      proj/admin_urls.py
  11. 4
      proj/settings.py
  12. 37
      proj/urls.py
  13. 2
      service/admin.py
  14. 0
      stats_collector/__init__.py
  15. 344
      stats_collector/admin.py
  16. 9
      stats_collector/admin_urls.py
  17. 83
      stats_collector/forms.py
  18. 0
      stats_collector/management/__init__.py
  19. 0
      stats_collector/management/commands/__init__.py
  20. 31
      stats_collector/management/commands/stats_daily.py
  21. 25
      stats_collector/management/commands/stats_hourly.py
  22. 87
      stats_collector/management/commands/stats_test.py
  23. 605
      stats_collector/migrations/0001_initial.py
  24. 0
      stats_collector/migrations/__init__.py
  25. 79
      stats_collector/mixin.py
  26. 102
      stats_collector/models.py
  27. 16
      stats_collector/tests.py
  28. 15
      stats_collector/utils.py
  29. 1
      stats_collector/views.py
  30. 44
      templates/admin/base.html
  31. 4
      templates/admin/conference/conference_list.html
  32. 2
      templates/admin/exposition/exposition_list.html
  33. 12
      templates/admin/includes/admin_nav.html
  34. 9
      templates/admin/stats/content_type_form.html
  35. 40
      templates/admin/stats/event_params_form.html
  36. 152
      templates/admin/stats/event_stat.html
  37. 191
      templates/admin/stats/section_stat.html

@ -1,26 +1,41 @@
# -*- coding: utf-8 -*-
from django.shortcuts import render_to_response
from django.http import HttpResponseRedirect, HttpResponse
from django.core.context_processors import csrf
import json
import random
from city.models import City
from django.conf import settings
from django.contrib.auth.decorators import login_required
from django.contrib.contenttypes.models import ContentType
from django.core.context_processors import csrf
from django.forms.formsets import BaseFormSet, formset_factory
from django.forms.models import modelformset_factory
from django.contrib.contenttypes.models import ContentType
from django.contrib.auth.decorators import login_required
#models and forms
from models import Conference, TimeTable, Statistic
from forms import ConferenceChangeForm, ConferenceCreateForm, ConferenceDeleteForm, TimeTableForm, StatisticForm, ConferenceFilterForm
from theme.models import Tag
from city.models import City
from django.http import HttpResponse, HttpResponseRedirect
from django.shortcuts import render_to_response
from django.utils import translation
from exposition.admin import get_by_lang
from file.forms import FileForm, FileModelForm
from file.models import FileModel, TmpFile
from file.forms import FileModelForm, FileForm
from photologue.forms import PhotoForm
#python
import random
#custom views
from functions.custom_views import objects_list, delete_object
from forms import (
ConferenceChangeForm,
ConferenceCreateForm,
ConferenceDeleteForm,
ConferenceFilterForm,
StatisticForm,
TimeTableForm
)
from functions.admin_views import (
AdminListView,
AdminView,
stat_paginate_results,
upload_photo
)
from functions.custom_views import delete_object, objects_list
from functions.views_help import get_referer
from functions.admin_views import AdminListView, AdminView, upload_photo
from haystack.query import SearchQuerySet
from models import Conference, Statistic, TimeTable
from photologue.forms import PhotoForm
from theme.models import Tag
def conference_all(request):
@ -289,6 +304,7 @@ class ConferenceView(AdminView):
class ConferenceListView(AdminListView):
paginate_func = staticmethod(stat_paginate_results)
template_name = 'admin/conference/conference_list.html'
form_class = ConferenceFilterForm
model = Conference
@ -298,10 +314,6 @@ def upload_conference_photo(request, conf_id):
return upload_photo(request, conf_id, Conference)
from django.utils import translation
from haystack.query import SearchQuerySet
import json
from exposition.admin import get_by_lang
def search_conf(request):
term = request.GET['term'].capitalize()

@ -202,6 +202,9 @@ class Conference(TranslatableModel, EventMixin, ExpoMixin):
def clicks(self):
return self.paid_new.tickets.clicks() + self.paid_new.participation.clicks() + self.paid_new.official.clicks()
def get_objectstat_views(self):
return sum(self.objectstats_set.all().values_list('value', flat=True))
class Statistic(TranslatableModel):
conference = models.ForeignKey(Conference, related_name='statistic')

@ -1,10 +1,25 @@
# -*- coding: utf-8 -*-
from django.conf.urls import patterns, include, url
from views import ConferenceDetail, ConferenceList, ConferenceByCity, ConferenceByCountry, ConferenceByTheme,\
ConferenceCountryCatalog, ConferenceCityCatalog, ConferenceTagCatalog, ConferenceThemeCatalog, ConferenceMembers,\
ConferenceVisitors, ConferenceServiceView, ConferenceThankView, ConferenceByTag, ConferencePhotoView
from django.conf.urls import include, patterns, url
from exposition.views import ExpositionSearchView
from .views import (
ConferenceByCity,
ConferenceByCountry,
ConferenceByTag,
ConferenceByTheme,
ConferenceCityCatalog,
ConferenceCountryCatalog,
ConferenceDetail,
ConferenceList,
ConferenceMembers,
ConferencePhotoView,
ConferenceServiceView,
ConferenceTagCatalog,
ConferenceThankView,
ConferenceThemeCatalog,
ConferenceVisitors
)
urlpatterns = patterns('',

@ -29,12 +29,17 @@ from note.models import Note
from service.models import Service
from service.order_forms import AdvertiseForm
from service.views import order_forms
from stats_collector.mixin import (
ConfSectionKindMixin,
ConfSectionMixin,
ObjectStatMixin
)
from theme.models import Tag, Theme
MONTHES = settings.MONTHES
class ConferenceBy(JitterCacheMixin, MetadataMixin, ListView):
class ConferenceBy(ConfSectionMixin, JitterCacheMixin, MetadataMixin, ListView):
cache_range = settings.CACHE_RANGE
template_name = 'client/conference/conference_by.html'
title1 = ''
@ -55,6 +60,7 @@ class ConferenceByCountry(ConferenceBy):
title1 = _(u'По странам')
title2 = _(u'Коференции мира по странам')
catalog = 'country/'
stat_kind = 'country'
def get_queryset(self):
return self.model.objects.conference_countries_with_count()
@ -68,6 +74,7 @@ class ConferenceByTag(ConferenceBy):
title1 = _(u'По тегам')
title2 = _(u'Коференции мира по тегам')
catalog = 'tag/'
stat_kind = 'tag'
def get_queryset(self):
return self.model.active.conference_themes_with_count()
@ -79,6 +86,7 @@ class ConferenceByTheme(ConferenceBy):
title1 = _(u'По тематикам')
title2 = _(u'Коференции мира по тематикам')
catalog = 'theme/'
stat_kind = 'theme'
def get_queryset(self):
return self.model.active.conference_themes_with_count()
@ -93,6 +101,7 @@ class ConferenceByCity(ConferenceBy):
title1 = _(u'По городам')
title2 = _(u'Коференции мира по городам')
catalog = 'city/'
stat_kind = 'city'
def get_queryset(self):
return self.model.used.conference_cities_with_count()
@ -102,7 +111,7 @@ class ConferenceByCity(ConferenceBy):
# .order_by('translations__name').distinct()
class ConferenceCatalog(JitterCacheMixin, MetadataMixin, ListView):
class ConferenceCatalog(ConfSectionKindMixin, JitterCacheMixin, MetadataMixin, ListView):
cache_range = settings.CACHE_RANGE
model = Conference
paginate_by = settings.CLIENT_PAGINATION
@ -171,6 +180,7 @@ class ConferenceCatalog(JitterCacheMixin, MetadataMixin, ListView):
class ConferenceCountryCatalog(ConferenceCatalog):
catalog_url = '/conference/country/'
stat_kind = 'country'
def get_filtered_qs(self):
#this method used in parent get_queryset
@ -189,6 +199,7 @@ class ConferenceCountryCatalog(ConferenceCatalog):
class ConferenceCityCatalog(ConferenceCatalog):
catalog_url = '/conference/city/'
stat_kind = 'city'
def get_filtered_qs(self):
#this method used in parent get_queryset
slug = self.kwargs.get('slug')
@ -209,6 +220,7 @@ class ConferenceThemeCatalog(ConferenceCatalog):
catalog_url = '/conference/theme/'
country = None
city = None
stat_kind = 'theme'
def get_filtered_qs(self):
#this method used in parent get_queryset
@ -246,6 +258,7 @@ class ConferenceThemeCatalog(ConferenceCatalog):
class ConferenceTagCatalog(ConferenceCatalog):
catalog_url = '/conference/tag/'
stat_kind = 'tag'
def get_filtered_qs(self):
#this method used in parent get_queryset
slug = self.kwargs.get('slug')
@ -308,7 +321,6 @@ class ConferenceMembers(MetadataMixin, ListView):
return context
class ConferenceThankView(MetadataMixin, DetailView):
model = Conference
slug_field = 'url'
@ -383,7 +395,7 @@ class ConferenceServiceView(FormMixin, DetailView):
return self.initial.copy()
class ConferenceDetail(JitterCacheMixin, MetadataMixin, DetailView):
class ConferenceDetail(ObjectStatMixin, JitterCacheMixin, MetadataMixin, DetailView):
cache_range = settings.CACHE_RANGE
model = Conference
slug_field = 'url'
@ -410,7 +422,7 @@ class ConferenceDetail(JitterCacheMixin, MetadataMixin, DetailView):
return context
class ConferenceList(MetadataMixin, JitterCacheMixin, ListView):
class ConferenceList(ConfSectionMixin, MetadataMixin, JitterCacheMixin, ListView):
cache_range = settings.CACHE_RANGE
model = Conference
paginate_by = settings.CLIENT_PAGINATION

@ -1,28 +1,41 @@
# -*- coding: utf-8 -*-
import json
from django.shortcuts import render_to_response
from django.http import HttpResponseRedirect, HttpResponse
from django.core.context_processors import csrf
import random
from city.models import City
from django.conf import settings
from django.contrib.auth.decorators import login_required
from django.contrib.contenttypes.models import ContentType
from django.core.context_processors import csrf
from django.forms.formsets import BaseFormSet, formset_factory
from django.forms.models import modelformset_factory
from django.contrib.contenttypes.models import ContentType
from django.contrib.auth.decorators import login_required
# models and forms
from haystack.query import SearchQuerySet
from models import Exposition, TimeTable, Statistic, TmpTimeTable
from forms import ExpositionCreateForm, ExpositionDeleteForm, TimeTableForm, StatisticForm, ExpositionFilterForm
from theme.models import Tag
from city.models import City
from django.http import HttpResponse, HttpResponseRedirect
from django.shortcuts import render_to_response
from django.utils import translation
from file.forms import FileForm, FileModelForm
from file.models import FileModel, TmpFile
from file.forms import FileModelForm, FileForm
from photologue.forms import PhotoForm
# python
import random
# custom views
from functions.custom_views import objects_list, delete_object
from forms import (
ExpositionCreateForm,
ExpositionDeleteForm,
ExpositionFilterForm,
StatisticForm,
TimeTableForm
)
from functions.admin_views import (
AdminListView,
AdminView,
stat_paginate_results,
upload_photo
)
from functions.custom_views import delete_object, objects_list
from functions.views_help import get_referer
from functions.admin_views import AdminListView, AdminView, upload_photo
from haystack.query import SearchQuerySet
from models import Exposition, Statistic, TimeTable, TmpTimeTable
from photologue.forms import PhotoForm
from theme.models import Tag
def exposition_all(request):
@ -330,6 +343,7 @@ class ExpositionView(AdminView):
return context
class ExpositionListView(AdminListView):
paginate_func = staticmethod(stat_paginate_results)
template_name = 'admin/exposition/exposition_list.html'
form_class = ExpositionFilterForm
model = Exposition
@ -347,7 +361,6 @@ def get_by_lang(item, field, lang='en'):
:return:
"""
return getattr(item, field+'_'+lang)
from django.utils import translation
def search_expo(request):
term = request.GET['term'].capitalize()

@ -290,6 +290,9 @@ class Exposition(TranslatableModel, EventMixin, ExpoMixin):
def clicks(self):
return self.paid_new.tickets.clicks() + self.paid_new.participation.clicks() + self.paid_new.official.clicks()
def get_objectstat_views(self):
return sum(self.objectstats_set.all().values_list('value', flat=True))
class Statistic(TranslatableModel):
exposition = models.ForeignKey(Exposition, related_name='statistic')

@ -1,12 +1,27 @@
# -*- coding: utf-8 -*-
from django.conf.urls import patterns, include, url
from views import ExpositionStatistic, ExpositionPrice, ExpositionProgramme, ExpositionSearchView, \
ExpositionByCountry, ExpositionByTheme, ExpositionByCity, ExpositionByTag, ExpoPhotoView
from views import ExpositionServiceView
from views import ExpoCountryCatalog, ExpoCityCatalog, ExpoThemeCatalog, ExpoTagCatalog, ExpoList, ExpoDetail,\
ExpoVisitors, ExpoMembers, ExpositionThankView
from django.conf.urls import include, patterns, url
from .views import (
ExpoCityCatalog,
ExpoCountryCatalog,
ExpoDetail,
ExpoList,
ExpoMembers,
ExpoPhotoView,
ExpositionByCity,
ExpositionByCountry,
ExpositionByTag,
ExpositionByTheme,
ExpositionPrice,
ExpositionProgramme,
ExpositionSearchView,
ExpositionServiceView,
ExpositionStatistic,
ExpositionThankView,
ExpoTagCatalog,
ExpoThemeCatalog,
ExpoVisitors
)
urlpatterns = patterns('',
url(r'^expo/add-note/(?P<slug>.*)/$', 'exposition.views.add_note'),

@ -4,6 +4,7 @@ import datetime
import json
from accounts.models import User
from article.models import Article
from city.models import City
from country.models import Country
from django.conf import settings
@ -28,21 +29,26 @@ from note.models import Note
from service.models import Service
from service.order_forms import AdvertiseForm
from service.views import order_forms
# from stats_collector.models import SectionStats
from stats_collector.mixin import (
ExpoSectionKindMixin,
ExpoSectionMixin,
ObjectStatMixin
)
from theme.models import Tag, Theme
from article.models import Article
class ExpositionBy(JitterCacheMixin, MetadataMixin, ListView):
class ExpositionBy(ExpoSectionMixin, JitterCacheMixin, MetadataMixin, ListView):
template_name = 'exposition/exposition_by.html'
title1 = ''
title2 = ''
"""
abstact class
"""
def get_context_data(self, **kwargs):
context = super(ExpositionBy, self).get_context_data(**kwargs)
context.update({'title1': self.title1, 'title2': self.title2, 'catalog': self.catalog})
return context
@ -52,6 +58,7 @@ class ExpositionByCountry(ExpositionBy):
title1 = _(u'По странам')
title2 = _(u'Выставки мира по странам')
catalog = 'country/'
stat_kind = 'country'
def get_queryset(self):
return self.model.objects.expo_countries_with_count()
@ -67,6 +74,7 @@ class ExpositionByTheme(ExpositionBy):
title1 = _(u'По тематикам')
title2 = _(u'Выставки мира по тематикам')
catalog = 'theme/'
stat_kind = 'theme'
def get_queryset(self):
return self.model.active.expo_themes_with_count()
@ -75,24 +83,26 @@ class ExpositionByTheme(ExpositionBy):
# .filter(exposition_themes__theme__isnull=False, translations__language_code=lang)\
# .order_by('translations__name').distinct()
class ExpositionByTag(ExpositionBy):
cache_range = [60*30, 60*60]
model = Tag
title1 = _(u'По тегам')
title2 = _(u'Выставки мира по тегам')
catalog = 'tag/'
stat_kind = 'tag'
def get_queryset(self):
return self.model.active.expo_themes_with_count()
class ExpositionByCity(ExpositionBy):
cache_range = [60*30, 60*60]
model = City
title1 = _(u'По городам')
title2 = _(u'Выставки мира по городам')
catalog = 'city/'
stat_kind = 'city'
def get_queryset(self):
return self.model.used.expo_cities_with_count()
@ -129,6 +139,7 @@ def exposition_add_calendar(request, id):
return HttpResponse(json.dumps(args), content_type='application/json')
def exposition_visit(request, id):
args = {'success': False}
user = request.user
@ -147,10 +158,9 @@ def exposition_visit(request, id):
args['success'] = True
return HttpResponse(json.dumps(args), content_type='application/json')
#------------------------------------------------------------------------------
class ExpoDetail(JitterCacheMixin, MetadataMixin, DetailView):
class ExpoDetail(ObjectStatMixin, JitterCacheMixin, MetadataMixin, DetailView):
cache_range = [60*30, 60*60]
model = Exposition
slug_field = 'url'
@ -243,6 +253,7 @@ def visit_redirect(request, slug):
redirect = obj.get_permanent_url() + 'price/'
return HttpResponsePermanentRedirect(redirect)
class ExpositionServiceView(JitterCacheMixin, MetadataMixin, FormMixin, DetailView):
cache_range = [60*30, 60*60]
model = Exposition
@ -313,7 +324,7 @@ class ExpositionServiceView(JitterCacheMixin, MetadataMixin, FormMixin, DetailVi
return self.initial.copy()
class ExpoList(MetadataMixin, JitterCacheMixin, ListView):
class ExpoList(ExpoSectionMixin, MetadataMixin, JitterCacheMixin, ListView):
cache_range = [60*30, 60*60]
model = Exposition
paginate_by = settings.CLIENT_PAGINATION
@ -349,8 +360,7 @@ class ExpoList(MetadataMixin, JitterCacheMixin, ListView):
return context
class ExpoCatalog(JitterCacheMixin, MetadataMixin, ListView):
class ExpoCatalog(ExpoSectionKindMixin, JitterCacheMixin, MetadataMixin, ListView):
model = Exposition
paginate_by = settings.CLIENT_PAGINATION
template_name = 'client/exposition/catalog.html'
@ -425,6 +435,7 @@ class ExpoCatalog(JitterCacheMixin, MetadataMixin, ListView):
class ExpoCountryCatalog(ExpoCatalog):
catalog_url = '/expo/country/'
stat_kind = 'country'
def get_filtered_qs(self):
#this method used in parent get_queryset
slug = self.kwargs.get('slug')
@ -442,6 +453,7 @@ class ExpoCountryCatalog(ExpoCatalog):
class ExpoCityCatalog(ExpoCatalog):
catalog_url = '/expo/city/'
stat_kind = 'city'
def get_filtered_qs(self):
#this method used in parent get_queryset
slug = self.kwargs.get('slug')
@ -450,6 +462,7 @@ class ExpoCityCatalog(ExpoCatalog):
qs = self.model.enable.upcoming().filter(city=city)
self.filter_object = city
return qs
def get_context_data(self, **kwargs):
context = super(ExpoCityCatalog, self).get_context_data(**kwargs)
city = self.kwargs['city']
@ -461,6 +474,7 @@ class ExpoCityCatalog(ExpoCatalog):
class ExpoThemeCatalog(ExpoCatalog):
template_name = 'client/exposition/catalog_theme.html'
catalog_url = '/expo/theme/'
stat_kind = 'theme'
country = None
city = None
@ -501,6 +515,7 @@ class ExpoThemeCatalog(ExpoCatalog):
class ExpoTagCatalog(ExpoCatalog):
catalog_url = '/expo/tag/'
stat_kind = 'tag'
def get_filtered_qs(self):
#this method used in parent get_queryset

@ -90,9 +90,15 @@ def paginate_results(qs, page=None):
return result
def stat_paginate_results(qs, page=None):
result = paginate_results(qs, page=page)
result.object_list = result.object_list.prefetch_related('objectstats_set')
return result
from hvad.models import TranslatableModel
class AdminListView(FormView):
paginate_func = staticmethod(paginate_results)
def get_form(self, form_class):
if self.request.GET:
@ -120,7 +126,7 @@ class AdminListView(FormView):
"""
qs = form.filter()
result = paginate_results(qs, page=self.request.GET.get('page'))
result = self.paginate_func(qs, page=self.request.GET.get('page'))
context = self.get_context_data(form=form)
context.update({'object_list': result})
return self.render_to_response(context)
@ -131,7 +137,7 @@ class AdminListView(FormView):
qs = self.model.objects.language().all().order_by('name')
else:
qs = self.model.objects.all().order_by('-modified')
result = paginate_results(qs, page=self.request.GET.get('page'))
result = self.paginate_func(qs, page=self.request.GET.get('page'))
context['object_list'] = result
return context

@ -1,9 +1,9 @@
# -*- coding: utf-8 -*-
from django.conf.urls import patterns, include, url
from proj.admin import AdminIndex
from functions import required
from django.conf.urls import include, patterns, url
from django.contrib import admin
from django.contrib.admin.views.decorators import staff_member_required
from functions import required
from proj.admin import AdminIndex
urlpatterns = required(
@ -36,6 +36,7 @@ urlpatterns = required(
url(r'^import_xls/', include('import_xls.admin_urls')),
url(r'^translator_catalog/', include('specialist_catalog.admin_urls')),
url(r'^newsletters/', include('emencia.django.newsletter.admin_urls')),
url(r'^stats/', include('stats_collector.admin_urls')),
url(r'^language/add/', 'directories.admin.language_add'),
url(r'^currency/add/', 'directories.admin.currency_add'),
@ -57,5 +58,8 @@ urlpatterns = required(
#
url(r'^ckeditor/', include('ckeditor.urls')),
url(r'^tinymce/', include('tinymce.urls')),
# url(r'^stats/', include('statsy.urls')),
)
)

@ -315,6 +315,7 @@ SOCIAL_AUTH_LINKEDIN_SCOPE = ['email']
INSTALLED_APPS = (
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
@ -325,6 +326,7 @@ INSTALLED_APPS = (
'django.contrib.sitemaps',
'haystack',
#custom modules
'stats_collector',
'emencia.django.newsletter',
'accounts',
'article',
@ -370,6 +372,8 @@ INSTALLED_APPS = (
'social.apps.django_app.default', # social auth
'core',
'specialist_catalog',
'graphos',
# 'statsy',
)
CRONJOBS = [

@ -1,12 +1,34 @@
# -*- coding: utf-8 -*-
import debug_toolbar
from core.simple_index_view import (
AboutView,
AdvertisingView,
AdvertisingViewLanding
)
from django.conf import settings
from django.conf.urls import patterns, include, url
from core.simple_index_view import AdvertisingView, AboutView, AdvertisingViewLanding
from views import MainPageView
from django.conf.urls import include, patterns, url
from django.conf.urls.static import static
from django.contrib.sitemaps import views
import debug_toolbar
from solid_i18n.urls import solid_i18n_patterns
from django.views.generic.base import TemplateView
from sitemaps import (
Additional,
BlogsSiteMap,
ConfCard,
ConfCity,
ConfCountry,
ConfTag,
ConfTheme,
ExpoCard,
ExpoCity,
ExpoCountry,
ExpoTag,
ExpoTheme,
Important,
NewsSiteMap
)
from solid_i18n.urls import solid_i18n_patterns
from views import MainPageView
class Robot(TemplateView):
template_name = 'client/robots.txt'
@ -16,8 +38,6 @@ class YandexCheck(TemplateView):
template_name = 'client/simple_pages/yandex_check.html'
from sitemaps import ExpoCard, ExpoCity, ExpoCountry, ExpoTheme, ExpoTag, ConfCard, ConfCity, ConfCountry, ConfTheme,\
ConfTag, NewsSiteMap, BlogsSiteMap, Additional, Important
sitemaps = {
@ -84,6 +104,7 @@ if settings.DEBUG:
(r'media/(?P<path>.*)',
'serve',
{'document_root': settings.MEDIA_ROOT}), )
urlpatterns += static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)
import debug_toolbar
urlpatterns += patterns('',
@ -105,5 +126,3 @@ urlpatterns += solid_i18n_patterns('',
url(r'^', include('settings.old_urls')),
url(r'^', include('accounts.user_catalog_urls')),
)

@ -130,7 +130,7 @@ class LinkedServiceUpdateView(UpdateView):
model = LinkedService
template_name = "admin/service/linked_service.html"
success_url = "/admin/service/control/all/"
def get_object(self, queryset=None):
url = self.kwargs['url']
service = get_object_or_404(Service, url=url)

@ -0,0 +1,344 @@
# from exposition.models import Exposition
import json
import operator
from datetime import date, timedelta
import numpy
import pandas
from city.models import City
# -*- coding: utf-8 -*-
# from conference.models import Conference
from country.models import Country
from django.contrib.contenttypes.models import ContentType
from django.core.serializers.json import DjangoJSONEncoder
from django.db.models import Q
from django.http import HttpResponse
from django.template.loader import render_to_string
from django.utils import timezone
from django.utils.encoding import force_text
from django.utils.translation import ugettext_lazy as _
from django.views.generic import FormView, TemplateView
from graphos.renderers import flot, gchart
from graphos.sources.model import ModelDataSource
from theme.models import Tag, Theme
from .forms import (
ByContentObjectsFilter,
DateFilter,
EventsDateFilter,
EventsParamsFilter,
event_choices,
kind_choices
)
from .models import ObjectStats, SectionStats
kind_choices_dict = dict(kind_choices)
class CustomJSEncoder(DjangoJSONEncoder):
def default(self, o):
# See "Date Time String Format" in the ECMA-262 specification.
if isinstance(o, date):
return 'Date({y}, {js_m}, {day})'.format(
y=o.year, js_m=o.month - 1, day=o.day)
else:
return super(CustomJSEncoder, self).default(o)
def pydate_to_js(o):
return 'Date({y}, {js_m}, {day})'.format(
y=o.year, js_m=o.month - 1, day=o.day)
class StatBaseView(FormView):
def get_template_names(self):
if self.request.is_ajax():
return self.ajax_template_name
return super(StatBaseView, self).get_template_names()
def after_get(self):
pass
def get(self, request, *args, **kwargs):
today = timezone.now().date()
self.qs = self.qs.filter(
created_at__gte=today - timedelta(days=7),
created_at__lt=today
)
self.after_get()
return super(StatBaseView, self).get(request, *args, **kwargs)
def form_valid(self, form):
if form.cleaned_data['date_begin']:
self.qs = self.qs.filter(created_at__gte=form.cleaned_data['date_begin'])
if form.cleaned_data['date_end']:
self.qs = self.qs.filter(created_at__lte=form.cleaned_data['date_end'])
def make_json_response(self, data):
return HttpResponse(json.dumps(data), content_type='application/json')
def get_dataframe(self):
if self.df is not None:
return self.df
self.df = pandas.DataFrame(list(self.qs))
return self.df
def get_pivot_table(self):
if self.pt is not None:
return self.pt
df = self.get_dataframe()
self.pt = df.pivot_table(values='value', index='created_at', columns=self.pt_columns, aggfunc=numpy.sum)
return self.pt
class StatSectionsView(StatBaseView):
template_name = 'admin/stats/section_stat.html'
ajax_template_name = 'admin/stats/content_type_form.html'
form_class = DateFilter
content_form_class = ByContentObjectsFilter
def get_queryset(self):
return SectionStats.objects\
.all()\
.values('created_at', 'section', 'kind', 'value', 'content_type', 'object_id')
def dispatch(self, request, *args, **kwargs):
self.qs = self.get_queryset()
self.pt = self.df = self.content_form = self.ct_choices = None
self.pt_columns = 'kind'
return super(StatSectionsView, self).dispatch(request, *args, **kwargs)
def form_valid(self, form):
super(StatSectionsView, self).form_valid(form)
if form.cleaned_data['section']:
self.qs = self.qs.filter(section=form.cleaned_data['section'])
if form.cleaned_data['kind']:
self.qs = self.qs.filter(kind=form.cleaned_data['kind'])
self.get_and_check_content_form()
if self.request.is_ajax():
data = {
'success': True,
'html': render_to_string(self.ajax_template_name, self.get_context_data())
}
return self.make_json_response(data)
return self.render_to_response(self.get_context_data(form=form))
def form_invalid(self, form):
if self.request.is_ajax():
data = {
'success': False,
'errors': form.errors
}
return self.make_json_response(data)
return super(StatSectionsView, self).form_invalid(form)
def get_ct_form(self):
form = None
check = False
pairs = self.qs\
.filter(content_type__isnull=False, object_id__isnull=False)\
.values_list('content_type', 'object_id')
if pairs:
ct_id, object_ids = zip(*pairs)
ct_id = list(set(ct_id))
object_ids = set(object_ids)
if len(ct_id) == 1:
ct_id = ct_id[0]
form_kwargs = {}
post_data = self.request.POST
ct_model = ContentType.objects.get_for_id(ct_id)
self.ct_choices = ct_model.model_class().objects.language().filter(pk__in=object_ids).values_list('pk', 'name').order_by('name')
self.ct_choices_dict = dict(self.ct_choices)
# detect if we need to validate form
content_type = post_data.get('content_type', None)
if content_type and int(content_type) == ct_id:
check = True
form_kwargs.update({
'data': post_data,
})
form_kwargs.update({
'initial': {'content_type': ct_id},
'choices': self.ct_choices,
})
form = self.content_form_class(**form_kwargs)
return form, check
def get_and_check_content_form(self):
self.content_form, check = self.get_ct_form()
if check and self.content_form.is_valid() and self.content_form.cleaned_data['ct_objects']:
self.qs = self.qs.filter(
content_type=self.content_form.cleaned_data['content_type'],
object_id__in=self.content_form.cleaned_data['ct_objects']
)
self.pt_columns = 'object_id'
def get_col_map(self):
if self.pt_columns == 'kind':
return kind_choices_dict
else:
return self.ct_choices_dict
def get_column_names(self):
col_map = self.get_col_map()
columns = [force_text(col_map[x]) for x in self.pt.columns.tolist()]
return json.dumps(columns).replace('[', '').replace(']', '')
def get_context_data(self, **kwargs):
context = super(StatSectionsView, self).get_context_data(**kwargs)
context['content_form'] = self.content_form
if self.request.is_ajax():
return context
pt = self.get_pivot_table()
# change numpy.nan values to python's None (js null with json)
# result = pt.where(pt.notnull(), None)
result = pt.fillna(value=0)
result_summary = result.sum().to_dict()
context['columns'] = self.get_column_names()
# if self.pt_columns != 'kind':
# result.columns = list(map(lambda x: str(int(x)), result.columns.tolist()))
data = list(map(
# lambda x: {'date': pydate_to_js(x[0]), 'attrs': json.dumps(x[1:]).replace('[', '').replace(']', '')},
lambda x: json.dumps(list(x), cls=CustomJSEncoder),
result.itertuples()
))
data_summary = []
for key, val in result_summary.items():
data_summary.append({
'name': self.get_col_map()[key],
'val': val
})
context['data'] = data
context['data_summary'] = data_summary
return context
class EventStatView(StatBaseView):
form_class = EventsDateFilter
params_form_cls = EventsParamsFilter
pt_columns = ['content_type', 'object_id']
template_name = 'admin/stats/event_stat.html'
def get_queryset(self):
return ObjectStats.objects\
.all()\
.select_related()\
.values('created_at', 'value')
def dispatch(self, request, *args, **kwargs):
self.qs = self.get_queryset()
self.pt = self.df = self.params_form = None
return super(EventStatView, self).dispatch(request, *args, **kwargs)
def after_get(self):
self.params_form = self.get_params_form()
def form_valid(self, form):
super(EventStatView, self).form_valid(form)
self.event_types = ['conference', 'exposition']
if form.cleaned_data['event']:
params = {'{attr}_id__isnull'.format(attr=form.cleaned_data['event']): False}
self.qs = self.qs.filter(**params)
self.event_types = [form.cleaned_data['event'], ]
self.params_form = self.get_params_form()
self.check_params_form()
return self.render_to_response(self.get_context_data(form=form))
def get_params_form(self):
country_ids = set()
city_ids = set()
theme_ids = set()
tag_ids = set()
val_list = [
'exposition__country',
'conference__country',
'exposition__city',
'conference__city',
'exposition__theme',
'conference__theme',
'exposition__tag',
'conference__tag',
]
e_country_ids, c_country_ids, e_city_ids, c_city_ids, e_theme_ids, c_theme_ids, e_tag_ids, c_tag_ids = \
zip(*self.qs.values_list(*val_list))
country_ids.update(e_country_ids)
country_ids.update(c_country_ids)
city_ids.update(e_city_ids)
city_ids.update(c_city_ids)
theme_ids.update(e_theme_ids)
theme_ids.update(e_theme_ids)
tag_ids.update(e_tag_ids)
tag_ids.update(c_tag_ids)
for ids_set in [country_ids, city_ids, theme_ids, tag_ids]:
if None in ids_set:
ids_set.remove(None)
form_kwargs = {
'country_choices': Country.objects.language().filter(pk__in=country_ids).values_list('pk', 'name').order_by('name'),
'city_choices': City.objects.language().filter(pk__in=city_ids).values_list('pk', 'name').order_by('name'),
'theme_choices': Theme.objects.language().filter(pk__in=theme_ids).values_list('pk', 'name').order_by('name'),
'tag_choices': Tag.objects.language().filter(pk__in=tag_ids).values_list('pk', 'name').order_by('name'),
'data': self.request.POST
}
form = self.params_form_cls(**form_kwargs)
return form
def check_params_form(self):
if self.params_form.is_valid():
query = []
for event_type in self.event_types:
params = {}
if self.params_form.cleaned_data['country']:
params.update({
event_type + '__country_id__in': self.params_form.cleaned_data['country']
})
if self.params_form.cleaned_data['city']:
params.update({
event_type + '__city_id__in': self.params_form.cleaned_data['city']
})
if self.params_form.cleaned_data['theme']:
params.update({
event_type + '__theme__in': self.params_form.cleaned_data['theme']
})
if self.params_form.cleaned_data['tag']:
params.update({
event_type + '__tag__in': self.params_form.cleaned_data['tag']
})
query.append(Q(**params))
if len(query) == 1:
self.qs = self.qs.filter(query[0])
else:
self.qs = self.qs.filter(reduce(operator.or_, query))
def get_context_data(self, **kwargs):
context = super(EventStatView, self).get_context_data(**kwargs)
context['params_form'] = self.params_form
if self.qs:
df = self.get_dataframe()
pt = df.pivot_table(values='value', index='created_at', aggfunc=numpy.sum)
result = pt.fillna(value=0)
data = list(map(
lambda x: json.dumps(list(x), cls=CustomJSEncoder),
result.iteritems()
))
context['data'] = data
context['data_summary'] = int(result.sum())
return context

@ -0,0 +1,9 @@
# -*- coding: utf-8 -*-
from django.conf.urls import include, patterns, url
from .admin import StatSectionsView, EventStatView
urlpatterns = patterns('',
url(r'^events/$', EventStatView.as_view()),
url(r'^$', StatSectionsView.as_view()),
)

@ -0,0 +1,83 @@
# -*- coding: utf-8 -*-
from datetime import timedelta
from conference.models import Conference
from django import forms
from django.contrib.contenttypes.models import ContentType
from django.utils.translation import ugettext_lazy as _
from exposition.models import Exposition
_all = (('', _(u'Все')), )
section_choices = (
('expo', _(u'Конференции')),
('conf', _(u'Выставки')),
)
kind_choices = (
('city', _(u'Город')),
('country', _(u'Страна')),
('tag', _(u'Тег')),
('theme', _(u'Тема')),
)
class BaseDateFilter(forms.Form):
date_begin = forms.DateField(label=_(u'Дата начала'), input_formats=['%Y-%m-%d', '%d.%m.%Y'], required=False)
date_end = forms.DateField(label=_(u'Дата окончания'), input_formats=['%Y-%m-%d', '%d.%m.%Y'], required=False)
def clean(self):
if not self.cleaned_data['date_begin'] and self.cleaned_data['date_end']:
self.cleaned_data['date_begin'] = self.cleaned_data['date_end'] - timedelta(days=14)
return self.cleaned_data
class DateFilter(BaseDateFilter):
section = forms.ChoiceField(label=_(u'Раздел'), choices=_all + section_choices, required=False)
kind = forms.ChoiceField(label=_(u'Тип'), choices=_all + kind_choices, required=False)
class ByContentObjectsFilter(forms.Form):
content_type = forms.IntegerField(label=_(u'Тип объекта'), widget=forms.HiddenInput(), required=False)
ct_objects = forms.TypedMultipleChoiceField(label=_(u'Объект'), required=False, coerce=int)
def __init__(self, *args, **kwargs):
choices = kwargs.pop('choices')
super(ByContentObjectsFilter, self).__init__(*args, **kwargs)
self.fields['ct_objects'].choices = choices
def clean_content_type(self):
pk = self.cleaned_data['content_type']
if pk:
return ContentType.objects.get_for_id(pk)
return None
event_choices = (
('conference', _(u'Конференции')),
('exposition', _(u'Выставки'))
)
class EventsDateFilter(BaseDateFilter):
event = forms.ChoiceField(label=_(u'Событие'), choices=_all + event_choices, required=False)
class EventsParamsFilter(forms.Form):
country = forms.TypedMultipleChoiceField(label=_(u'Страна'), required=False, coerce=int)
city = forms.TypedMultipleChoiceField(label=_(u'Город'), required=False, coerce=int)
theme = forms.TypedMultipleChoiceField(label=_(u'Тема'), required=False, coerce=int)
tag = forms.TypedMultipleChoiceField(label=_(u'Тег'), required=False, coerce=int)
def __init__(self, *args, **kwargs):
country_choices = kwargs.pop('country_choices')
city_choices = kwargs.pop('city_choices')
theme_choices = kwargs.pop('theme_choices')
tag_choices = kwargs.pop('tag_choices')
super(EventsParamsFilter, self).__init__(*args, **kwargs)
self.fields['country'].choices = country_choices
self.fields['city'].choices = city_choices
self.fields['theme'].choices = theme_choices
self.fields['tag'].choices = tag_choices

@ -0,0 +1,31 @@
# -*- coding: utf-8 -*-
from optparse import make_option
from datetime import timedelta
from django.core.cache import cache
from django.core.management.base import BaseCommand
from django.utils import timezone
from stats_collector.models import ObjectStats, SectionStats
from stats_collector.utils import unique_items_iterator
class Command(BaseCommand):
def handle(self, *args, **options):
prev_day = timezone.now().date() - timedelta(days=1)
for model in [ObjectStats, SectionStats]:
key = model.make_key(prev_day)
# pop items from redis
l = cache._client.lrange(key, 0, -1)
cache._client.ltrim(key, len(l), -1)
unique_items = {}
for key, val in unique_items_iterator(l):
_val = unique_items.get(key, 0)
unique_items[key] = _val + val
if unique_items:
model_objects = []
for k, v in unique_items.items():
model_objects.append(model.create_instance(*k + (v, ), created_at=prev_day))
model.objects.bulk_create(model_objects)

@ -0,0 +1,25 @@
# -*- coding: utf-8 -*-
from optparse import make_option
from django.core.management.base import BaseCommand
from django.core.cache import cache
from stats_collector.models import ObjectStats, SectionStats
from stats_collector.utils import unique_items_iterator
class Command(BaseCommand):
def handle(self, *args, **options):
pipe = cache._client.pipeline()
for model in [ObjectStats, SectionStats]:
key = model.make_key()
# pop items from redis
l = cache._client.lrange(key, 0, -1)
# cache._client.ltrim(key, len(l), -1)
pipe.ltrim(key, len(l), -1)
unique_items = {}
for k, v in unique_items_iterator(l):
_val = unique_items.get(k, 0)
unique_items[k] = _val + v
for k, v in unique_items.items():
pipe.rpush(key, model.dump_item(k + (v,)))
pipe.execute()

@ -0,0 +1,87 @@
# -*- coding: utf-8 -*-
from datetime import timedelta
from optparse import make_option
from random import randint
from city.models import City
from conference.models import Conference
from country.models import Country
from django.contrib.contenttypes.models import ContentType
from django.core.cache import cache
from django.core.management.base import BaseCommand
from django.db.models.fields import related
from django.utils import timezone
from exposition.models import Exposition
from stats_collector.models import ObjectStats, SectionStats
from stats_collector.utils import unique_items_iterator
from theme.models import Tag, Theme
today = timezone.now().date()
class Command(BaseCommand):
def handle(self, *args, **options):
self.create_section_test_data()
self.create_objects_test_data()
def create_section_test_data(self):
total_objects = [Conference.objects.all()[:30], Exposition.objects.all()[:30]]
bulk_objects = []
for day in xrange(92):
date = today - timedelta(days=day)
for model, field in [(City, 'city'), (Country, 'country'), (Theme, 'theme'), (Tag, 'tag')]:
for _objects in total_objects:
obj = _objects[randint(0, 29)]
field_value = getattr(obj, field)
if isinstance(obj._meta.get_field_by_name(field)[0], related.ManyToManyField):
_field_value = field_value.all()
if len(_field_value) == 0:
continue
field_value = _field_value[randint(0, len(_field_value) - 1)]
bulk_objects.append(
SectionStats(
section=obj.__class__.__name__.lower()[:4],
kind=field,
content_object=field_value,
created_at=date,
value=randint(11, 898),
)
)
bulk_objects.append(
SectionStats(
section=obj.__class__.__name__.lower()[:4],
kind=field,
created_at=date,
value=randint(11, 898),
)
)
bulk_objects.append(
SectionStats(
section=obj.__class__.__name__.lower()[:4],
created_at=date,
value=randint(11, 898),
)
)
SectionStats.objects.bulk_create(bulk_objects)
def create_objects_test_data(self):
total_objects = {
'conference': Conference.objects.all()[:30],
'exposition': Exposition.objects.all()[:30]
}
bulk_objects = []
for day in xrange(92):
date = today - timedelta(days=day)
# for model, field in [(City, 'city'), (Country, 'country'), (Theme, 'theme'), (Tag, 'tag')]:
for attr, _objects in total_objects.items():
for obj in _objects:
bulk_objects.append(
ObjectStats(
created_at=date,
value=randint(11, 898),
**{attr: obj}
)
)
ObjectStats.objects.bulk_create(bulk_objects)

@ -0,0 +1,605 @@
# -*- coding: utf-8 -*-
from south.utils import datetime_utils as datetime
from south.db import db
from south.v2 import SchemaMigration
from django.db import models
class Migration(SchemaMigration):
def forwards(self, orm):
# Adding model 'SectionStats'
db.create_table(u'stats_collector_sectionstats', (
(u'id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
('created_at', self.gf('django.db.models.fields.DateField')(db_index=True, null=True, blank=True)),
('value', self.gf('django.db.models.fields.PositiveIntegerField')(null=True, blank=True)),
('content_type', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['contenttypes.ContentType'], null=True, blank=True)),
('object_id', self.gf('django.db.models.fields.IntegerField')(null=True, blank=True)),
('section', self.gf('django.db.models.fields.CharField')(max_length=32, null=True, blank=True)),
('kind', self.gf('django.db.models.fields.CharField')(max_length=64, null=True, blank=True)),
))
db.send_create_signal(u'stats_collector', ['SectionStats'])
# Adding index on 'SectionStats', fields ['content_type', 'object_id']
db.create_index(u'stats_collector_sectionstats', ['content_type_id', 'object_id'])
# Adding model 'ObjectStats'
db.create_table(u'stats_collector_objectstats', (
(u'id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
('created_at', self.gf('django.db.models.fields.DateField')(db_index=True, null=True, blank=True)),
('value', self.gf('django.db.models.fields.PositiveIntegerField')(null=True, blank=True)),
('exposition', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['exposition.Exposition'], null=True, blank=True)),
('conference', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['conference.Conference'], null=True, blank=True)),
))
db.send_create_signal(u'stats_collector', ['ObjectStats'])
def backwards(self, orm):
# Removing index on 'SectionStats', fields ['content_type', 'object_id']
db.delete_index(u'stats_collector_sectionstats', ['content_type_id', 'object_id'])
# Deleting model 'SectionStats'
db.delete_table(u'stats_collector_sectionstats')
# Deleting model 'ObjectStats'
db.delete_table(u'stats_collector_objectstats')
models = {
u'accounts.user': {
'Meta': {'ordering': "['-rating']", 'object_name': 'User'},
'blocked': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'company': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'users'", 'null': 'True', 'to': u"orm['company.Company']"}),
'date_joined': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
'date_modified': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}),
'date_registered': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
'email': ('django.db.models.fields.EmailField', [], {'max_length': '255', 'db_index': 'True'}),
'first_name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'is_admin': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
'last_name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
'organiser': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['organiser.Organiser']", 'unique': 'True', 'null': 'True', 'on_delete': 'models.PROTECT', 'blank': 'True'}),
'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
'position': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}),
'rating': ('django.db.models.fields.IntegerField', [], {'default': '100'}),
'translator': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'user'", 'null': 'True', 'on_delete': 'models.PROTECT', 'to': u"orm['translator.Translator']", 'blank': 'True', 'unique': 'True'}),
'url': ('django.db.models.fields.SlugField', [], {'max_length': '50', 'blank': 'True'}),
'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}),
'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255', 'db_index': 'True'})
},
u'auth.group': {
'Meta': {'object_name': 'Group'},
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
},
u'auth.permission': {
'Meta': {'ordering': "(u'content_type__app_label', u'content_type__model', u'codename')", 'unique_together': "((u'content_type', u'codename'),)", 'object_name': 'Permission'},
'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['contenttypes.ContentType']"}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
},
u'city.city': {
'Meta': {'unique_together': '()', 'object_name': 'City', 'index_together': '()'},
'code_IATA': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['directories.Iata']", 'null': 'True', 'blank': 'True'}),
'country': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'cities'", 'null': 'True', 'on_delete': 'models.PROTECT', 'to': u"orm['country.Country']"}),
'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'inflect': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}),
'logo': ('django.db.models.fields.files.ImageField', [], {'max_length': '255', 'blank': 'True'}),
'modified': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}),
'old_url': ('django.db.models.fields.CharField', [], {'max_length': '55'}),
'phone_code': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True', 'blank': 'True'}),
'population': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True', 'blank': 'True'}),
'services': ('django.db.models.fields.BigIntegerField', [], {'default': 'None'}),
'url': ('django.db.models.fields.SlugField', [], {'unique': 'True', 'max_length': '50'})
},
u'company.company': {
'Meta': {'ordering': "['-rating', 'id']", 'unique_together': '()', 'object_name': 'Company', 'index_together': '()'},
'address': ('functions.custom_fields.LocationField', [], {'blank': 'True'}),
'blocked': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'city': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'companies'", 'null': 'True', 'on_delete': 'models.PROTECT', 'to': u"orm['city.City']"}),
'country': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'companies'", 'null': 'True', 'on_delete': 'models.PROTECT', 'to': u"orm['country.Country']"}),
'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
'creator': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'created_company'", 'null': 'True', 'to': u"orm['accounts.User']"}),
'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
'facebook': ('django.db.models.fields.URLField', [], {'max_length': '200', 'blank': 'True'}),
'fax': ('django.db.models.fields.BigIntegerField', [], {'null': 'True', 'blank': 'True'}),
'foundation': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True', 'blank': 'True'}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'linkedin': ('django.db.models.fields.URLField', [], {'max_length': '200', 'blank': 'True'}),
'logo': ('django.db.models.fields.files.ImageField', [], {'max_length': '100', 'blank': 'True'}),
'modified': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}),
'phone': ('django.db.models.fields.BigIntegerField', [], {'null': 'True', 'blank': 'True'}),
'rating': ('django.db.models.fields.IntegerField', [], {'default': '100'}),
'staff_number': ('django.db.models.fields.CharField', [], {'max_length': '50', 'blank': 'True'}),
'tag': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'companies'", 'null': 'True', 'symmetrical': 'False', 'to': u"orm['theme.Tag']"}),
'theme': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'companies'", 'null': 'True', 'symmetrical': 'False', 'to': u"orm['theme.Theme']"}),
'twitter': ('django.db.models.fields.URLField', [], {'max_length': '200', 'blank': 'True'}),
'url': ('django.db.models.fields.SlugField', [], {'max_length': '255'}),
'vk': ('django.db.models.fields.URLField', [], {'max_length': '200', 'blank': 'True'}),
'web_page': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'})
},
u'conference.conference': {
'Meta': {'unique_together': '()', 'object_name': 'Conference', 'index_together': '()'},
'audience': ('django.db.models.fields.BigIntegerField', [], {'default': 'None'}),
'canceled': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'canceled_by_administrator': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'city': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'conference_city'", 'on_delete': 'models.PROTECT', 'to': u"orm['city.City']"}),
'company': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'conference_companies'", 'null': 'True', 'symmetrical': 'False', 'to': u"orm['company.Company']"}),
'country': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'conference_country'", 'on_delete': 'models.PROTECT', 'to': u"orm['country.Country']"}),
'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
'currency': ('functions.custom_fields.EnumField', [], {'default': "'RUB'", 'values': "('RUB', 'USD', 'EUR', 'RMB', 'GBP', 'AED', 'SGD', 'TRY', 'CZK', 'CHF', 'SEK', 'LKR', 'UAH', 'IDR', 'PLN', 'JPY')"}),
'data_begin': ('django.db.models.fields.DateField', [], {}),
'data_end': ('django.db.models.fields.DateField', [], {}),
'discount': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True', 'blank': 'True'}),
'expohit': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'foundation_year': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True', 'blank': 'True'}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'is_published': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'link': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}),
'logo': ('django.db.models.fields.files.ImageField', [], {'max_length': '100', 'blank': 'True'}),
'main': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['expobanner.MainPage']", 'null': 'True', 'on_delete': 'models.SET_NULL', 'blank': 'True'}),
'main_page': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0', 'db_index': 'True'}),
'max_price': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True', 'blank': 'True'}),
'members': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True', 'blank': 'True'}),
'min_price': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True', 'blank': 'True'}),
'modified': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}),
'moved': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'old_url': ('django.db.models.fields.SlugField', [], {'unique': 'True', 'max_length': '255'}),
'org': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
'organiser': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'conference_organisers'", 'null': 'True', 'symmetrical': 'False', 'to': u"orm['organiser.Organiser']"}),
'paid_new': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['expobanner.Paid']", 'null': 'True', 'on_delete': 'models.SET_NULL', 'blank': 'True'}),
'periodic': ('django.db.models.fields.FloatField', [], {'null': 'True', 'blank': 'True'}),
'photogallery': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['photologue.Gallery']", 'null': 'True', 'on_delete': 'models.SET_NULL', 'blank': 'True'}),
'place': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'conference_place'", 'null': 'True', 'on_delete': 'models.PROTECT', 'to': u"orm['place_conference.PlaceConference']"}),
'place_alt': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
'quality_label': ('django.db.models.fields.BigIntegerField', [], {'default': 'None'}),
'rating': ('django.db.models.fields.IntegerField', [], {'default': '0', 'db_index': 'True'}),
'services': ('django.db.models.fields.BigIntegerField', [], {'default': 'None'}),
'tag': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'conference_tags'", 'null': 'True', 'symmetrical': 'False', 'to': u"orm['theme.Tag']"}),
'tax': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
'theme': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'conference_themes'", 'symmetrical': 'False', 'to': u"orm['theme.Theme']"}),
'url': ('django.db.models.fields.SlugField', [], {'unique': 'True', 'max_length': '255'}),
'users': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'conference_users'", 'null': 'True', 'symmetrical': 'False', 'to': u"orm['accounts.User']"}),
'views': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
'visitors': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True', 'blank': 'True'}),
'web_page': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'})
},
u'contenttypes.contenttype': {
'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
},
u'country.area': {
'Meta': {'ordering': "['translations__name']", 'unique_together': '()', 'object_name': 'Area', 'index_together': '()'},
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'})
},
u'country.country': {
'Meta': {'ordering': "['translations__name']", 'unique_together': '()', 'object_name': 'Country', 'index_together': '()'},
'area': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['country.Area']"}),
'big_cities': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'cities'", 'null': 'True', 'symmetrical': 'False', 'to': u"orm['city.City']"}),
'capital': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'capital'", 'null': 'True', 'on_delete': 'models.PROTECT', 'to': u"orm['city.City']"}),
'country_code': ('django.db.models.fields.CharField', [], {'max_length': '2'}),
'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
'currency': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'to': u"orm['directories.Currency']", 'null': 'True', 'blank': 'True'}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'inflect': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}),
'language': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'to': u"orm['directories.Language']", 'null': 'True', 'blank': 'True'}),
'latitude': ('django.db.models.fields.FloatField', [], {'null': 'True', 'blank': 'True'}),
'logo': ('django.db.models.fields.files.ImageField', [], {'max_length': '255', 'blank': 'True'}),
'longitude': ('django.db.models.fields.FloatField', [], {'null': 'True', 'blank': 'True'}),
'modified': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}),
'old_url': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '55'}),
'phone_code': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True', 'blank': 'True'}),
'population': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True', 'blank': 'True'}),
'services': ('django.db.models.fields.BigIntegerField', [], {'default': 'None'}),
'teritory': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True', 'blank': 'True'}),
'time_delivery': ('django.db.models.fields.PositiveSmallIntegerField', [], {'null': 'True', 'blank': 'True'}),
'timezone': ('django.db.models.fields.FloatField', [], {'null': 'True', 'blank': 'True'}),
'url': ('django.db.models.fields.SlugField', [], {'unique': 'True', 'max_length': '50'})
},
u'directories.currency': {
'Meta': {'unique_together': '()', 'object_name': 'Currency', 'index_together': '()'},
'code': ('django.db.models.fields.CharField', [], {'max_length': '3'}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'})
},
u'directories.iata': {
'Meta': {'object_name': 'Iata'},
'airport': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
'code': ('django.db.models.fields.CharField', [], {'max_length': '4'}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'})
},
u'directories.language': {
'Meta': {'unique_together': '()', 'object_name': 'Language', 'index_together': '()'},
'code': ('django.db.models.fields.CharField', [], {'max_length': '2'}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'language': ('django.db.models.fields.CharField', [], {'max_length': '255'})
},
u'expobanner.banner': {
'Meta': {'ordering': "['sort']", 'object_name': 'Banner'},
'alt': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
'cookie': ('django.db.models.fields.CharField', [], {'default': "'expo_b_default_popup'", 'max_length': '30', 'null': 'True', 'blank': 'True'}),
'country': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'to': u"orm['country.Country']", 'null': 'True', 'blank': 'True'}),
'created_at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
'flash': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'fr': ('django.db.models.fields.DateField', [], {'default': 'datetime.datetime(2016, 5, 18, 0, 0)'}),
'group': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'banners'", 'null': 'True', 'to': u"orm['expobanner.BannerGroup']"}),
'html': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'img': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}),
'link': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'often': ('django.db.models.fields.PositiveSmallIntegerField', [], {'default': '1'}),
'paid': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'popup': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'public': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
'sort': ('django.db.models.fields.PositiveSmallIntegerField', [], {'default': '500'}),
'stat_pswd': ('django.db.models.fields.CharField', [], {'max_length': '16'}),
'text': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
'theme': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'to': u"orm['theme.Theme']", 'null': 'True', 'blank': 'True'}),
'title': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}),
'to': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
'updated_at': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}),
'url': ('django.db.models.fields.CharField', [], {'max_length': '1024'}),
'urls': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'url_banners'", 'null': 'True', 'symmetrical': 'False', 'to': u"orm['expobanner.URL']"})
},
u'expobanner.bannergroup': {
'Meta': {'ordering': "['name']", 'object_name': 'BannerGroup'},
'created_at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
'height': ('django.db.models.fields.PositiveSmallIntegerField', [], {'default': '0'}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
'public': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
'slug': ('django.db.models.fields.SlugField', [], {'unique': 'True', 'max_length': '50'}),
'speed': ('django.db.models.fields.PositiveSmallIntegerField', [], {'default': '2000'}),
'updated_at': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}),
'width': ('django.db.models.fields.PositiveSmallIntegerField', [], {'default': '0'})
},
u'expobanner.mainpage': {
'Meta': {'ordering': "['-public']", 'object_name': 'MainPage'},
'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'link': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['expobanner.Banner']"}),
'modified': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}),
'position': ('django.db.models.fields.PositiveIntegerField', [], {'default': '2', 'null': 'True', 'blank': 'True'}),
'public': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
'stat_pswd': ('django.db.models.fields.CharField', [], {'max_length': '16'})
},
u'expobanner.paid': {
'Meta': {'ordering': "['-public']", 'object_name': 'Paid'},
'catalog': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'paid_catalog'", 'to': u"orm['expobanner.Banner']"}),
'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'kind': ('django.db.models.fields.PositiveSmallIntegerField', [], {'default': '1', 'db_index': 'True'}),
'logo': ('django.db.models.fields.files.ImageField', [], {'max_length': '100', 'blank': 'True'}),
'modified': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}),
'official': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'paid_official'", 'to': u"orm['expobanner.Banner']"}),
'organiser': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),
'participation': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'paid_participation'", 'to': u"orm['expobanner.Banner']"}),
'public': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
'stat_pswd': ('django.db.models.fields.CharField', [], {'max_length': '16'}),
'tickets': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'paid_tickets'", 'to': u"orm['expobanner.Banner']"})
},
u'expobanner.top': {
'Meta': {'ordering': "['position']", 'object_name': 'Top'},
'catalog': ('django.db.models.fields.CharField', [], {'max_length': '16'}),
'cities': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'top_in_set'", 'null': 'True', 'symmetrical': 'False', 'to': u"orm['city.City']"}),
'country': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'to': u"orm['country.Country']", 'null': 'True', 'blank': 'True'}),
'excluded_cities': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'to': u"orm['city.City']", 'null': 'True', 'blank': 'True'}),
'excluded_tags': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'to': u"orm['theme.Tag']", 'null': 'True', 'blank': 'True'}),
'fr': ('django.db.models.fields.DateField', [], {'default': 'datetime.datetime(2016, 5, 18, 0, 0)'}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'link': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['expobanner.Banner']"}),
'months': ('functions.custom_fields.MonthMultiSelectField', [], {'default': 'None', 'max_length': '255', 'null': 'True', 'blank': 'True'}),
'position': ('django.db.models.fields.PositiveIntegerField', [], {'default': '2', 'null': 'True', 'blank': 'True'}),
'stat_pswd': ('django.db.models.fields.CharField', [], {'max_length': '16'}),
'theme': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'to': u"orm['theme.Theme']", 'null': 'True', 'blank': 'True'}),
'to': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
'years': ('django.db.models.fields.PositiveSmallIntegerField', [], {'default': 'None', 'null': 'True', 'blank': 'True'})
},
u'expobanner.url': {
'Meta': {'ordering': "['-created_at']", 'object_name': 'URL'},
'created_at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'public': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
'regex': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'sites': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'site_urls'", 'null': 'True', 'symmetrical': 'False', 'to': u"orm['sites.Site']"}),
'title': ('django.db.models.fields.CharField', [], {'max_length': '256'}),
'updated_at': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}),
'url': ('django.db.models.fields.CharField', [], {'max_length': '2048'})
},
u'exposition.exposition': {
'Meta': {'unique_together': '()', 'object_name': 'Exposition', 'index_together': '()'},
'application_deadline': ('django.db.models.fields.DateField', [], {'null': 'True'}),
'area': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True', 'blank': 'True'}),
'audience': ('django.db.models.fields.BigIntegerField', [], {'default': 'None'}),
'canceled': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'canceled_by_administrator': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'city': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'exposition_city'", 'on_delete': 'models.PROTECT', 'to': u"orm['city.City']"}),
'company': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'exposition_companies'", 'null': 'True', 'symmetrical': 'False', 'to': u"orm['company.Company']"}),
'country': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'exposition_country'", 'on_delete': 'models.PROTECT', 'to': u"orm['country.Country']"}),
'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
'creator': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'exposition_creator'", 'null': 'True', 'on_delete': 'models.SET_NULL', 'to': u"orm['accounts.User']"}),
'currency': ('functions.custom_fields.EnumField', [], {'default': "'RUB'", 'values': "('RUB', 'USD', 'EUR', 'RMB', 'GBP', 'AED', 'SGD', 'TRY', 'CZK', 'CHF', 'SEK', 'LKR', 'UAH', 'IDR', 'PLN', 'JPY')"}),
'data_begin': ('django.db.models.fields.DateField', [], {}),
'data_end': ('django.db.models.fields.DateField', [], {}),
'discount': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True', 'blank': 'True'}),
'expohit': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'foundation_year': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True', 'blank': 'True'}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'is_published': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'logo': ('django.db.models.fields.files.ImageField', [], {'max_length': '100', 'blank': 'True'}),
'main': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['expobanner.MainPage']", 'null': 'True', 'on_delete': 'models.SET_NULL', 'blank': 'True'}),
'main_page': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0', 'db_index': 'True'}),
'max_closed_area': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True', 'blank': 'True'}),
'max_closed_equipped_area': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True', 'blank': 'True'}),
'max_open_area': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True', 'blank': 'True'}),
'members': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True', 'blank': 'True'}),
'min_area': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True', 'blank': 'True'}),
'min_closed_area': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True', 'blank': 'True'}),
'min_closed_equipped_area': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True', 'blank': 'True'}),
'min_open_area': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True', 'blank': 'True'}),
'min_stand_size': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True', 'blank': 'True'}),
'modified': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}),
'moved': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'old_url': ('django.db.models.fields.SlugField', [], {'unique': 'True', 'max_length': '255'}),
'org': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
'organiser': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'exposition_organisers'", 'null': 'True', 'symmetrical': 'False', 'to': u"orm['organiser.Organiser']"}),
'paid_new': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['expobanner.Paid']", 'null': 'True', 'on_delete': 'models.SET_NULL', 'blank': 'True'}),
'periodic': ('django.db.models.fields.FloatField', [], {'null': 'True', 'blank': 'True'}),
'photogallery': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['photologue.Gallery']", 'null': 'True', 'on_delete': 'models.SET_NULL', 'blank': 'True'}),
'place': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'exposition_place'", 'null': 'True', 'on_delete': 'models.PROTECT', 'to': u"orm['place_exposition.PlaceExposition']"}),
'place_alt': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
'price_catalog': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True', 'blank': 'True'}),
'quality_label': ('django.db.models.fields.BigIntegerField', [], {'default': 'None'}),
'rating': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
'registration_link': ('django.db.models.fields.URLField', [], {'max_length': '255', 'blank': 'True'}),
'registration_payment': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True', 'blank': 'True'}),
'services': ('django.db.models.fields.BigIntegerField', [], {'default': 'None'}),
'tag': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'exposition_tags'", 'null': 'True', 'symmetrical': 'False', 'to': u"orm['theme.Tag']"}),
'tax': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
'theme': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'exposition_themes'", 'symmetrical': 'False', 'to': u"orm['theme.Theme']"}),
'top': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['expobanner.Top']", 'null': 'True', 'on_delete': 'models.SET_NULL', 'blank': 'True'}),
'url': ('django.db.models.fields.SlugField', [], {'unique': 'True', 'max_length': '255'}),
'users': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'exposition_users'", 'null': 'True', 'symmetrical': 'False', 'to': u"orm['accounts.User']"}),
'views': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
'visitors': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True', 'blank': 'True'}),
'web_page': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'})
},
u'file.filemodel': {
'Meta': {'unique_together': '()', 'object_name': 'FileModel', 'index_together': '()'},
'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['contenttypes.ContentType']", 'null': 'True'}),
'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
'file_path': ('django.db.models.fields.files.FileField', [], {'max_length': '100'}),
'file_type': ('functions.custom_fields.EnumField', [], {'default': "'PDF'", 'values': "('PDF', 'DOC', 'TXT', 'OTHER', 'JPG', 'BMP', 'PNG', 'GIF')", 'blank': 'True'}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'img_height': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True', 'blank': 'True'}),
'img_width': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True', 'blank': 'True'}),
'modified': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}),
'object_id': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True', 'blank': 'True'}),
'purpose': ('functions.custom_fields.EnumField', [], {'default': "'photo'", 'values': "['photo', 'flat', 'logo', 'map', 'scheme teritory', 'diplom', 'preview', 'preview2']"})
},
u'note.note': {
'Meta': {'object_name': 'Note'},
'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['contenttypes.ContentType']", 'null': 'True'}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'object_id': ('django.db.models.fields.PositiveIntegerField', [], {}),
'text': ('django.db.models.fields.TextField', [], {}),
'user': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['accounts.User']"})
},
u'organiser.organiser': {
'Meta': {'unique_together': '()', 'object_name': 'Organiser', 'index_together': '()'},
'active': ('django.db.models.fields.NullBooleanField', [], {'default': '0', 'null': 'True', 'blank': 'True'}),
'address': ('functions.custom_fields.LocationField', [], {'null': 'True', 'blank': 'True'}),
'city': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['city.City']", 'null': 'True', 'on_delete': 'models.PROTECT', 'blank': 'True'}),
'country': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['country.Country']", 'null': 'True', 'on_delete': 'models.PROTECT', 'blank': 'True'}),
'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
'events_number': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True', 'blank': 'True'}),
'facebook': ('django.db.models.fields.URLField', [], {'max_length': '200', 'blank': 'True'}),
'fax': ('django.db.models.fields.BigIntegerField', [], {'null': 'True', 'blank': 'True'}),
'foundation': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True', 'blank': 'True'}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'linkedin': ('django.db.models.fields.URLField', [], {'max_length': '200', 'blank': 'True'}),
'logo': ('django.db.models.fields.files.ImageField', [], {'max_length': '100', 'blank': 'True'}),
'modified': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}),
'phone': ('django.db.models.fields.BigIntegerField', [], {'null': 'True', 'blank': 'True'}),
'place_conference': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'organiser_place_conference'", 'null': 'True', 'symmetrical': 'False', 'to': u"orm['place_conference.PlaceConference']"}),
'place_exposition': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'organiser_place_exposition'", 'null': 'True', 'symmetrical': 'False', 'to': u"orm['place_exposition.PlaceExposition']"}),
'rating': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
'staff_number': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True', 'blank': 'True'}),
'tag': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'to': u"orm['theme.Tag']", 'null': 'True', 'blank': 'True'}),
'theme': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'to': u"orm['theme.Theme']", 'null': 'True', 'blank': 'True'}),
'twitter': ('django.db.models.fields.URLField', [], {'max_length': '200', 'blank': 'True'}),
'url': ('django.db.models.fields.SlugField', [], {'max_length': '255', 'blank': 'True'}),
'vk': ('django.db.models.fields.URLField', [], {'max_length': '200', 'blank': 'True'}),
'web_page': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'})
},
u'photologue.gallery': {
'Meta': {'ordering': "['-date_added']", 'unique_together': '()', 'object_name': 'Gallery', 'index_together': '()'},
'date_added': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'is_public': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
'photos': ('sortedm2m.fields.SortedManyToManyField', [], {'blank': 'True', 'related_name': "'galleries'", 'null': 'True', 'symmetrical': 'False', 'to': u"orm['photologue.Photo']"}),
'sites': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'to': u"orm['sites.Site']", 'null': 'True', 'blank': 'True'}),
'slug': ('django.db.models.fields.SlugField', [], {'unique': 'True', 'max_length': '200'}),
'tags': ('photologue.models.TagField', [], {'max_length': '255', 'blank': 'True'})
},
u'photologue.photo': {
'Meta': {'ordering': "['sort']", 'unique_together': '()', 'object_name': 'Photo', 'index_together': '()'},
'crop_from': ('django.db.models.fields.CharField', [], {'default': "'center'", 'max_length': '10', 'blank': 'True'}),
'date_added': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
'date_taken': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
'effect': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'photo_related'", 'null': 'True', 'to': u"orm['photologue.PhotoEffect']"}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'image': ('django.db.models.fields.files.ImageField', [], {'max_length': '100'}),
'is_public': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
'sites': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'to': u"orm['sites.Site']", 'null': 'True', 'blank': 'True'}),
'slug': ('django.db.models.fields.SlugField', [], {'unique': 'True', 'max_length': '200'}),
'sort': ('django.db.models.fields.PositiveIntegerField', [], {'default': '10', 'null': 'True', 'db_index': 'True'}),
'tags': ('photologue.models.TagField', [], {'max_length': '255', 'blank': 'True'}),
'users': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['photologue.UserMark']", 'null': 'True', 'symmetrical': 'False'}),
'view_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'})
},
u'photologue.photoeffect': {
'Meta': {'object_name': 'PhotoEffect'},
'background_color': ('django.db.models.fields.CharField', [], {'default': "'#FFFFFF'", 'max_length': '7'}),
'brightness': ('django.db.models.fields.FloatField', [], {'default': '1.0'}),
'color': ('django.db.models.fields.FloatField', [], {'default': '1.0'}),
'contrast': ('django.db.models.fields.FloatField', [], {'default': '1.0'}),
'description': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
'filters': ('django.db.models.fields.CharField', [], {'max_length': '200', 'blank': 'True'}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}),
'reflection_size': ('django.db.models.fields.FloatField', [], {'default': '0'}),
'reflection_strength': ('django.db.models.fields.FloatField', [], {'default': '0.6'}),
'sharpness': ('django.db.models.fields.FloatField', [], {'default': '1.0'}),
'transpose_method': ('django.db.models.fields.CharField', [], {'max_length': '15', 'blank': 'True'})
},
u'photologue.usermark': {
'Meta': {'object_name': 'UserMark'},
'height': ('django.db.models.fields.PositiveSmallIntegerField', [], {}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'left': ('django.db.models.fields.PositiveSmallIntegerField', [], {}),
'top': ('django.db.models.fields.PositiveSmallIntegerField', [], {}),
'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'marks'", 'to': u"orm['accounts.User']"}),
'width': ('django.db.models.fields.PositiveSmallIntegerField', [], {})
},
u'place_conference.placeconference': {
'Meta': {'unique_together': '()', 'object_name': 'PlaceConference', 'index_together': '()'},
'address': ('functions.custom_fields.LocationField', [], {}),
'amount_halls': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True', 'blank': 'True'}),
'banquet_hall': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}),
'catering': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}),
'city': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'place_conferences'", 'on_delete': 'models.PROTECT', 'to': u"orm['city.City']"}),
'conference_call': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}),
'country': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['country.Country']", 'on_delete': 'models.PROTECT'}),
'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
'exp_hall_area': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True', 'blank': 'True'}),
'exposition_hall': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}),
'fax': ('django.db.models.fields.BigIntegerField', [], {'null': 'True', 'blank': 'True'}),
'foundation_year': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True', 'blank': 'True'}),
'hotel': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'logo': ('django.db.models.fields.files.ImageField', [], {'max_length': '255', 'blank': 'True'}),
'modified': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}),
'multimedia_equipment': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}),
'phone': ('django.db.models.fields.BigIntegerField', [], {'null': 'True', 'blank': 'True'}),
'total_capacity': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True', 'blank': 'True'}),
'translate_equipment': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}),
'type': ('functions.custom_fields.EnumField', [], {'default': "'Convention centre'", 'values': "['Convention centre', 'Exposition centre']"}),
'url': ('django.db.models.fields.SlugField', [], {'unique': 'True', 'max_length': '50'}),
'video_link': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}),
'views': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
'virtual_tour': ('django.db.models.fields.URLField', [], {'max_length': '200', 'blank': 'True'}),
'web_page': ('django.db.models.fields.URLField', [], {'max_length': '200', 'blank': 'True'}),
'wifi': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'})
},
u'place_exposition.placeexposition': {
'Meta': {'ordering': "['-rating', 'id']", 'unique_together': '()', 'object_name': 'PlaceExposition', 'index_together': '()'},
'address': ('functions.custom_fields.LocationField', [], {}),
'bank': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}),
'business_centre': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}),
'cafe': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}),
'children_room': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}),
'city': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'place_expositions'", 'on_delete': 'models.PROTECT', 'to': u"orm['city.City']"}),
'closed_area': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True', 'blank': 'True'}),
'conference_centre': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}),
'country': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['country.Country']", 'on_delete': 'models.PROTECT'}),
'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
'disabled_service': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}),
'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
'event_in_year': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True', 'blank': 'True'}),
'fax': ('django.db.models.fields.BigIntegerField', [], {'null': 'True', 'blank': 'True'}),
'foundation_year': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True', 'blank': 'True'}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'is_published': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
'logo': ('django.db.models.fields.files.ImageField', [], {'max_length': '255', 'blank': 'True'}),
'mobile_application': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}),
'modified': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}),
'online_registration': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}),
'open_area': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True', 'blank': 'True'}),
'parking': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}),
'partner': ('django.db.models.fields.NullBooleanField', [], {'default': '0', 'null': 'True', 'blank': 'True'}),
'phone': ('django.db.models.fields.BigIntegerField', [], {'null': 'True', 'blank': 'True'}),
'photogallery': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['photologue.Gallery']", 'null': 'True', 'on_delete': 'models.SET_NULL', 'blank': 'True'}),
'press_centre': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}),
'rating': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
'terminals': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}),
'total_area': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True', 'blank': 'True'}),
'total_halls': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True', 'blank': 'True'}),
'total_pavilions': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True', 'blank': 'True'}),
'type': ('functions.custom_fields.EnumField', [], {'default': "'Exposition complex'", 'values': "['Exposition complex', 'Convention centre', 'Exposition centre']"}),
'url': ('django.db.models.fields.SlugField', [], {'unique': 'True', 'max_length': '255'}),
'views': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
'virtual_tour': ('django.db.models.fields.URLField', [], {'max_length': '200', 'blank': 'True'}),
'web_page': ('django.db.models.fields.URLField', [], {'max_length': '200', 'blank': 'True'}),
'wifi': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'})
},
u'sites.site': {
'Meta': {'ordering': "('domain',)", 'object_name': 'Site', 'db_table': "'django_site'"},
'domain': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
},
u'stats_collector.objectstats': {
'Meta': {'ordering': "('created_at',)", 'object_name': 'ObjectStats'},
'conference': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['conference.Conference']", 'null': 'True', 'blank': 'True'}),
'created_at': ('django.db.models.fields.DateField', [], {'db_index': 'True', 'null': 'True', 'blank': 'True'}),
'exposition': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['exposition.Exposition']", 'null': 'True', 'blank': 'True'}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'value': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True', 'blank': 'True'})
},
u'stats_collector.sectionstats': {
'Meta': {'ordering': "('created_at',)", 'object_name': 'SectionStats', 'index_together': "[('content_type', 'object_id')]"},
'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['contenttypes.ContentType']", 'null': 'True', 'blank': 'True'}),
'created_at': ('django.db.models.fields.DateField', [], {'db_index': 'True', 'null': 'True', 'blank': 'True'}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'kind': ('django.db.models.fields.CharField', [], {'max_length': '64', 'null': 'True', 'blank': 'True'}),
'object_id': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
'section': ('django.db.models.fields.CharField', [], {'max_length': '32', 'null': 'True', 'blank': 'True'}),
'value': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True', 'blank': 'True'})
},
u'theme.tag': {
'Meta': {'unique_together': '()', 'object_name': 'Tag', 'index_together': '()'},
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'inflect': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}),
'old_url': ('django.db.models.fields.SlugField', [], {'unique': 'True', 'max_length': '255'}),
'theme': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'tags'", 'on_delete': 'models.PROTECT', 'to': u"orm['theme.Theme']"}),
'url': ('django.db.models.fields.SlugField', [], {'unique': 'True', 'max_length': '255'})
},
u'theme.theme': {
'Meta': {'unique_together': '()', 'object_name': 'Theme', 'index_together': '()'},
'blogtheme_linking': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'to': u"orm['theme.ThemeBlog']", 'null': 'True'}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'inflect': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}),
'main_page': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0', 'db_index': 'True'}),
'old_url': ('django.db.models.fields.SlugField', [], {'unique': 'True', 'max_length': '255'}),
'types': ('django.db.models.fields.BigIntegerField', [], {'default': 'None'}),
'url': ('django.db.models.fields.SlugField', [], {'unique': 'True', 'max_length': '255'})
},
u'theme.themeblog': {
'Meta': {'unique_together': '()', 'object_name': 'ThemeBlog', 'index_together': '()'},
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'inflect': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}),
'url': ('django.db.models.fields.SlugField', [], {'unique': 'True', 'max_length': '255'})
},
u'translator.translator': {
'Meta': {'unique_together': '()', 'object_name': 'Translator', 'index_together': '()'},
'birth': ('django.db.models.fields.DateField', [], {}),
'car': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'gender': ('functions.custom_fields.EnumField', [], {'default': "'male'", 'values': "('male', 'female')"}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'})
}
}
complete_apps = ['stats_collector']

@ -0,0 +1,79 @@
# -*- coding: utf-8 -*-
from django.contrib.contenttypes.models import ContentType
from .models import SectionStats, ObjectStats
class SectionBaseMixin(object):
"""
Section stat base mixin
"""
section = None
stat_kind = None
def render_to_response(self, context, **response_kwargs):
try:
SectionStats.cache_count_add(
self.section, self.stat_kind, None, None, 1)
# ['section', 'kind', 'content_type', 'object_id', 'value']
except:
pass
return super(SectionBaseMixin, self).render_to_response(context, **response_kwargs)
class ExpoSectionBaseMixin(object):
section = 'expo'
class ExpoSectionMixin(ExpoSectionBaseMixin, SectionBaseMixin):
pass
class ConfSectionBaseMixin(object):
section = 'conf'
class ConfSectionMixin(ConfSectionBaseMixin, SectionBaseMixin):
pass
class SectionKindBaseMixin(object):
section = None
stat_kind = None
def render_to_response(self, context, **response_kwargs):
if self.stat_kind is not None and self.stat_kind in self.kwargs:
try:
obj = self.kwargs.get(self.stat_kind)
content_type = ContentType.objects.get_for_model(obj)
SectionStats.cache_count_add(
self.section, self.stat_kind, content_type.pk, obj.pk, 1)
# ['section', 'kind', 'content_type', 'object_id', 'value']
except:
pass
# except Exception as e:
# print(e)
return super(SectionKindBaseMixin, self).render_to_response(context, **response_kwargs)
class ExpoSectionKindMixin(ExpoSectionBaseMixin, SectionKindBaseMixin):
pass
class ConfSectionKindMixin(ConfSectionBaseMixin, SectionKindBaseMixin):
pass
class ObjectStatMixin(object):
def render_to_response(self, context, **response_kwargs):
try:
obj = self.object
if obj.__class__.__name__.lower() == 'conference':
ObjectStats.cache_count_add(obj.pk, None, 1)
else:
ObjectStats.cache_count_add(None, obj.pk, 1)
# ['conference_id', 'exposition_id', 'value']
except:
pass
return super(ObjectStatMixin, self).render_to_response(context, **response_kwargs)

@ -0,0 +1,102 @@
# -*- coding: utf-8 -*-
import json
import time
from collections import namedtuple
from datetime import timedelta
from conference.models import Conference
from django.contrib.contenttypes.generic import GenericForeignKey
from django.contrib.contenttypes.models import ContentType
from django.core.cache import cache
from django.core.serializers.json import DjangoJSONEncoder
from django.db import models
from django.utils import timezone
from django_pandas.managers import DataFrameManager
from exposition.models import Exposition
class StatsSuperBase(models.Model):
_strftime_format = '%d.%m.%Y'
_cache_key = 'section_stats_{date}'
created_at = models.DateField('created at', blank=True, null=True, db_index=True)
value = models.PositiveIntegerField('value', blank=True, null=True)
class Meta:
verbose_name = 'Stats Object'
verbose_name_plural = 'Stats Objects'
ordering = ('created_at',)
abstract = True
@classmethod
def make_key(cls, date=None):
if date is None:
date = timezone.now().date()
return cls._cache_key.format(date=date.isoformat())
@classmethod
def dump_item(self, item):
return json.dumps(item, cls=DjangoJSONEncoder)
@classmethod
def create_item(cls, *args, **kwargs):
return cls._collector_class(*args, **kwargs)
@classmethod
def create_instance(cls, *args, **kwargs):
created_at = kwargs.pop('created_at', None)
item = cls.create_item(*args, **kwargs)
return cls(created_at=created_at, **item._asdict())
@classmethod
def create_cache_item(cls, *args, **kwargs):
return cls.dump_item(cls.create_item(*args, **kwargs))
@classmethod
def cache_count_add(cls, *args, **kwargs):
item = cls.create_cache_item(*args, **kwargs)
key = cls.make_key()
cache._client.rpush(key, item)
return item
@property
def created_at_(self):
return self.created_at.strftime(self._strftime_format)
# class StatsBase(StatsSuperBase):
class SectionStats(StatsSuperBase):
_collector_class = namedtuple(
'SectionCollector',
['section', 'kind', 'content_type_id', 'object_id', 'value']
)
content_type = models.ForeignKey(ContentType, blank=True, null=True)
object_id = models.IntegerField(blank=True, null=True)
content_object = GenericForeignKey('content_type', 'object_id')
class Meta(StatsSuperBase.Meta):
index_together = [
("content_type", "object_id"),
]
section = models.CharField('section', blank=True, null=True, max_length=32)
kind = models.CharField('kind', blank=True, null=True, max_length=64)
def __unicode__(self):
return u'{0}:{1} {2}'.format(self.section, self.kind, self.created_at.strftime(self._strftime_format))
class ObjectStats(StatsSuperBase):
_cache_key = 'obj_stats_{date}'
_collector_class = namedtuple(
'ObjectCollector',
['conference_id', 'exposition_id', 'value']
)
exposition = models.ForeignKey(Exposition, null=True, blank=True)
conference = models.ForeignKey(Conference, null=True, blank=True)
def __unicode__(self):
return u'{0}'.format(self.created_at.strftime(self._strftime_format))

@ -0,0 +1,16 @@
"""
This file demonstrates writing tests using the unittest module. These will pass
when you run "manage.py test".
Replace this with more appropriate tests for your application.
"""
from django.test import TestCase
class SimpleTest(TestCase):
def test_basic_addition(self):
"""
Tests that 1 + 1 always equals 2.
"""
self.assertEqual(1 + 1, 2)

@ -0,0 +1,15 @@
# -*- coding: utf-8 -*-
import json
from collections import Counter
def items_iterator(objects_list, model):
for string_item, count in Counter(objects_list).items():
item = model._collector_class(*json.loads(string_item))
yield item._replace(value=item.value * count)
def unique_items_iterator(objects_list):
for string_item, count in Counter(objects_list).items():
item = json.loads(string_item)
yield tuple(item[:-1]), item[-1] * count

@ -0,0 +1 @@
# Create your views here.

@ -9,8 +9,6 @@
<link rel="stylesheet" href="{% static 'bootstrap/css/bootstrap.min.css' %} ">
{# css harizma #}
<link id="bs-css" href="{% static 'css/bootstrap-cerulean.css' %}" rel="stylesheet">
<link href="{% static 'css/bootstrap-responsive.css' %}" rel="stylesheet">
@ -29,12 +27,20 @@
<link href="{% static 'css/jquery.iphone.toggle.css' %}" rel='stylesheet'>
<link href="{% static 'css/opa-icons.css' %}" rel='stylesheet'>
<link href="{% static 'css/uploadify.css' %}" rel='stylesheet'>
{# select2 #}
<link href="{% static 'js/select/select2.css' %}" rel="stylesheet"/>
<script src="{% static 'js/select/select2.js' %}"></script>
{# The fav icon #}
<link rel="shortcut icon" href="img/favicon.ico">
<link rel="shortcut icon" href="img/favicon.ico">
{# datetimepicker #}
<link href="{% static 'js/datetimepicker/css/datetimepicker.css' %}" rel="stylesheet"/>
<script src="{% static 'js/datetimepicker/js/bootstrap-datetimepicker.js' %}"></script>
<script src="{% static 'custom_js/main.js' %}"></script>
<script src="{% static 'js/datetimepicker/js/locales/bootstrap-datetimepicker.ru.js' %}"></script>
{% block main_js_exlude %}
<script src="{% static 'custom_js/main.js' %}"></script>
{% endblock main_js_exlude %}
{% block scripts %}
{% endblock %}
@ -56,27 +62,25 @@
</head>
<body style="padding-top: 30px">
{# Side navigation #}
{% block sidebar %}
{% if user.is_superuser %}
{% include 'admin/includes/admin_nav.html' %}
{% else %}
{% include 'admin/includes/staff_nav.html' %}
{% endif %}
{% endblock %}
{# Side navigation #}
{% block sidebar %}
{% if user.is_superuser %}
{% include 'admin/includes/admin_nav.html' %}
{% else %}
{% include 'admin/includes/staff_nav.html' %}
{% endif %}
{% endblock %}
<div class="span7 offset3" id="content" >
{# Main content #}
{% block body %}
{% endblock %}
<div class="span7 offset3" id="content" >
{# Main content #}
{% block body %}
{% endblock %}
</div>
</body>
{% block bot_scripts %}
{% endblock %}
</html>
</html>

@ -54,7 +54,7 @@ td a{
<tr>
<td>{{ item.name }}</td>
<td>{{ item.data_begin|date:"Y-m-d" }}</td>
<td>{{ item.data_begin|date:"Y-m-d" }}<br><i class="icon-eye-open"></i> {{ item.get_objectstat_views }}</td>
<td><a class="btn-small btn-inverse copy" data-id="{{ item.id }}" href="#">Копировать</a><input id="copy_url_{{ item.id }}" type="text" placeholder="новый урл"></td>
<td style="width: 200px; height:100px;">
<a class="btn-small btn-warning off" style="{% if item.is_published %}{% else %}display: none;{% endif %}"
@ -116,4 +116,4 @@ td a{
})
</script>
{% endblock %}
{% endblock %}

@ -51,7 +51,7 @@ td a{
<tr>
<td>{{ item.name }}</td>
<td>{{ item.data_begin|date:"Y-m-d" }}</td>
<td>{{ item.data_begin|date:"Y-m-d" }}<br><i class="icon-eye-open"></i> {{ item.get_objectstat_views }}</td>
<td><a class="btn-small btn-inverse copy" data-id="{{ item.id }}" href="#">Копировать</a><input id="copy_url_{{ item.id }}" type="text" placeholder="новый урл"></td>
<td style="width: 200px; height:100px;">
<a class="btn-small btn-warning off" style="{% if item.is_published %}{% else %}display: none;{% endif %}"

@ -1,3 +1,5 @@
{% load i18n %}
<div class="span3" data-spy="affix" data-offset-top="0" id="navigation">
<div class="well sidebar-nav">
<ul class="nav nav-tabs nav-stacked">
@ -48,9 +50,13 @@
<li><a href="/admin/settings/main-page/">Главная страница</a></li>
<li><a href="/admin/meta/all/">Мета</a></li>
<li class="divider"></li>
<li><a href="/admin/import-theme">Импорт тематик</a></li>
<li><a href="/admin/import-tag">Импорт тегов</a></li>
<li class="divider"></li>
<li><a href="/admin/import-theme">Импорт тематик</a></li>
<li><a href="/admin/import-tag">Импорт тегов</a></li>
<li class="divider"></li>
<li><a href="/admin/stats/">{% trans "Статистика разделов" %}</a></li>
<li><a href="/admin/stats/events/">{% trans "Статистика событий" %}</a></li>
</ul>
</li>

@ -0,0 +1,9 @@
{% if content_form %}
{{ content_form.content_type }}
<div class="control-group {% if content_form.ct_objects.errors %}error{% endif %}">
<label class="control-label"><b>{{ content_form.ct_objects.label }}:</b></label>
<div class="controls">{{ content_form.ct_objects }}
<span class="help-inline">{{ content_form.ct_objects.errors }}</span>
</div>
</div>
{% endif %}

@ -0,0 +1,40 @@
{% if params_form %}
<div class="span4" style="margin-left: 0px;">
{# country #}
<div class="control-group {% if params_form.country.errors %}error{% endif %}">
<label class="control-label"><b>{{ params_form.country.label }}:</b></label>
<div class="controls">{{ params_form.country }}
<span class="help-inline">{{ params_form.country.errors }}</span>
</div>
</div>
{# theme #}
<div class="control-group {% if params_form.theme.errors %}error{% endif %}">
<label class="control-label"><b>{{ params_form.theme.label }}:</b></label>
<div class="controls">{{ params_form.theme }}
<span class="help-inline">{{ params_form.theme.errors }}</span>
</div>
</div>
</div>
<div class="span4" style="margin-left: 0px;">
{# city #}
<div class="control-group {% if params_form.city.errors %}error{% endif %}">
<label class="control-label"><b>{{ params_form.city.label }}:</b></label>
<div class="controls">{{ params_form.city }}
<span class="help-inline">{{ params_form.city.errors }}</span>
</div>
</div>
{# tag #}
<div class="control-group {% if params_form.tag.errors %}error{% endif %}">
<label class="control-label"><b>{{ params_form.tag.label }}:</b></label>
<div class="controls">{{ params_form.tag }}
<span class="help-inline">{{ params_form.tag.errors }}</span>
</div>
</div>
</div>
{% endif %}

@ -0,0 +1,152 @@
{% extends "base.html" %}
{% load static %}
{% load i18n %}
{% block main_js_exlude %}
{% endblock main_js_exlude %}
{% block scripts %}
<script type="text/javascript" src="https://www.gstatic.com/charts/loader.js"></script>
<script type="text/javascript">
google.charts.load('current', {'packages':['corechart'], 'language': '{{ LANGUAGE_CODE }}'});
{% if data %}
function drawChart() {
var data = google.visualization.arrayToDataTable([
{% autoescape off %}
[{type: 'date', label: '{% trans "Дата" %}'}, '{% trans "Просмотры" %}'],
{% for item in data %}
{{ item }},
{% endfor %}
{% endautoescape %}
]);
var options = {
title: '{% trans "Статистика разделов" %}',
legend: { position: 'bottom' },
vAxis: {
title: '{% trans "Просмотры" %}'
},
width: 900,
height: 500,
};
var chart = new google.visualization.LineChart(document.getElementById('curve_chart'));
chart.draw(data, options);
}
google.charts.setOnLoadCallback(drawChart);
{% endif %}
{% if data_summary %}
function drawSummaryChart() {
var data = google.visualization.arrayToDataTable([
{% autoescape off %}
['name', '{% trans "Просмотры" %}', { role: 'annotation' }],
['{% trans "События" %}', {{ data_summary }}, {{ data_summary }}],
{% endautoescape %}
]);
var options = {
title: '{% trans "Сумарные данные" %}',
// legend: { position: 'bottom' },
// xAxis: {
// title: '{% trans "Просмотры" %}'
// },
legend: { position: "none" },
width: 900,
height: 500,
};
var rchart = new google.visualization.BarChart(document.getElementById('bar_chart'));
rchart.draw(data, options);
}
google.charts.setOnLoadCallback(drawSummaryChart);
{% endif %}
$(document).ready(function(){
$('#id_date_begin').datetimepicker({
todayHighlight: true,
format : 'dd.mm.yyyy',
minView: 2,
language: '{{ LANGUAGE_CODE }}'
});
$('#id_date_end').datetimepicker({
todayHighlight: true,
format : 'dd.mm.yyyy',
minView: 2,
language: '{{ LANGUAGE_CODE }}'
});
$('select').select2('destroy');
$('select:not(#id_event)').select2({width: "element"});
});
</script>
{% endblock scripts %}
{% block body %}
<div class="box span8">
<div class="box-header well">
<h2><i class="icon-arrow-down"></i>Фильтр</h2>
</div>
<div class="box-content">
<form id="stat_filter_form" action="." method="POST">
{% csrf_token %}
<div class="span8">
<div class="span4" style="margin-left: 0px;">
{# date_begin #}
<div class="control-group {% if form.date_begin.errors %}error{% endif %}">
<label class="control-label"><b>{{ form.date_begin.label }}:</b></label>
<div class="controls">{{ form.date_begin }}
<span class="help-inline">{{ form.date_begin.errors }}</span>
</div>
</div>
{# event #}
<div class="control-group {% if form.event.errors %}error{% endif %}">
<label class="control-label"><b>{{ form.event.label }}:</b></label>
<div class="controls">{{ form.event }}
<span class="help-inline">{{ form.event.errors }}</span>
</div>
</div>
</div>
<div class="span4" style="margin-left: 0px;">
{# date_end #}
<div class="control-group {% if form.date_end.errors %}error{% endif %}">
<label class="control-label"><b>{{ form.date_end.label }}:</b></label>
<div class="controls">{{ form.date_end }}
<span class="help-inline">{{ form.date_end.errors }}</span>
</div>
</div>
</div>
</div>
<div class="span8 params_form">
{% include "admin/stats/event_params_form.html" %}
</div>
<div class="span8">
{% if form.errors %}
<div class="alert alert-error">
{% for key, value in form.errors.items %}
<p>{{ value }}</p>
{% endfor %}
</div>
{% endif %}
<button type="submit">{% trans "Применить" %}</button>
</div>
</form>
</div>
</div>
<div class="span9">
<div id="curve_chart"></div>
<div id="bar_chart"></div>
</div>
{% endblock body %}

@ -0,0 +1,191 @@
{% extends "base.html" %}
{% load static %}
{% load i18n %}
{% block scripts %}
<script type="text/javascript" src="https://www.gstatic.com/charts/loader.js"></script>
<script type="text/javascript">
google.charts.load('current', {'packages':['corechart'], 'language': '{{ LANGUAGE_CODE }}'});
function drawChart() {
var data = google.visualization.arrayToDataTable([
{% autoescape off %}
[{type: 'date', label: '{% trans "Дата" %}'}, {{ columns }}],
{% for item in data %}
{{ item }},
{% endfor %}
{% endautoescape %}
]);
var options = {
title: 'Статистика разделов',
legend: { position: 'bottom' },
vAxis: {
title: '{% trans "Просмотры" %}'
},
width: 900,
height: 500,
};
var chart = new google.visualization.LineChart(document.getElementById('curve_chart'));
chart.draw(data, options);
}
function drawSummaryChart() {
var data = google.visualization.arrayToDataTable([
{% autoescape off %}
['name', '{% trans "Просмотры" %}', { role: 'annotation' }],
{% for item in data_summary %}
['{{ item.name }}', {{ item.val }}, {{ item.val }}],
{% endfor %}
{% endautoescape %}
]);
var options = {
title: '{% trans "Сумарные данные" %}',
// legend: { position: 'bottom' },
// xAxis: {
// title: '{% trans "Просмотры" %}'
// },
legend: { position: "none" },
width: 900,
height: 500,
};
var rchart = new google.visualization.BarChart(document.getElementById('bar_chart'));
rchart.draw(data, options);
}
google.charts.setOnLoadCallback(drawChart);
google.charts.setOnLoadCallback(drawSummaryChart);
function initStatFilterForm() {
form = $('form#stat_filter_form');
ct_form_div = form.find('div#ct_form');
form.find('input:not(#id_content_type), select:not(#id_ct_objects)').on('change', function() {
form.find('div.alert').remove();
form.find('select#id_ct_objects').select2('val', '');
$.ajax({
url: form.attr('action'),
type: 'POST',
dataType: 'json',
data: form.serializeArray(),
})
.done(function(data) {
if (data.success) {
// form.find('select#id_ct_objects').select2('destroy');
ct_form_div.html(data.html);
form.find('select#id_ct_objects').select2({width: "element"});
} else {
$.each(data.errors, function(i, val) {
if (i == '__all__') {
form.find('button').before('<div class="alert alert-error"></div>');
alert_div = form.find('div.alert');
for (var error = 0; error < val.length; error++) {
alert_div.prepend('<p>' + val[error] + '</p>');
}
} else {
field = form.find('input[name="' + i + '"]')
field.parents('div.control-group').addClass('error');
field.siblings('div.help-inline').html(val);
}
});
}
console.log(data);
})
});
}
$(document).ready(function(){
$('#id_date_begin').datetimepicker({
todayHighlight: true,
format : 'dd.mm.yyyy',
minView: 2,
language: '{{ LANGUAGE_CODE }}'
});
$('#id_date_end').datetimepicker({
todayHighlight: true,
format : 'dd.mm.yyyy',
minView: 2,
language: '{{ LANGUAGE_CODE }}'
});
$('select:not(#id_ct_objects)').select2('destroy');
// $('#id_ct_objects').select2({width: "element"});
initStatFilterForm();
});
</script>
{% endblock scripts %}
{% block body %}
<div class="box span8">
<div class="box-header well">
<h2><i class="icon-arrow-down"></i>Фильтр</h2>
</div>
<div class="box-content">
<form id="stat_filter_form" action="." method="POST">
{% csrf_token %}
<div class="span4" style="margin-left: 0px;">
{# date_begin #}
<div class="control-group {% if form.date_begin.errors %}error{% endif %}">
<label class="control-label"><b>{{ form.date_begin.label }}:</b></label>
<div class="controls">{{ form.date_begin }}
<span class="help-inline">{{ form.date_begin.errors }}</span>
</div>
</div>
{# section #}
<div class="control-group {% if form.section.errors %}error{% endif %}">
<label class="control-label"><b>{{ form.section.label }}:</b></label>
<div class="controls">{{ form.section }}
<span class="help-inline">{{ form.section.errors }}</span>
</div>
</div>
</div>
<div class="span4" style="margin-left: 0px;">
{# date_end #}
<div class="control-group {% if form.date_end.errors %}error{% endif %}">
<label class="control-label"><b>{{ form.date_end.label }}:</b></label>
<div class="controls">{{ form.date_end }}
<span class="help-inline">{{ form.date_end.errors }}</span>
</div>
</div>
{# kind #}
<div class="control-group {% if form.kind.errors %}error{% endif %}">
<label class="control-label"><b>{{ form.kind.label }}:</b></label>
<div class="controls">{{ form.kind }}
<span class="help-inline">{{ form.kind.errors }}</span>
</div>
</div>
<div id="ct_form">
{% include "admin/stats/content_type_form.html" %}
</div>
</div>
{% if form.errors %}
<div class="alert alert-error">
{% for key, value in form.errors.items %}
<p>{{ value }}</p>
{% endfor %}
</div>
{% endif %}
<button type="submit">{% trans "Применить" %}</button>
</form>
{# style="width: 900px; height: 500px" #}
</div>
</div>
<div class="span9">
<div id="curve_chart"></div>
<div id="bar_chart"></div>
</div>
{% endblock body %}
Loading…
Cancel
Save