diff --git a/expobanner/admin.py b/expobanner/admin.py index d1273215..1625121c 100644 --- a/expobanner/admin.py +++ b/expobanner/admin.py @@ -1,8 +1,12 @@ # -*- coding: utf-8 -*- -from django.views.generic import TemplateView, CreateView, ListView, UpdateView +from django.views.generic import TemplateView, CreateView, ListView, UpdateView, DetailView from django.conf import settings -from expobanner.models import URL, BannerGroup, Banner -from expobanner.forms import UrlCreateForm, BannerCreateGroupForm, BannerCreateForm, BannerGroupUpdateForm +from django.http import HttpResponseRedirect +from django.shortcuts import get_object_or_404 +from expobanner.models import URL, BannerGroup, Banner, Paid +from expobanner.forms import UrlCreateForm, BannerCreateGroupForm, BannerCreateForm, BannerGroupUpdateForm,\ + PaidCreateForm, PaidUpdateForm +from exposition.models import Exposition class BannersControl(TemplateView): @@ -52,6 +56,12 @@ class BannerGroupList(AbstractList): class BannerList(AbstractList): model = Banner verbose = u'Список банеров' + template_name = 'admin/expobanner/banner_list.html' + + def get_queryset(self): + qs = super(BannerList, self).get_queryset() + qs = qs.filter(group__isnull=False) + return qs # UPDATE VIEWS class AbstractUpdate(UpdateView): @@ -71,4 +81,61 @@ class BannerGroupUpdate(AbstractUpdate): class BannerUpdate(AbstractUpdate): model = Banner - form_class = BannerCreateForm \ No newline at end of file + form_class = BannerCreateForm + + +class BannerStat(DetailView): + model = Banner + template_name = 'admin/expobanner/banner_stat.html' + +class PaidList(ListView): + model = Exposition + template_name = 'admin/expobanner/paid_list.html' + paginate_by = settings.ADMIN_PAGINATION + + def get_queryset(self): + return self.model.objects.language().filter(paid_new__isnull=False) + +class PaidCreate(CreateView): + form_class = PaidCreateForm + template_name = 'admin/expobanner/paid_create.html' + success_url = '/admin/expobanners/paid/list/' + +class PaidUpdate(UpdateView): + model = Paid + form_class = PaidUpdateForm + template_name = 'admin/expobanner/paid_update.html' + success_url = '/admin/expobanners/paid/list/' + + def get_initial(self): + """ + Returns the initial data to use for forms on this view. + """ + initial = super(PaidUpdate, self).get_initial() + obj = self.object + initial['tickets'] = obj.tickets.url + initial['participation'] = obj.participation.url + initial['official'] = obj.official.url + + return initial + + def get_context_data(self, **kwargs): + context = super(PaidUpdate, self).get_context_data(**kwargs) + obj = self.object + context['exposition'] = obj.get_event() + return context + + +def paid_turn(request, pk, status): + paid = get_object_or_404(Paid, pk=pk) + if status == 'on': + paid.public = True + else: + paid.public = False + paid.save() + return HttpResponseRedirect('/admin/expobanners/paid/list/') + + +class PaidStat(DetailView): + model = Paid + template_name = 'admin/expobanner/paid_stat.html' \ No newline at end of file diff --git a/expobanner/admin_urls.py b/expobanner/admin_urls.py index db31823e..c03071da 100644 --- a/expobanner/admin_urls.py +++ b/expobanner/admin_urls.py @@ -3,19 +3,22 @@ from django.conf.urls import patterns, url from expobanner.admin import * urlpatterns = patterns('expobanner.admin', + # banners url(r'^banners/control/$', BannersControl.as_view(), name='expobanner-baneers_control'), - url(r'^banners/url/$', CreateUrl.as_view(), name='expobanner-create_url'), url(r'^banners/group/$', CreateBannerGroup.as_view(), name='expobanner-create_group'), url(r'^banners/banner/$', CreateBanner.as_view(), name='expobanner-create_banner'), - url(r'^banners/url/list/$', UrlList.as_view(), name='expobanner-list_url'), url(r'^banners/group/list/$', BannerGroupList.as_view(), name='expobanner-list_group'), url(r'^banners/banner/list/$', BannerList.as_view(), name='expobanner-list_banner'), - url(r'^banners/url/(?P\d+)/edit/$', UrlUpdate.as_view(), name='expobanner-update_url'), url(r'^banners/group/(?P\d+)/edit/$', BannerGroupUpdate.as_view(), name='expobanner-update_group'), url(r'^banners/banner/(?P\d+)/edit/$', BannerUpdate.as_view(), name='expobanner-update_banner'), - - + url(r'^banners/banner/(?P\d+)/stat/$', BannerStat.as_view(), name='expobanner_stat_banner'), + # paid + url(r'^paid/list/$', PaidList.as_view(), name='expobanner-list_paid'), + url(r'^paid/(?P\d+)/edit/$', PaidUpdate.as_view(), name='expobanner-update_paid'), + url(r'^paid/$', PaidCreate.as_view(), name='expobanner-create_paid'), + url(r'^paid/turn/(?P\d+)/(?P.*)/$', paid_turn, name='expobanner-paid-turn'), + url(r'^paid/(?P\d+)/stat/$', PaidStat.as_view(), name='expobanner_stat_paid'), ) \ No newline at end of file diff --git a/expobanner/forms.py b/expobanner/forms.py index 82bfd39e..8bb9e0cf 100644 --- a/expobanner/forms.py +++ b/expobanner/forms.py @@ -1,6 +1,7 @@ # -*- coding: utf-8 -*- from django import forms -from expobanner.models import URL, BannerGroup, Banner +from expobanner.models import URL, BannerGroup, Banner, Paid +from exposition.models import Exposition from country.models import Country from city.models import City from theme.models import Theme, Tag @@ -34,7 +35,92 @@ class BannerCreateForm(forms.ModelForm): #city = forms.CharField(label=u'Город', widget=forms.HiddenInput(), required=False) #tag = forms.CharField(label=u'Тег', widget=forms.HiddenInput(), required=False) - class Meta: model = Banner - exclude = ['created_at', 'updated_at', 'often', 'paid'] \ No newline at end of file + exclude = ['created_at', 'updated_at', 'often', 'paid', 'stat_pswd'] + + +class ClientStatForm(forms.Form): + stat_pswd = forms.CharField(label=u'Введите пароль:') + + def check_pass(self, obj): + pswd = self.cleaned_data['stat_pswd'] + return obj.stat_pswd == pswd + + +class PaidCreateForm(forms.ModelForm): + verbose = u'Создать проплаченую выставку' + exposition = forms.CharField(label=u'Выставка', widget=forms.HiddenInput()) + tickets = forms.URLField(label=u'Линк на билеты') + participation = forms.URLField(label=u'Линк на участие') + official = forms.URLField(label=u'Линк на официальный сайт') + + class Meta: + model = Paid + fields = ['logo', 'organiser', 'public'] + + def save(self, commit=True): + paid = super(PaidCreateForm, self).save(commit=False) + if commit: + expo = self.cleaned_data['exposition'] + tickets = self.cleaned_data['tickets'] + tickets_link = Banner.objects.create_for_paid(expo, tickets, 'tickets') + participation = self.cleaned_data['participation'] + participation_link = Banner.objects.create_for_paid(expo, participation, 'participation') + official = self.cleaned_data['official'] + official_link = Banner.objects.create_for_paid(expo, official, 'official') + catalog = expo.get_permanent_url() + catalog_link = Banner.objects.create_for_paid(expo, catalog, 'catalog') + + + paid.tickets = tickets_link + paid.participation = participation_link + paid.official = official_link + paid.catalog = catalog_link + paid.save() + + expo.paid_new = paid + expo.save() + return paid + + def clean_exposition(self): + expo_id = self.cleaned_data['exposition'] + try: + expo = Exposition.objects.get(id=expo_id) + except Exposition.DoesNotExist: + raise forms.ValidationError(u'Такой выставки не существует') + return expo + +class PaidUpdateForm(forms.ModelForm): + tickets = forms.URLField(label=u'Линк на билеты') + participation = forms.URLField(label=u'Линк на участие') + official = forms.URLField(label=u'Линк на официальный сайт') + + class Meta: + model = Paid + fields = ['logo', 'organiser', 'public'] + + def save(self, commit=True): + paid = super(PaidUpdateForm, self).save(commit=False) + if commit: + tickets = self.cleaned_data['tickets'] + b_tickets = paid.tickets + if tickets != b_tickets.url: + b_tickets.url = tickets + b_tickets.save() + + participation = self.cleaned_data['participation'] + b_participation = paid.participation + if participation != b_participation.url: + b_participation.url = participation + b_participation.save() + + official = self.cleaned_data['official'] + b_official = paid.official + if official != b_official.url: + b_official.url = official + b_official.save() + + paid.save() + + return paid \ No newline at end of file diff --git a/expobanner/management/__init__.py b/expobanner/management/__init__.py new file mode 100644 index 00000000..13ef41a7 --- /dev/null +++ b/expobanner/management/__init__.py @@ -0,0 +1 @@ +__author__ = 'kotzilla' diff --git a/expobanner/management/commands/__init__.py b/expobanner/management/commands/__init__.py new file mode 100644 index 00000000..13ef41a7 --- /dev/null +++ b/expobanner/management/commands/__init__.py @@ -0,0 +1 @@ +__author__ = 'kotzilla' diff --git a/expobanner/management/commands/banner_log_check_previous_day.py b/expobanner/management/commands/banner_log_check_previous_day.py new file mode 100644 index 00000000..3a6a1f10 --- /dev/null +++ b/expobanner/management/commands/banner_log_check_previous_day.py @@ -0,0 +1,42 @@ +# -*- coding: utf-8 -*- +from datetime import date, timedelta +from django.core.management.base import BaseCommand +from expobanner.models import Log, LogStat, Banner +from django.conf import settings + + +class Command(BaseCommand): + def handle(self, *args, **options): + prev_day = date.today() - timedelta(days=1) + for banner in Banner.objects.select_related('group').filter(): + try: + logstat = LogStat.objects.get(banner=banner, group=banner.group, date=prev_day) + except LogStat.DoesNotExist: + logstat = LogStat(banner=banner, group=banner.group, date=prev_day) + + views = Log.objects.filter(datetime__startswith=prev_day, + banner=banner, + group=banner.group, + type=1).count() + clicks = Log.objects.filter(datetime__startswith=prev_day, + banner=banner, + group=banner.group, + type=2).count() + unique_views = Log.objects.filter(datetime__startswith=prev_day, + banner=banner, + group=banner.group, + type=1).values('ip').distinct().count() + unique_clicks = Log.objects.filter(datetime__startswith=prev_day, + banner=banner, + group=banner.group, + type=2).values('ip').distinct().count() + + if not logstat.click or logstat.click < clicks: + logstat.click = clicks + if not logstat.view or logstat.view < views: + logstat.view = views + if not logstat.unique_click or logstat.unique_click < unique_clicks: + logstat.unique_click = unique_clicks + if not logstat.unique_view or logstat.unique_view < unique_views: + logstat.unique_view = unique_views + logstat.save() diff --git a/expobanner/management/commands/banner_log_update.py b/expobanner/management/commands/banner_log_update.py new file mode 100644 index 00000000..86cfb920 --- /dev/null +++ b/expobanner/management/commands/banner_log_update.py @@ -0,0 +1,67 @@ +# -*- coding: utf-8 -*- +from datetime import date +from django.core.management.base import BaseCommand +from expobanner.models import Log, LogStat, Banner, PaidStat +from exposition.models import Exposition + + +class Command(BaseCommand): + def handle(self, *args, **options): + today = date.today() + # banners + for banner in Banner.objects.select_related('group').filter(public=True, group__isnull=False): + try: + logstat = LogStat.objects.get(banner=banner, group=banner.group, date=today) + except LogStat.DoesNotExist: + logstat = LogStat(banner=banner, group=banner.group, date=today) + + views = Log.objects.filter(datetime__startswith=today, + banner=banner, + group=banner.group, + type=1).count() + clicks = Log.objects.filter(datetime__startswith=today, + banner=banner, + group=banner.group, + type=2).count() + unique_views = Log.objects.filter(datetime__startswith=today, + banner=banner, + group=banner.group, + type=1).values('ip').distinct().count() + unique_clicks = Log.objects.filter(datetime__startswith=today, + banner=banner, + group=banner.group, + type=2).values('ip').distinct().count() + logstat.click = clicks + logstat.view = views + logstat.unique_click = unique_clicks + logstat.unique_view = unique_views + logstat.save() + + # paid expos + expos = list(Exposition.objects.select_related('paid_new').filter(paid_new__isnull=False)) + for expo in expos: + paid = expo.paid_new + try: + paidstat = PaidStat.objects.get(paid=paid, date=today) + except PaidStat.DoesNotExist: + paidstat = PaidStat(paid=paid, date=today) + + t_clicks = Log.objects.filter(datetime__startswith=today, banner=paid.tickets, type=2).count() + p_clicks = Log.objects.filter(datetime__startswith=today, banner=paid.participation, type=2).count() + o_clicks = Log.objects.filter(datetime__startswith=today, banner=paid.official, type=2).count() + c_clicks = Log.objects.filter(datetime__startswith=today, banner=paid.catalog, type=2).count() + + paidstat.tickets_clicks = t_clicks + paidstat.participation_clicks = p_clicks + paidstat.official_clicks = o_clicks + paidstat.catalog_clicks = c_clicks + + paidstat.save() + + + + + + + + diff --git a/expobanner/managers.py b/expobanner/managers.py index 0735f53c..dfc42384 100644 --- a/expobanner/managers.py +++ b/expobanner/managers.py @@ -23,6 +23,10 @@ class BiasedManager(models.Manager): shuffle(result) return result + def create_for_paid(self, expo, url, role): + alt = u'%s_%s'%(expo.name, role) + return self.create(alt=alt, url=url, paid=True) + class BannerGroupCached(models.Manager): def all(self): key = 'banner_group_all' diff --git a/expobanner/mixins.py b/expobanner/mixins.py new file mode 100644 index 00000000..9520ab37 --- /dev/null +++ b/expobanner/mixins.py @@ -0,0 +1,3 @@ +class StatMixin(object): + def get_cookie_name(self): + return u'%s_%d'%(self._meta.db_table, self.id) \ No newline at end of file diff --git a/expobanner/models.py b/expobanner/models.py index b4ceef75..436abfa5 100644 --- a/expobanner/models.py +++ b/expobanner/models.py @@ -1,11 +1,14 @@ # -*- coding: utf-8 -*- +import random import hashlib from datetime import datetime, date from django.db import models from django.utils.translation import ugettext_lazy as _ from django.conf import settings from django.contrib.sites.models import Site +from django.db.models.signals import post_save from .managers import BiasedManager, BannerGroupCached, URLCached +from .mixins import StatMixin from theme.models import Theme from country.models import Country @@ -64,7 +67,7 @@ class BannerGroup (models.Model): return '/admin/expobanners/banners/group/%d/edit/'%self.id -class Banner(models.Model): +class Banner(models.Model, StatMixin): objects = BiasedManager() title = models.CharField(verbose_name=u'Заголовок', max_length=255, blank=True) @@ -92,13 +95,18 @@ class Banner(models.Model): html = models.BooleanField(verbose_name=_('HTML?'), default=False) flash = models.BooleanField(verbose_name=_('Flash?'), default=False) + js = models.BooleanField(verbose_name=_('Javascript?'), default=False) paid = models.BooleanField(verbose_name=_('Is Paid event link?'), default=False) - public = models.BooleanField(verbose_name=u'Активный', default=True) created_at = models.DateTimeField(verbose_name=_('Created At'), auto_now_add=True) updated_at = models.DateTimeField(verbose_name=_('Updated At'), auto_now=True) + stat_pswd = models.CharField(max_length=16) + + class Meta: + ordering = ['-public'] + def get_admin_url(self): return '/admin/expobanners/banners/banner/%d/edit/'%self.id @@ -110,10 +118,9 @@ class Banner(models.Model): key = str(datetime.now()) return hashlib.md5(key).hexdigest() - def log(self, request, type, key): + def log(self, request, type): log = { 'type': type, - 'key': key, 'banner': self, 'group': self.group, 'ip': request.META.get('REMOTE_ADDR'), @@ -150,6 +157,9 @@ class Banner(models.Model): return ('banner_click', (), {'banner_id': self.pk, 'key': self.key()}) return get_absolute_url(self) + def get_click_link(self): + return '/expo-b/click/%d/'%self.id + class Meta: ordering = ['sort'] verbose_name = _('Banner') @@ -158,7 +168,7 @@ class Banner(models.Model): class Log(models.Model): banner = models.ForeignKey(Banner, related_name='banner_logs') - group = models.ForeignKey(BannerGroup, related_name='group_logs', verbose_name=_('Group'), blank=True) + group = models.ForeignKey(BannerGroup, related_name='group_logs', verbose_name=_('Group'), blank=True, null=True) urls = models.ManyToManyField(URL, related_name='url_logs', verbose_name=_('URLs'), blank=True) user = models.ForeignKey(settings.AUTH_USER_MODEL, null=True, blank=True, related_name='users', verbose_name=_('User')) @@ -181,7 +191,7 @@ class Log(models.Model): class LogStat(models.Model): banner = models.ForeignKey(Banner, related_name='banner_stat', verbose_name=_('Banner'), blank=True) - group = models.ForeignKey(BannerGroup, related_name='group_stat', verbose_name=_('Group'), blank=True) + group = models.ForeignKey(BannerGroup, related_name='group_stat', verbose_name=_('Group'), blank=True, null=True) urls = models.ManyToManyField(URL, related_name='url_bloks', verbose_name=_('URLs'), null=True, blank=True) date = models.DateField(verbose_name=_('Data')) @@ -195,17 +205,26 @@ class LogStat(models.Model): # ------------------ -class Paid(models.Model): +class Paid(models.Model, StatMixin): tickets = models.ForeignKey(Banner, related_name='paid_tickets') participation = models.ForeignKey(Banner, related_name='paid_participation') official = models.ForeignKey(Banner, related_name='paid_official') - logo = models.ImageField(upload_to='/')# !!!!! - organiser = models.CharField(max_length=100) - active = models.BooleanField(default=True) + catalog = models.ForeignKey(Banner, related_name='paid_catalog') + logo = models.ImageField(upload_to='expo-b/paid', blank=True) + organiser = models.CharField(max_length=100, blank=True) + public = models.BooleanField(default=True, verbose_name=u'Активная') stat_pswd = models.CharField(max_length=16) created = models.DateTimeField(auto_now_add=True) modified = models.DateTimeField(auto_now=True) + class Meta: + ordering = ['-public'] + + def get_event(self): + if self.exposition_set.all().exists(): + return self.exposition_set.all()[0] + return None + class PaidStat(models.Model): paid = models.ForeignKey(Paid) @@ -214,9 +233,12 @@ class PaidStat(models.Model): price_views = models.PositiveIntegerField(default=0) catalog_views = models.PositiveIntegerField(default=0) catalog_clicks = models.PositiveIntegerField(default=0) + tickets_clicks = models.PositiveIntegerField(default=0) + participation_clicks = models.PositiveIntegerField(default=0) + official_clicks = models.PositiveIntegerField(default=0) -class Top(models.Model): +class Top(models.Model, StatMixin): catalog = models.CharField(max_length=16) position = models.PositiveIntegerField(blank=True, null=True) theme = models.ManyToManyField('theme.Theme', blank=True, null=True) @@ -238,4 +260,32 @@ class TopStat(models.Model): country = models.ForeignKey('country.Country', blank=True, null=True) city = models.ForeignKey('city.City', blank=True, null=True) views = models.PositiveIntegerField(default=0) - clicks = models.PositiveIntegerField(default=0) \ No newline at end of file + clicks = models.PositiveIntegerField(default=0) + +def generatePassword(length=5): + """ + generate random password + """ + SYMBOLS = [',', '.', '?', '!', '-', '+', '1', '2', '3', '4', '5', '6', '7', '8', + '9', '0', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', + 'm', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 'A', + 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', + 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '#'] + PASSWORD_LENGTH = length + newPassword = [] + for i in range(PASSWORD_LENGTH): + newPassword.append(SYMBOLS[random.randrange(0, len(SYMBOLS))]) + return ''.join(newPassword) + + +def generate_stat_pass(sender, **kwargs): + obj = kwargs['instance'] + if not obj.stat_pswd: + obj.stat_pswd = generatePassword() + obj.save() + + + +post_save.connect(generate_stat_pass, sender=Banner) +post_save.connect(generate_stat_pass, sender=Paid) +post_save.connect(generate_stat_pass, sender=Top) diff --git a/expobanner/stat_views.py b/expobanner/stat_views.py new file mode 100644 index 00000000..a1ac7ae7 --- /dev/null +++ b/expobanner/stat_views.py @@ -0,0 +1,57 @@ +# -*- coding: utf-8 -*- +from django.http import HttpResponseRedirect +from django.views.generic import TemplateView, CreateView, ListView, UpdateView, DetailView +from django.views.generic.edit import FormMixin +from django.forms.util import ErrorList +from django.conf import settings +from django.core.urlresolvers import reverse +from expobanner.models import Banner, Paid +from expobanner.forms import ClientStatForm + + + +class BannerStat(FormMixin, DetailView): + model = Banner + form_class = ClientStatForm + template_name = 'client/expobanners/banner_stat.html' + + def get_success_url(self): + return reverse('banner_stat_client', kwargs={'pk': self.object.pk}) + + def get_context_data(self, **kwargs): + context = super(BannerStat, self).get_context_data(**kwargs) + obj = self.object + cookie_name = obj.get_cookie_name() + cookie = self.request.session.get(cookie_name) + if not cookie: + form = context.get('form') + # form in context if form invalid called + if not form: + context['form'] = self.get_form(self.form_class) + + return context + + def post(self, request, *args, **kwargs): + self.object = self.get_object() + form = self.get_form(self.form_class) + if form.is_valid(): + return self.form_valid(form) + else: + return self.form_invalid(form) + + def form_valid(self, form): + obj = self.object + success = form.check_pass(obj) + if success: + self.request.session[obj.get_cookie_name()] = 1 + return HttpResponseRedirect(self.get_success_url()) + else: + form.errors['stat_pswd'] = ErrorList([u'Неправильный пароль']) + return self.form_invalid(form) + +class PaidStat(BannerStat): + model = Paid + template_name = 'client/expobanners/paid_stat.html' + + def get_success_url(self): + return reverse('paid_stat_client', kwargs={'pk': self.object.pk}) \ No newline at end of file diff --git a/expobanner/urls.py b/expobanner/urls.py index 4371bc5f..801aece7 100644 --- a/expobanner/urls.py +++ b/expobanner/urls.py @@ -1,11 +1,12 @@ from django.conf.urls import url - +from expobanner.stat_views import * from . import views urlpatterns = [ - url(r'^click/(?P\d{1,4})/(?P[-\w]+)/$', views.click, name='banner_click'), - url(r'^view/(?P\d+)/(?P[-\w]+)/$', views.view, name='banner_view'), - + url(r'^click/(?P\d{1,4})/$', views.click, name='banner_click'), + #url(r'^view/(?P\d+)/$', views.view, name='banner_view'), # url(r'^get-banners/$', views.get_banners), + url(r'^banner/(?P\d+)/stat/$', BannerStat.as_view(), name='banner_stat_client'), + url(r'^paid/(?P\d+)/stat/$', PaidStat.as_view(), name='paid_stat_client'), ] diff --git a/expobanner/utils.py b/expobanner/utils.py new file mode 100644 index 00000000..50e2f2c6 --- /dev/null +++ b/expobanner/utils.py @@ -0,0 +1,73 @@ +# -*- coding: utf-8 -*- +import random +from django.db import connection + +def get_client_ip(request): + x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR') + if x_forwarded_for: + ip = x_forwarded_for.split(',')[0] + else: + ip = request.META.get('REMOTE_ADDR') + return ip + +def get_by_sort(banner_list): + max_sort = 0 + for banner in banner_list: + sort = banner.sort + if sort > max_sort: + max_sort = sort + result = [banner for banner in banner_list if banner.sort == max_sort] + return result + + +def get_banner_by_params(banners_list, urls, params): + print('START. NUMBER of queries = %d'%len(connection.queries)) + thematic_banners = [] + url_banners = [] + + for banner in banners_list: + #print('-------------------------') + #print('number of queries = %d'%len(connection.queries)) + + # check by theme + banner_theme_ids = [str(theme.id) for theme in banner.theme.all()] + #print('number of queries = %d'%len(connection.queries)) + + if banner_theme_ids: + if params.get('theme'): + theme = params['theme'] + if theme in banner_theme_ids: + thematic_banners.append(banner) + continue + # check by country + banner_country_ids = [str(country.id) for country in banner.country.all()] + #print('number of queries = %d'%len(connection.queries)) + if banner_country_ids: + if params.get('country'): + + country = params['country'] + if country in banner_country_ids: + thematic_banners.append(banner) + continue + + # check by url + if urls: + banner_urls = banner.urls.all() + print('number of queries = %d'%len(connection.queries)) + + if banner_urls: + + banner_urls = set(banner_urls) + common_urls = set(urls).intersection(banner_urls) + + if common_urls: + url_banners.append(banner) + continue + print('-------------------------') + if thematic_banners: + return random.choice(thematic_banners) + if url_banners: + return random.choice(url_banners) + return None + + #print('END. NUMBER of queries = %d'%len(connection.queries)) diff --git a/expobanner/views.py b/expobanner/views.py index b854325b..fd2763a6 100644 --- a/expobanner/views.py +++ b/expobanner/views.py @@ -1,97 +1,27 @@ # -*- coding: utf-8 -*- import json import re -import random from django.http import HttpResponse from django.shortcuts import redirect, get_object_or_404 from .models import Banner, BannerGroup, URL +from expobanner.utils import get_by_sort, get_banner_by_params, get_client_ip -def click(request, banner_id, key): +def click(request, banner_id): banner = get_object_or_404(Banner, pk=banner_id) - banner.log(request, 2, key) + banner.log(request, 2) return redirect(banner.url) -def view(request, banner_id, key): +def view(request, banner_id): banner = get_object_or_404(Banner, pk=banner_id) - banner.log(request, 1, key) + banner.log(request, 1) return redirect(banner.img.url) - -def get_client_ip(request): - x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR') - if x_forwarded_for: - ip = x_forwarded_for.split(',')[0] - else: - ip = request.META.get('REMOTE_ADDR') - return ip - -def get_by_sort(banner_list): - max_sort = 0 - for banner in banner_list: - sort = banner.sort - if sort > max_sort: - max_sort = sort - result = [banner for banner in banner_list if banner.sort == max_sort] - return result - -from django.db import connection -def get_banner_by_params(banners_list, urls, params): - print('START. NUMBER of queries = %d'%len(connection.queries)) - good_banners = [] - - for banner in banners_list: - print('-------------------------') - print('number of queries = %d'%len(connection.queries)) - print(banner) - # check by theme - banner_theme_ids = [str(theme.id) for theme in banner.theme.all()] - print('number of queries = %d'%len(connection.queries)) - - if banner_theme_ids: - if params.get('theme'): - theme = params['theme'] - if theme in banner_theme_ids: - good_banners.append(banner) - continue - # check by country - banner_country_ids = [str(country.id) for country in banner.country.all()] - print('number of queries = %d'%len(connection.queries)) - if banner_country_ids: - if params.get('country'): - - country = params['country'] - if country in banner_country_ids: - good_banners.append(banner) - continue - - # check by url - if urls: - banner_urls = banner.urls.all() - print('number of queries = %d'%len(connection.queries)) - - if banner_urls: - - banner_urls = set(banner_urls) - common_urls = set(urls).intersection(banner_urls) - - if common_urls: - good_banners.append(banner) - continue - print('-------------------------') - good_banners = get_by_sort(good_banners) - - print('END. NUMBER of queries = %d'%len(connection.queries)) - - - if good_banners: - return random.choice(good_banners) - return [] - def get_banners(request): + #url = request.GET.get('url', '/') + url = request.META.get('HTTP_REFERER', '/') # get urls by current url - url = request.GET.get('url', '/') urls = URL.cached.all() good_urls = [] for u in urls: @@ -110,17 +40,31 @@ def get_banners(request): group_banners = BannerGroup.cached.group_banners() result = [] + # get banners for all groups for group, banners in group_banners.iteritems(): banner = get_banner_by_params(banners, good_urls, params) - result.append({'id': group, - 'url': banner.url, - 'is_html': banner.html, - 'is_flash': banner.flash, - 'is_img': True, - 'html': banner.text, - 'img': banner.img.url - }) - - return HttpResponse(json.dumps(result, indent=4), content_type='application/json') - - + if banner: + if banner.js or banner.html: + text = banner.text + img = '' + alt = '' + is_img = False + else: + text = '' + img = banner.img.url + alt = banner.alt + is_img = True + result.append({'id': group, + 'url': banner.get_click_link(), + 'is_html': banner.html, + 'is_flash': banner.flash, + 'is_img': is_img, + 'is_js': banner.js, + 'img': img, + 'alt': alt, + 'text': text + }) + # add view log + banner.log(request, 1) + + return HttpResponse(json.dumps(result, indent=4), content_type='application/json') \ No newline at end of file diff --git a/exposition/models.py b/exposition/models.py index dce42537..ed34bff5 100644 --- a/exposition/models.py +++ b/exposition/models.py @@ -155,6 +155,8 @@ class Exposition(TranslatableModel, EventMixin, ExpoMixin): max_open_area = models.PositiveIntegerField(verbose_name='Максимальная цена открытой площади', blank=True, null=True) registration_payment = models.PositiveIntegerField(verbose_name='Регистрационный взнос', blank=True, null=True) + + paid_new = models.ForeignKey('expobanner.Paid', blank=True, null=True, on_delete=models.SET_NULL) #set manager of this model(fisrt manager is default) objects = ExpoManager() enable = ClientManager() diff --git a/exposition/views.py b/exposition/views.py index 48b55b3b..b6464599 100644 --- a/exposition/views.py +++ b/exposition/views.py @@ -151,6 +151,7 @@ class ExpoDetail(JitterCacheMixin, MetadataMixin, DetailView): model = Exposition slug_field = 'url' template_name = 'client/exposition/exposition_detail.html' + queryset = Exposition.objects.language().select_related('place', 'city', 'country', 'paid_new') def get_context_data(self, **kwargs): context = super(ExpoDetail, self).get_context_data(**kwargs) @@ -167,6 +168,7 @@ class ExpositionPrice(MetadataMixin, DetailView): model = Exposition slug_field = 'url' template_name = 'client/exposition/price.html' + queryset = Exposition.objects.language().select_related('place', 'city', 'country', 'paid_new') @@ -375,6 +377,11 @@ class ExpoCountryCatalog(ExpoCatalog): qs = self.model.enable.upcoming().filter(country=country) return qs + def get_context_data(self, **kwargs): + context = super(ExpoCountryCatalog, self).get_context_data(**kwargs) + context['country'] = str(self.kwargs['country'].id) + return context + class ExpoCityCatalog(ExpoCatalog): catalog_url = '/expo/city/' def get_filtered_qs(self): @@ -385,6 +392,10 @@ class ExpoCityCatalog(ExpoCatalog): qs = self.model.enable.upcoming().filter(city=city) self.filter_object = city return qs + def get_context_data(self, **kwargs): + context = super(ExpoCityCatalog, self).get_context_data(**kwargs) + context['city'] = str(self.kwargs['city'].id) + return context class ExpoThemeCatalog(ExpoCatalog): @@ -423,10 +434,11 @@ class ExpoThemeCatalog(ExpoCatalog): def get_context_data(self, **kwargs): context = super(ExpoThemeCatalog, self).get_context_data(**kwargs) if self.country: - context['country'] = self.country + context['country'] = str(self.country.id) if self.city: - context['city'] = self.city + context['city'] = str(self.city.id) context['theme_for_filter'] = self.kwargs['theme'] + context['themes'] = [str(self.kwargs['theme'].id)] return context @@ -449,6 +461,8 @@ class ExpoTagCatalog(ExpoCatalog): context = super(ExpoTagCatalog, self).get_context_data(**kwargs) tag = self.kwargs['tag'] context['theme_for_filter'] = tag.theme + context['themes'] = [str(tag.theme.id)] + context['tag'] = str(self.kwargs['tag'].id) return context diff --git a/functions/admin_views.py b/functions/admin_views.py index cb2f18a2..0fb38183 100644 --- a/functions/admin_views.py +++ b/functions/admin_views.py @@ -126,10 +126,7 @@ class AdminListView(FormView): def get_context_data(self, **kwargs): context = super(AdminListView, self).get_context_data(**kwargs) - if hasattr(self.model,'user'): - qs = self.model.objects.language().order_by('user__first_name') - else: - qs = self.model.objects.order_by('first_name') + qs = self.model.objects.language().all().order_by('name') result = paginate_results(qs, page=self.request.GET.get('page')) context['object_list'] = result return context diff --git a/functions/model_mixin.py b/functions/model_mixin.py index a96c53cc..5577ac9c 100644 --- a/functions/model_mixin.py +++ b/functions/model_mixin.py @@ -34,6 +34,9 @@ class EventMixin(object): url = '%s%s/'%(self.get_catalog_url(), self.url) return url + def get_paid_catalog_url(self): + return self.paid_new.catalog.get_click_link() + def org_split(self): if self.org: return self.org.split(';') diff --git a/meta/models.py b/meta/models.py index c3be90d8..0bd6bdc0 100644 --- a/meta/models.py +++ b/meta/models.py @@ -127,9 +127,7 @@ from django.core.cache import cache class SeoTextManager(TranslationManager): cache_time = 120 - def cache_get(self, *args, **kwargs): - # ПЕРЕРОБИТИ url = kwargs.get('url') lang = kwargs.get('lang')[:2] or translation.get_language()[:2] key = 'seo_text_cache' @@ -137,7 +135,7 @@ class SeoTextManager(TranslationManager): if result: return result.get(lang+'_' + url) - qs = SeoText.objects.language('all') + qs = list(SeoText.objects.language('all')) value_dict = {obj.language_code+'_'+obj.url:obj for obj in qs} cache.set(key, value_dict, self.cache_time) return value_dict.get(lang+'_'+url) diff --git a/proj/settings.py b/proj/settings.py index 678d9aa5..c2828869 100644 --- a/proj/settings.py +++ b/proj/settings.py @@ -352,7 +352,6 @@ INSTALLED_APPS = ( 'pytils', # ?? 'pymorphy', # ?? 'password_reset', # reset password - 'django_crontab', # crons 'social.apps.django_app.default', # social auth 'core', ) @@ -402,14 +401,21 @@ LOGGING = { } } -CRONJOBS = [ - ('0 */1 * * *', 'django.core.management.call_command', ['update_index conference --age=1']), - ('0 */1 * * *', 'django.core.management.call_command', ['update_index exposition --age=1']), - ('0 */12 * * *', 'django.core.management.call_command', ['update_index place_exposition --age=12']), - ('0 */24 * * *', 'django.core.management.call_command', ['update_index company --age=24']), - ('0 */24 * * *', 'django.core.management.call_command', ['update_index theme --age=24']), - ('0 */24 * * *', 'django.core.management.call_command', ['update_index tag --age=24']), -] +# TODO automate crons +""" +# update search indexes +0 * * * * /usr/bin/python /var/www/proj/manage.py update_index conference --remove --age=6 +0 * * * * /usr/bin/python /var/www/proj/manage.py update_index exposition --remove --age=6 +0 1,13 * * * /usr/bin/python /var/www/proj/manage.py update_index place_exposition --remove --age=24 +0 3 * * * /usr/bin/python /var/www/proj/manage.py update_index company --remove --age=48 +0 4 * * * /usr/bin/python /var/www/proj/manage.py update_index theme --remove --age=48 +0 5 * * * /usr/bin/python /var/www/proj/manage.py update_index tag --remove --age=48 +0 6 * * * /usr/bin/python /var/www/proj/manage.py update_index country --remove --age=48 +0 7 * * * /usr/bin/python /var/www/proj/manage.py update_index city --remove --age=48 +# update banner logs +10 * * * * /usr/bin/python /var/www/proj/manage.py banner_log_update +20 2,14 * * * /usr/bin/python /var/www/proj/manage.py banner_log_check_previous_day +""" THUMBNAIL_DEBUG = DEBUG diff --git a/templates/admin/expobanner/banner_list.html b/templates/admin/expobanner/banner_list.html new file mode 100644 index 00000000..2b41f228 --- /dev/null +++ b/templates/admin/expobanner/banner_list.html @@ -0,0 +1,36 @@ +{% extends 'base.html' %} + +{% block body %} + +
+
+

{{ verbose }}

+
+
+ {% block list_table %} + + + + + + + + + + + {% for item in object_list %} + + + + + + {% endfor %} + +
Объект  
{{ item }}Изменить Статистика
+ {% endblock %} +
+ {# pagination #} + {% include 'admin/includes/admin_pagination.html' with page_obj=object_list %} +
+ +{% endblock %} \ No newline at end of file diff --git a/templates/admin/expobanner/banner_stat.html b/templates/admin/expobanner/banner_stat.html new file mode 100644 index 00000000..15d51bc2 --- /dev/null +++ b/templates/admin/expobanner/banner_stat.html @@ -0,0 +1,43 @@ +{% extends 'base.html' %} +{% load static %} +{% block scripts %} + +{% endblock %} + + +{% block body %} +
+
+
+

{{ object }} (Пароль: {{ object.stat_pswd }})

+
+
+ + + + + + + + + + + + {% with stats=object.banner_stat.all %} + {% for stat in stats %} + + + + + + + + {% endfor %} + {% endwith %} + +
ДатаПоказыКликиУникальные показыУникальные клики
{{ stat.date|date:"Y-m-d" }}{{ stat.view }}{{ stat.click }}{{ stat.unique_view }}{{ stat.unique_click }}
+
+
+
+ +{% endblock %} \ No newline at end of file diff --git a/templates/admin/expobanner/paid_create.html b/templates/admin/expobanner/paid_create.html new file mode 100644 index 00000000..4e3af395 --- /dev/null +++ b/templates/admin/expobanner/paid_create.html @@ -0,0 +1,71 @@ +{% extends 'base.html' %} +{% load static %} + +{% block scripts %} +{# selects #} + + + +{% endblock %} + +{% block body %} +
{% csrf_token %} +
+
+
+

{{ form.verbose }}

+
+
+ {% for field in form %} +
+ +
{{ field }} + {{ field.errors }} +
+
+ {% endfor %} +
+
+
+ +
+ + +
+
+{% endblock %} \ No newline at end of file diff --git a/templates/admin/expobanner/paid_list.html b/templates/admin/expobanner/paid_list.html new file mode 100644 index 00000000..81402128 --- /dev/null +++ b/templates/admin/expobanner/paid_list.html @@ -0,0 +1,38 @@ +{% extends 'base.html' %} + +{% block body %} + +
+
+

Список проплаченых выставок

+
+
+ {% block list_table %} + Добавить выставку + + + + + + + + + + + {% for item in object_list %} + + + + + + + {% endfor %} + +
Выставка   
{{ item }}Изменить {% if item.paid_new.public %}отключить{% else %}включить{% endif %} Статистика
+ {% endblock %} +
+ {# pagination #} + {% include 'admin/includes/admin_pagination.html' with page_obj=object_list %} +
+ +{% endblock %} \ No newline at end of file diff --git a/templates/admin/expobanner/paid_stat.html b/templates/admin/expobanner/paid_stat.html new file mode 100644 index 00000000..b935251c --- /dev/null +++ b/templates/admin/expobanner/paid_stat.html @@ -0,0 +1,43 @@ +{% extends 'base.html' %} +{% load static %} +{% block scripts %} + +{% endblock %} + + +{% block body %} +
+
+
+

{{ object.get_event }} (Пароль: {{ object.stat_pswd }})

+
+
+ + + + + + + + + + + + {% with stats=object.paidstat_set.all %} + {% for stat in stats %} + + + + + + + + {% endfor %} + {% endwith %} + +
ДатаОфициальный сайтБилетыУчастиеПереходы с каталога
{{ stat.date|date:"Y-m-d" }}{{ stat.official_clicks }}{{ stat.tickets_clicks }}{{ stat.participation_clicks }}{{ stat.catalog_clicks }}
+
+
+
+ +{% endblock %} \ No newline at end of file diff --git a/templates/admin/expobanner/paid_update.html b/templates/admin/expobanner/paid_update.html new file mode 100644 index 00000000..d9b82a11 --- /dev/null +++ b/templates/admin/expobanner/paid_update.html @@ -0,0 +1,32 @@ +{% extends 'base.html' %} +{% load static %} + +{% block scripts %} +{% endblock %} + +{% block body %} +
{% csrf_token %} +
+
+
+

{{ exposition }}

+
+
+ {% for field in form %} +
+ +
{{ field }} + {{ field.errors }} +
+
+ {% endfor %} +
+
+
+ +
+ + +
+
+{% endblock %} \ No newline at end of file diff --git a/templates/admin/includes/admin_nav.html b/templates/admin/includes/admin_nav.html index 9f33389b..ac114c8b 100644 --- a/templates/admin/includes/admin_nav.html +++ b/templates/admin/includes/admin_nav.html @@ -109,6 +109,7 @@ Реклама diff --git a/templates/client/base_catalog.html b/templates/client/base_catalog.html index 24827f0b..106ec884 100644 --- a/templates/client/base_catalog.html +++ b/templates/client/base_catalog.html @@ -17,6 +17,7 @@
{% include 'client/includes/online_consult.html' %} + {% include 'client/includes/banners/aside_1.html' %} {% block aside_banner1 %} {% if theme_for_filter.id == 27 or theme_for_filter.id == 9 or theme_for_filter.id == 48 %} @@ -52,15 +53,19 @@ {% endblock %} {% include 'client/includes/side_confs.html' %}
+ {% include 'client/includes/banners/aside_2.html' %} +
{% include 'client/includes/news.html' with news=news_list %}
+ {% include 'client/includes/banners/aside_3.html' %} {% block aside_vk %}
{% include 'client/includes/social_widjet.html' %}
{% endblock %} + {% include 'client/includes/banners/aside_4.html' %}
@@ -68,7 +73,7 @@ {% include 'client/includes/catalog_search.html' %} {% endwith %} {% block under_search_baner %} - {% include 'client/includes/banners/under_search.html' %} + {% include 'client/includes/banners/search_under.html' %} {% endblock %} {% block bread_scrumbs %} diff --git a/templates/client/blank.html b/templates/client/blank.html index 5c14ac22..6ffdd844 100644 --- a/templates/client/blank.html +++ b/templates/client/blank.html @@ -77,51 +77,17 @@ This template include basic anf main styles and js files, socialInputMask:['http://','https://'] }); - - - - - + + {% include 'client/includes/banners/catalog_inner.html' %} {%endif %} {% endfor %} diff --git a/templates/client/includes/exposition/exposition_object.html b/templates/client/includes/exposition/exposition_object.html index 18d2a2c7..8ae51315 100644 --- a/templates/client/includes/exposition/exposition_object.html +++ b/templates/client/includes/exposition/exposition_object.html @@ -208,29 +208,7 @@

- + {% include 'client/includes/banners/detail_inner.html' %}

diff --git a/templates/client/includes/exposition/price.html b/templates/client/includes/exposition/price.html index b7006c6a..f2470f8b 100644 --- a/templates/client/includes/exposition/price.html +++ b/templates/client/includes/exposition/price.html @@ -151,14 +151,15 @@
- {% if not exposition.paid %} - {% if exposition.country_id in sng_countries %} - {% else %} - {% trans 'Заказать билет' %} - {% endif %} + {% if exposition.paid_new_id and exposition.paid_new.public %} + {% trans 'Заказать билет' %} + {% else %} + {% if exposition.country_id in sng_countries %} {% else %} - {% trans 'Заказать билет' %} + {% trans 'Заказать билет' %} {% endif %} + {% endif %} +
{% if exposition.get_audience %}
@@ -222,10 +223,10 @@ {% else %}

{% trans 'Цены на площадь доступны по запросу' %}

{% endif %} - {% if not exposition.paid %} - {% trans 'Заявка на участие' %} + {% if exposition.paid_new_id and exposition.paid_new.public %} + {% trans 'Заявка на участие' %} {% else %} - {% trans 'Заявка на участие' %} + {% trans 'Заявка на участие' %} {% endif %} {% if exposition.min_stand_size or exposition.registration_payment or exposition.application_deadline %} diff --git a/templates/client/includes/header.html b/templates/client/includes/header.html index a58bb786..911ea5a4 100644 --- a/templates/client/includes/header.html +++ b/templates/client/includes/header.html @@ -37,7 +37,6 @@ {% endfor %} {% if user.is_staff %}
  • admin
  • -
  • TEST
  • {% endif %}
    @@ -98,19 +97,7 @@
    -
    - {% block header_banner %} - - - - - {% endblock %} -
    + {% include 'client/includes/banners/header.html' %}