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. 0
      stats_collector/__init__.py
  14. 344
      stats_collector/admin.py
  15. 9
      stats_collector/admin_urls.py
  16. 83
      stats_collector/forms.py
  17. 0
      stats_collector/management/__init__.py
  18. 0
      stats_collector/management/commands/__init__.py
  19. 31
      stats_collector/management/commands/stats_daily.py
  20. 25
      stats_collector/management/commands/stats_hourly.py
  21. 87
      stats_collector/management/commands/stats_test.py
  22. 605
      stats_collector/migrations/0001_initial.py
  23. 0
      stats_collector/migrations/__init__.py
  24. 79
      stats_collector/mixin.py
  25. 102
      stats_collector/models.py
  26. 16
      stats_collector/tests.py
  27. 15
      stats_collector/utils.py
  28. 1
      stats_collector/views.py
  29. 42
      templates/admin/base.html
  30. 2
      templates/admin/conference/conference_list.html
  31. 2
      templates/admin/exposition/exposition_list.html
  32. 12
      templates/admin/includes/admin_nav.html
  33. 9
      templates/admin/stats/content_type_form.html
  34. 40
      templates/admin/stats/event_params_form.html
  35. 152
      templates/admin/stats/event_stat.html
  36. 191
      templates/admin/stats/section_stat.html

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

@ -202,6 +202,9 @@ class Conference(TranslatableModel, EventMixin, ExpoMixin):
def clicks(self): def clicks(self):
return self.paid_new.tickets.clicks() + self.paid_new.participation.clicks() + self.paid_new.official.clicks() 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): class Statistic(TranslatableModel):
conference = models.ForeignKey(Conference, related_name='statistic') conference = models.ForeignKey(Conference, related_name='statistic')

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

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

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

@ -290,6 +290,9 @@ class Exposition(TranslatableModel, EventMixin, ExpoMixin):
def clicks(self): def clicks(self):
return self.paid_new.tickets.clicks() + self.paid_new.participation.clicks() + self.paid_new.official.clicks() 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): class Statistic(TranslatableModel):
exposition = models.ForeignKey(Exposition, related_name='statistic') exposition = models.ForeignKey(Exposition, related_name='statistic')

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

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

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

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

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

@ -1,12 +1,34 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
import debug_toolbar
from core.simple_index_view import (
AboutView,
AdvertisingView,
AdvertisingViewLanding
)
from django.conf import settings from django.conf import settings
from django.conf.urls import patterns, include, url from django.conf.urls import include, patterns, url
from core.simple_index_view import AdvertisingView, AboutView, AdvertisingViewLanding from django.conf.urls.static import static
from views import MainPageView
from django.contrib.sitemaps import views 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 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): class Robot(TemplateView):
template_name = 'client/robots.txt' template_name = 'client/robots.txt'
@ -16,8 +38,6 @@ class YandexCheck(TemplateView):
template_name = 'client/simple_pages/yandex_check.html' 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 = { sitemaps = {
@ -84,6 +104,7 @@ if settings.DEBUG:
(r'media/(?P<path>.*)', (r'media/(?P<path>.*)',
'serve', 'serve',
{'document_root': settings.MEDIA_ROOT}), ) {'document_root': settings.MEDIA_ROOT}), )
urlpatterns += static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)
import debug_toolbar import debug_toolbar
urlpatterns += patterns('', urlpatterns += patterns('',
@ -105,5 +126,3 @@ urlpatterns += solid_i18n_patterns('',
url(r'^', include('settings.old_urls')), url(r'^', include('settings.old_urls')),
url(r'^', include('accounts.user_catalog_urls')), url(r'^', include('accounts.user_catalog_urls')),
) )

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

@ -54,7 +54,7 @@ td a{
<tr> <tr>
<td>{{ item.name }}</td> <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><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;"> <td style="width: 200px; height:100px;">
<a class="btn-small btn-warning off" style="{% if item.is_published %}{% else %}display: none;{% endif %}" <a class="btn-small btn-warning off" style="{% if item.is_published %}{% else %}display: none;{% endif %}"

@ -51,7 +51,7 @@ td a{
<tr> <tr>
<td>{{ item.name }}</td> <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><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;"> <td style="width: 200px; height:100px;">
<a class="btn-small btn-warning off" style="{% if item.is_published %}{% else %}display: none;{% endif %}" <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="span3" data-spy="affix" data-offset-top="0" id="navigation">
<div class="well sidebar-nav"> <div class="well sidebar-nav">
<ul class="nav nav-tabs nav-stacked"> <ul class="nav nav-tabs nav-stacked">
@ -48,9 +50,13 @@
<li><a href="/admin/settings/main-page/">Главная страница</a></li> <li><a href="/admin/settings/main-page/">Главная страница</a></li>
<li><a href="/admin/meta/all/">Мета</a></li> <li><a href="/admin/meta/all/">Мета</a></li>
<li class="divider"></li> <li class="divider"></li>
<li><a href="/admin/import-theme">Импорт тематик</a></li> <li><a href="/admin/import-theme">Импорт тематик</a></li>
<li><a href="/admin/import-tag">Импорт тегов</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> </ul>
</li> </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