From 9e19d6c57d1325c4aa184774a3b980fb2c3e3ea8 Mon Sep 17 00:00:00 2001 From: Ivan Kovalkovskyi Date: Wed, 30 Sep 2015 17:52:53 +0300 Subject: [PATCH 01/16] service form and views --- service/admin.py | 27 +++- service/admin_urls.py | 5 +- service/forms.py | 11 +- templates/admin/service/service_add.html | 2 +- templates/admin/service/test_add.html | 155 +++++++++++++++++++++++ 5 files changed, 196 insertions(+), 4 deletions(-) create mode 100644 templates/admin/service/test_add.html diff --git a/service/admin.py b/service/admin.py index 91ae029d..050c0d9e 100644 --- a/service/admin.py +++ b/service/admin.py @@ -141,4 +141,29 @@ class ServiceControl(FormMixin, DetailView): def get_context_data(self, **kwargs): context = super(ServiceControl, self).get_context_data(**kwargs) context['form'] = self.get_form(self.form_class) - return context \ No newline at end of file + return context + +from .forms import _ServiceForm + +class ServiceAddView(FormView): + form_class = _ServiceForm + template_name = 'admin/service/test_add.html' + success_url = '/' + + def get(self, request, *args, **kwargs): + data = request.GET + form = self.form_class(data) + + if form.is_valid(): + countries = form.cleaned_data['countries'] + types = form.cleaned_data['type'] + expos = form.cleaned_data['expos'] + confs = form.cleaned_data['confs'] + is_all_cnt = form.cleaned_data['all_counties'] + raise + else: + pass + + + + diff --git a/service/admin_urls.py b/service/admin_urls.py index 4dda045f..2ed5c296 100644 --- a/service/admin_urls.py +++ b/service/admin_urls.py @@ -2,7 +2,7 @@ from django.conf.urls import patterns, include, url from views import CallBackListView, VisitListView, TranslationListView, AdvertisingListView, \ ParticipationListView, RemoteListView,TicketsListView -from service.admin import ServiceControlList, ServiceControl +from service.admin import ServiceControlList, ServiceControl, ServiceAddView urlpatterns = patterns('service.admin', url(r'^control/list/$', ServiceControlList.as_view()), @@ -18,8 +18,11 @@ urlpatterns = patterns('service.admin', url(r'order/participation/$', ParticipationListView.as_view()), url(r'order/remote/$', RemoteListView.as_view()), url(r'order/tickets/$', TicketsListView.as_view()), + url('^test/$', ServiceAddView.as_view()), #ajax url(r'^get_city/$', 'get_city'), + url('^get_expos/$', 'get_country'), + #url(r'^get_country/$', 'get_country'), ) diff --git a/service/forms.py b/service/forms.py index 946b0d64..11c0eaa2 100644 --- a/service/forms.py +++ b/service/forms.py @@ -146,4 +146,13 @@ class ServiceControlForm(forms.Form): self.fields['event_type'] = forms.MultipleChoiceField(required=False, label = 'Тип события', widget=forms.CheckboxSelectMultiple(), choices=[(item['service_bit'], item['verbose']) - for item in self.event]) \ No newline at end of file + for item in self.event]) +from bitfield import BitField + + +class _ServiceForm(forms.Form): + type = forms.MultipleChoiceField(choices=[(x, x) for x in Service.type], widget=forms.CheckboxSelectMultiple) + countries = forms.MultipleChoiceField(choices=[(x.id,x.name) for x in Country.objects.language().all()]) + all_counties = forms.BooleanField(widget=forms.CheckboxInput) + expos = forms.CharField(widget=forms.HiddenInput) + confs = forms.CharField(widget=forms.HiddenInput) \ No newline at end of file diff --git a/templates/admin/service/service_add.html b/templates/admin/service/service_add.html index ce487c45..9c5b2403 100644 --- a/templates/admin/service/service_add.html +++ b/templates/admin/service/service_add.html @@ -48,7 +48,7 @@ {% include 'admin/forms/multilang.html' %} {% endwith %} {# url #} -
+
{{ form.url }} diff --git a/templates/admin/service/test_add.html b/templates/admin/service/test_add.html new file mode 100644 index 00000000..559f655a --- /dev/null +++ b/templates/admin/service/test_add.html @@ -0,0 +1,155 @@ +{% extends 'base.html' %} +{% load static %} + + {% block scripts %} + + {# selects #} + + + + + + + {% endblock %} + +{% block body %} + +{# Uses multilang.html template for translated fields #} +
+{{ form.errors }} +
+ +
+ {{ form.type }} +
+
+
+ +
+ {{ form.countries }} +
+
+
+ +
+ {{ form.all_counties }} +
+
+ +
+ +
+ {{ form.expos }} +
+
+
+ +
+ {{ form.confs }} +
+
+
+
+ + +
+
+
+ + +{% endblock %} \ No newline at end of file From d738fccd86d135ef2cc149150e2eacbfbcf0d0e8 Mon Sep 17 00:00:00 2001 From: Ivan Kovalkovskyi Date: Thu, 1 Oct 2015 17:34:36 +0300 Subject: [PATCH 02/16] =?UTF-8?q?=D1=87=D0=B5=D1=82=C3=90nothing=20work?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- service/admin.py | 29 +++++++++++++++++++++++++++-- service/admin_urls.py | 5 +++-- service/forms.py | 32 ++++++++++++++++++++++++++++++-- service/models.py | 15 ++++++++++++++- 4 files changed, 74 insertions(+), 7 deletions(-) diff --git a/service/admin.py b/service/admin.py index 050c0d9e..ede3e3c1 100644 --- a/service/admin.py +++ b/service/admin.py @@ -164,6 +164,31 @@ class ServiceAddView(FormView): else: pass - - +from django.shortcuts import get_object_or_404 +from django.views.generic import UpdateView +from django.db.models import F +from django.db.models.query import EmptyQuerySet +from .forms import LinkedServiceForm +from .models import LinkedService +from exposition.models import Exposition +from conference.models import Conference + + +class ServiceUpdateView(UpdateView): + form_class = LinkedServiceForm + model = LinkedService + template_name = "admin/service/linked_service.html" + success_url = "/admin/service/all/" + + def get_object(self, queryset=None): + url = self.kwargs['url'] + service = get_object_or_404(Service, url=url) + obj = LinkedService.objects.get(service=service) + return obj + + def get_initial(self): + initial = { + 'expositions':','.join(["%s:%s"%(item.id, item.name) for item in object.expositions.all()]), + 'conferences':','.join(["%s:%s"%(item.id, item.name) for item in self.object.conferences.all()]) + } diff --git a/service/admin_urls.py b/service/admin_urls.py index 2ed5c296..c445dac2 100644 --- a/service/admin_urls.py +++ b/service/admin_urls.py @@ -2,7 +2,7 @@ from django.conf.urls import patterns, include, url from views import CallBackListView, VisitListView, TranslationListView, AdvertisingListView, \ ParticipationListView, RemoteListView,TicketsListView -from service.admin import ServiceControlList, ServiceControl, ServiceAddView +from service.admin import ServiceControlList, ServiceControl, ServiceAddView, ServiceUpdateView urlpatterns = patterns('service.admin', url(r'^control/list/$', ServiceControlList.as_view()), @@ -18,10 +18,11 @@ urlpatterns = patterns('service.admin', url(r'order/participation/$', ParticipationListView.as_view()), url(r'order/remote/$', RemoteListView.as_view()), url(r'order/tickets/$', TicketsListView.as_view()), + url('^test/(?P[a-z]*)/', ServiceUpdateView.as_view()), url('^test/$', ServiceAddView.as_view()), #ajax url(r'^get_city/$', 'get_city'), - url('^get_expos/$', 'get_country'), + #url(r'^get_country/$', 'get_country'), diff --git a/service/forms.py b/service/forms.py index 11c0eaa2..b62fac7f 100644 --- a/service/forms.py +++ b/service/forms.py @@ -147,7 +147,6 @@ class ServiceControlForm(forms.Form): widget=forms.CheckboxSelectMultiple(), choices=[(item['service_bit'], item['verbose']) for item in self.event]) -from bitfield import BitField class _ServiceForm(forms.Form): @@ -155,4 +154,33 @@ class _ServiceForm(forms.Form): countries = forms.MultipleChoiceField(choices=[(x.id,x.name) for x in Country.objects.language().all()]) all_counties = forms.BooleanField(widget=forms.CheckboxInput) expos = forms.CharField(widget=forms.HiddenInput) - confs = forms.CharField(widget=forms.HiddenInput) \ No newline at end of file + confs = forms.CharField(widget=forms.HiddenInput) + + +from .models import LinkedService +from django.db.models.query import EmptyQuerySet + + +class LinkedServiceForm(forms.ModelForm): + type = forms.MultipleChoiceField(choices = [(x, x) for x in list(Service.type)], widget = forms.CheckboxSelectMultiple) + + class Meta: + model = LinkedService + fields = ['countries', 'all_countries', 'expositions', 'conferences'] + widgets={ + 'expositions': forms.HiddenInput, + 'conferences': forms.HiddenInput + } + + def clean_expositions(self): + expositions = EmptyQuerySet() + if self.cleaned_data['expositions']: + expositions = Exposition.objects.language().filter(id__in=list(set(self.cleaned_data['expositions']))) + return expositions + + def clean_conferences(self): + conferences = EmptyQuerySet() + if self.cleaned_data['conferences']: + conferences = Conference.objects.language().filter(id__in=list(set(self.cleaned_data['conferences']))) + return conferences + diff --git a/service/models.py b/service/models.py index d0d711f3..c8d7946e 100644 --- a/service/models.py +++ b/service/models.py @@ -198,4 +198,17 @@ class CallBack(models.Model): viewed = models.DateTimeField(null=True, blank=True) class Meta: - ordering = ['-created'] \ No newline at end of file + ordering = ['-created'] + + +from country.models import Country +from exposition.models import Exposition +from conference.models import Conference + + +class LinkedService(models.Model): + service = models.ForeignKey(Service, blank=False) + countries = models.ManyToManyField(Country, blank=True) + all_countries = models.BooleanField(default=False) + expositions = models.ManyToManyField(Exposition, blank=True) + conferences = models.ManyToManyField(Conference, blank=True) From c09c058905b4d41db48289f608843dfb094f800d Mon Sep 17 00:00:00 2001 From: Ivan Kovalkovskyi Date: Fri, 2 Oct 2015 17:46:17 +0300 Subject: [PATCH 03/16] Linked service views and templates --- service/admin.py | 40 ++++- service/admin_urls.py | 8 +- service/forms.py | 27 ++- service/management/__init__.py | 1 + service/management/commands/__init__.py | 1 + .../commands/create_linked_services.py | 25 +++ service/models.py | 24 +++ templates/admin/service/linked_service.html | 162 ++++++++++++++++++ .../linked_service_confirm_delete.html | 11 ++ .../admin/service/linked_service_list.html | 48 ++++++ 10 files changed, 330 insertions(+), 17 deletions(-) create mode 100644 service/management/__init__.py create mode 100644 service/management/commands/__init__.py create mode 100644 service/management/commands/create_linked_services.py create mode 100644 templates/admin/service/linked_service.html create mode 100644 templates/admin/service/linked_service_confirm_delete.html create mode 100644 templates/admin/service/linked_service_list.html diff --git a/service/admin.py b/service/admin.py index ede3e3c1..47942e10 100644 --- a/service/admin.py +++ b/service/admin.py @@ -165,20 +165,21 @@ class ServiceAddView(FormView): pass from django.shortcuts import get_object_or_404 -from django.views.generic import UpdateView +from django.views.generic import UpdateView, ListView, DeleteView from django.db.models import F -from django.db.models.query import EmptyQuerySet +from django.core.urlresolvers import reverse from .forms import LinkedServiceForm from .models import LinkedService from exposition.models import Exposition from conference.models import Conference -class ServiceUpdateView(UpdateView): + +class LinkedServiceUpdateView(UpdateView): form_class = LinkedServiceForm model = LinkedService template_name = "admin/service/linked_service.html" - success_url = "/admin/service/all/" + success_url = "/admin/service/test/all/" def get_object(self, queryset=None): url = self.kwargs['url'] @@ -187,8 +188,35 @@ class ServiceUpdateView(UpdateView): return obj def get_initial(self): + types = {0:[], 1:['expo'], 2:['conference'], 3:['expo', 'conference']} initial = { - 'expositions':','.join(["%s:%s"%(item.id, item.name) for item in object.expositions.all()]), - 'conferences':','.join(["%s:%s"%(item.id, item.name) for item in self.object.conferences.all()]) + 'expositions': ",".join("%s:%s"%(item.id, item.name) for item in self.object.expositions.all()), + 'conferences': ",".join("%s:%s"%(item.id, item.name) for item in self.object.conferences.all()), + 'type': types[self.object.service.type.mask] } + return initial + + def get_success_url(self): + return self.success_url + def form_valid(self, form): + self.object = form.save() + self.object.update_all_flags() + return HttpResponseRedirect(self.get_success_url()) + +class LinkedServiceList(ListView): + model = LinkedService + template_name = 'admin/service/linked_service_list.html' + + +class LinkedServiceDeleteView(DeleteView): + model = LinkedService + template_name = 'admin/service/linked_service_confirm_delete.html' + success_url = '/admin/service/test/all' + slug_url_kwarg = 'url' + + def get_object(self, queryset=None): + url = self.kwargs['url'] + service = get_object_or_404(Service, url=url) + obj = LinkedService.objects.get(service=service) + return obj diff --git a/service/admin_urls.py b/service/admin_urls.py index c445dac2..f1816405 100644 --- a/service/admin_urls.py +++ b/service/admin_urls.py @@ -2,7 +2,7 @@ from django.conf.urls import patterns, include, url from views import CallBackListView, VisitListView, TranslationListView, AdvertisingListView, \ ParticipationListView, RemoteListView,TicketsListView -from service.admin import ServiceControlList, ServiceControl, ServiceAddView, ServiceUpdateView +from service.admin import ServiceControlList, ServiceControl, LinkedServiceList, LinkedServiceUpdateView, LinkedServiceDeleteView urlpatterns = patterns('service.admin', url(r'^control/list/$', ServiceControlList.as_view()), @@ -18,8 +18,10 @@ urlpatterns = patterns('service.admin', url(r'order/participation/$', ParticipationListView.as_view()), url(r'order/remote/$', RemoteListView.as_view()), url(r'order/tickets/$', TicketsListView.as_view()), - url('^test/(?P[a-z]*)/', ServiceUpdateView.as_view()), - url('^test/$', ServiceAddView.as_view()), + url('^test/delete/(?P[a-z]*)/', LinkedServiceDeleteView.as_view(), name='linked_service_delete'), + url('^test/all/', LinkedServiceList.as_view(), name = 'linked_service_all'), + url('^test/(?P[a-z]*)/', LinkedServiceUpdateView.as_view(), name= 'linked_service_update'), + #ajax url(r'^get_city/$', 'get_city'), diff --git a/service/forms.py b/service/forms.py index b62fac7f..b2f88280 100644 --- a/service/forms.py +++ b/service/forms.py @@ -162,25 +162,36 @@ from django.db.models.query import EmptyQuerySet class LinkedServiceForm(forms.ModelForm): - type = forms.MultipleChoiceField(choices = [(x, x) for x in list(Service.type)], widget = forms.CheckboxSelectMultiple) - + type = forms.MultipleChoiceField(choices = [(x, x) for x in list(Service.type)], widget = forms.CheckboxSelectMultiple, required=False) + expositions = forms.CharField(widget=forms.HiddenInput,required=False) + conferences = forms.CharField(widget=forms.HiddenInput, required=False) + class Meta: model = LinkedService fields = ['countries', 'all_countries', 'expositions', 'conferences'] - widgets={ - 'expositions': forms.HiddenInput, - 'conferences': forms.HiddenInput - } + + def clean_countries(self): + return list(set(self.cleaned_data['countries'])) def clean_expositions(self): expositions = EmptyQuerySet() if self.cleaned_data['expositions']: - expositions = Exposition.objects.language().filter(id__in=list(set(self.cleaned_data['expositions']))) + expositions = Exposition.objects.language().filter(id__in=list(set(self.cleaned_data['expositions'].split(',')))) return expositions def clean_conferences(self): conferences = EmptyQuerySet() if self.cleaned_data['conferences']: - conferences = Conference.objects.language().filter(id__in=list(set(self.cleaned_data['conferences']))) + conferences = Conference.objects.language().filter(id__in=list(set(self.cleaned_data['conferences'].split(',')))) return conferences + def save(self, commit=True): + obj = super(LinkedServiceForm, self).save(commit=True) + data = self.cleaned_data + # manage service type bit field + types = data['type'] + obj.service.type = 0 + for type in types: + obj.service.type = obj.service.type | getattr(Service.type, type) + obj.service.save() + return obj diff --git a/service/management/__init__.py b/service/management/__init__.py new file mode 100644 index 00000000..7ff70582 --- /dev/null +++ b/service/management/__init__.py @@ -0,0 +1 @@ +__author__ = 'dev' diff --git a/service/management/commands/__init__.py b/service/management/commands/__init__.py new file mode 100644 index 00000000..7ff70582 --- /dev/null +++ b/service/management/commands/__init__.py @@ -0,0 +1 @@ +__author__ = 'dev' diff --git a/service/management/commands/create_linked_services.py b/service/management/commands/create_linked_services.py new file mode 100644 index 00000000..b1f27201 --- /dev/null +++ b/service/management/commands/create_linked_services.py @@ -0,0 +1,25 @@ +from django.core.management.base import BaseCommand +from django.utils.translation import activate +from service.models import Service,LinkedService +from country.models import Country +from exposition.models import Exposition +from conference.models import Conference + + +class Command(BaseCommand): + def handle(self, *args, **options): + activate('ru') + LinkedService.objects.all().delete() + services = Service.objects.all() + for service in services: + linked = LinkedService() + linked.service = service + linked.save() + if Country.objects.language().filter(services=getattr(Country.services, service.url)).count() == Country.objects.language().count(): + linked.all_countries = True + else: + linked.countries = Country.objects.language().filter(services=getattr(Country.services, service.url)) + linked.expositions = Exposition.objects.language().filter(services=getattr(Exposition.services, service.url)) + linked.conferences = Conference.objects.language().filter(services=getattr(Conference.services, service.url)) + linked.save() + diff --git a/service/models.py b/service/models.py index c8d7946e..ec774a5e 100644 --- a/service/models.py +++ b/service/models.py @@ -204,6 +204,7 @@ class CallBack(models.Model): from country.models import Country from exposition.models import Exposition from conference.models import Conference +from django.db.models import F class LinkedService(models.Model): @@ -212,3 +213,26 @@ class LinkedService(models.Model): all_countries = models.BooleanField(default=False) expositions = models.ManyToManyField(Exposition, blank=True) conferences = models.ManyToManyField(Conference, blank=True) + + def update_countries_flag(self): + if self.all_countries: + Country.objects.language().update(services=F('services').bitor(getattr(Country.services, self.service.url))) + else: + self.countries.update(services=F('services').bitor(getattr(Country.services, self.service.url))) + Country.objects.exclude(id__in=[c.id for c in self.countries.all()]).update(services=F('services').bitand(~getattr(Country.services, self.service.url))) + + def update_expositions_flag(self): + self.expositions.update(services=F('services').bitor(getattr(Exposition.services, self.service.url))) + Exposition.objects.exclude(id__in=[c.id for c in self.expositions.all()]).update(services=F('services').bitand(~getattr(Exposition.services, self.service.url))) + + def update_conferences_flag(self): + self.conferences.update(services=F('services').bitor(getattr(Conference.services, self.service.url))) + Conference.objects.exclude(id__in=[c.id for c in self.conferences.all()]).update(services=F('services').bitand(~getattr(Conference.services, self.service.url))) + + def update_all_flags(self): + self.update_countries_flag() + self.update_expositions_flag() + self.update_conferences_flag() + + def __unicode__(self): + return u'Linked service for %s'%self.service.url diff --git a/templates/admin/service/linked_service.html b/templates/admin/service/linked_service.html new file mode 100644 index 00000000..9d65bc9c --- /dev/null +++ b/templates/admin/service/linked_service.html @@ -0,0 +1,162 @@ +{% extends 'base.html' %} +{% load static %} + + {% block scripts %} + + {# selects #} + + + + + + + {% endblock %} + +{% block body %} + +{# Uses multilang.html template for translated fields #} +
{% csrf_token %} +{{ form.errors }} +
+ +
+ {{ form.type }}{{ form.type.errors }} +
+
+
+ +
+ {{ form.countries }}{{ form.countries.errors }} +
+
+
+ +
+ {{ form.all_countries }} +
+
+ +
+ +
+ {{ form.expositions }}{{ form.expositions.errors }} +
+
+
+ +
+ {{ form.conferences }}{{ form.conferences.errors }} +
+
+
+
+ + +
+
+
+ + +{% endblock %} \ No newline at end of file diff --git a/templates/admin/service/linked_service_confirm_delete.html b/templates/admin/service/linked_service_confirm_delete.html new file mode 100644 index 00000000..21cc73d0 --- /dev/null +++ b/templates/admin/service/linked_service_confirm_delete.html @@ -0,0 +1,11 @@ +{% extends 'base.html' %} +{% block sidebar %}{% endblock %} +{% block body %} +
{% csrf_token %} +
+

Вы точно хотите удалить настройку для сервиса "{{ object.service.name }}" ?

+ + Нет +
+
+{% endblock %} \ No newline at end of file diff --git a/templates/admin/service/linked_service_list.html b/templates/admin/service/linked_service_list.html new file mode 100644 index 00000000..eb4af0cb --- /dev/null +++ b/templates/admin/service/linked_service_list.html @@ -0,0 +1,48 @@ +{% extends 'base.html' %} + +{% block body %} + +
+
+

Настройки услуг

+
+
+ + + + + + + + + + + + + + {{ object }} + {% for item in object_list %} + + + + + + + + + + {% endfor %} + +
idНазвание услугиТипСтранВиставокКонференций 
{{ item.id }}{{ item.service.name }}{% if item.service.type.mask == 1 %} expo {% elif item.service.type.mask == 2%} conf {% elif item.service.type.mask == 3 %} expo, conf{% endif %}{{ item.countries.count }}{{ item.expositions.count }}{{ item.conferences.count }} + + Изменить + + + Удалить + +
+
+ +
+ +{% endblock %} From e5fd4682f3792336e5c2822a6c800d9d55b51f15 Mon Sep 17 00:00:00 2001 From: Ivan Kovalkovskyi Date: Mon, 5 Oct 2015 16:57:10 +0300 Subject: [PATCH 04/16] Linked service improvements --- service/admin.py | 24 +- service/forms.py | 19 +- .../commands/create_linked_services.py | 7 +- service/models.py | 24 +- templates/admin/service/linked_service.html | 303 ++++++++---------- templates/admin/service/test_add.html | 155 --------- 6 files changed, 167 insertions(+), 365 deletions(-) delete mode 100644 templates/admin/service/test_add.html diff --git a/service/admin.py b/service/admin.py index 47942e10..d91251fb 100644 --- a/service/admin.py +++ b/service/admin.py @@ -143,35 +143,13 @@ class ServiceControl(FormMixin, DetailView): context['form'] = self.get_form(self.form_class) return context -from .forms import _ServiceForm -class ServiceAddView(FormView): - form_class = _ServiceForm - template_name = 'admin/service/test_add.html' - success_url = '/' - - def get(self, request, *args, **kwargs): - data = request.GET - form = self.form_class(data) - - if form.is_valid(): - countries = form.cleaned_data['countries'] - types = form.cleaned_data['type'] - expos = form.cleaned_data['expos'] - confs = form.cleaned_data['confs'] - is_all_cnt = form.cleaned_data['all_counties'] - raise - else: - pass from django.shortcuts import get_object_or_404 from django.views.generic import UpdateView, ListView, DeleteView -from django.db.models import F -from django.core.urlresolvers import reverse from .forms import LinkedServiceForm from .models import LinkedService -from exposition.models import Exposition -from conference.models import Conference + diff --git a/service/forms.py b/service/forms.py index b2f88280..fa84b396 100644 --- a/service/forms.py +++ b/service/forms.py @@ -149,14 +149,6 @@ class ServiceControlForm(forms.Form): for item in self.event]) -class _ServiceForm(forms.Form): - type = forms.MultipleChoiceField(choices=[(x, x) for x in Service.type], widget=forms.CheckboxSelectMultiple) - countries = forms.MultipleChoiceField(choices=[(x.id,x.name) for x in Country.objects.language().all()]) - all_counties = forms.BooleanField(widget=forms.CheckboxInput) - expos = forms.CharField(widget=forms.HiddenInput) - confs = forms.CharField(widget=forms.HiddenInput) - - from .models import LinkedService from django.db.models.query import EmptyQuerySet @@ -168,20 +160,23 @@ class LinkedServiceForm(forms.ModelForm): class Meta: model = LinkedService - fields = ['countries', 'all_countries', 'expositions', 'conferences'] + fields = ['countries', 'exclude_countries', 'expositions', 'conferences'] + help_text = { + 'exclude_countries': u'При отсутствии стран этот флаг значит ВСЕ страны!' + } def clean_countries(self): - return list(set(self.cleaned_data['countries'])) + return list(set(self.cleaned_data.get('countries'))) def clean_expositions(self): expositions = EmptyQuerySet() - if self.cleaned_data['expositions']: + if self.cleaned_data.get('expositions'): expositions = Exposition.objects.language().filter(id__in=list(set(self.cleaned_data['expositions'].split(',')))) return expositions def clean_conferences(self): conferences = EmptyQuerySet() - if self.cleaned_data['conferences']: + if self.cleaned_data.get('conferences'): conferences = Conference.objects.language().filter(id__in=list(set(self.cleaned_data['conferences'].split(',')))) return conferences diff --git a/service/management/commands/create_linked_services.py b/service/management/commands/create_linked_services.py index b1f27201..681d9f46 100644 --- a/service/management/commands/create_linked_services.py +++ b/service/management/commands/create_linked_services.py @@ -15,11 +15,10 @@ class Command(BaseCommand): linked = LinkedService() linked.service = service linked.save() - if Country.objects.language().filter(services=getattr(Country.services, service.url)).count() == Country.objects.language().count(): - linked.all_countries = True + if Country.objects.language().filter(services=getattr(Country.services, service.url)).count() > 180: + linked.exclude_countries = True + linked.countries = Country.objects.language().exclude(services=getattr(Country.services, service.url)) else: linked.countries = Country.objects.language().filter(services=getattr(Country.services, service.url)) - linked.expositions = Exposition.objects.language().filter(services=getattr(Exposition.services, service.url)) - linked.conferences = Conference.objects.language().filter(services=getattr(Conference.services, service.url)) linked.save() diff --git a/service/models.py b/service/models.py index ec774a5e..4549f10e 100644 --- a/service/models.py +++ b/service/models.py @@ -209,25 +209,29 @@ from django.db.models import F class LinkedService(models.Model): service = models.ForeignKey(Service, blank=False) - countries = models.ManyToManyField(Country, blank=True) - all_countries = models.BooleanField(default=False) - expositions = models.ManyToManyField(Exposition, blank=True) - conferences = models.ManyToManyField(Conference, blank=True) + countries = models.ManyToManyField(Country, blank=True, verbose_name=u"Страны") + exclude_countries = models.BooleanField(default=False, verbose_name=u"Исключить страны") + expositions = models.ManyToManyField(Exposition, blank=True, verbose_name= u"Выставки") + conferences = models.ManyToManyField(Conference, blank=True, verbose_name=u'Конференции') def update_countries_flag(self): - if self.all_countries: - Country.objects.language().update(services=F('services').bitor(getattr(Country.services, self.service.url))) + if self.exclude_countries: + 'filter all countries except selected and set flag to true' + Country.objects.language().exclude(id__in=[c.id for c in self.countries.all()]).update(services=F('services').bitor(getattr(Country.services, self.service.url))) + 'set another flags to false' + Country.objects.language().filter(id__in=[c.id for c in self.countries.all()]).update(services=F('services').bitand(~getattr(Country.services, self.service.url))) else: + 'if not exclude, filter all selected countries and set flag to true' self.countries.update(services=F('services').bitor(getattr(Country.services, self.service.url))) Country.objects.exclude(id__in=[c.id for c in self.countries.all()]).update(services=F('services').bitand(~getattr(Country.services, self.service.url))) def update_expositions_flag(self): - self.expositions.update(services=F('services').bitor(getattr(Exposition.services, self.service.url))) - Exposition.objects.exclude(id__in=[c.id for c in self.expositions.all()]).update(services=F('services').bitand(~getattr(Exposition.services, self.service.url))) + self.expositions.update(services=F('services').bitor(getattr(Exposition.services, self.service.url))) + Exposition.objects.exclude(id__in=[c.id for c in self.expositions.all()]).update(services=F('services').bitand(~getattr(Exposition.services, self.service.url))) def update_conferences_flag(self): - self.conferences.update(services=F('services').bitor(getattr(Conference.services, self.service.url))) - Conference.objects.exclude(id__in=[c.id for c in self.conferences.all()]).update(services=F('services').bitand(~getattr(Conference.services, self.service.url))) + self.conferences.update(services=F('services').bitor(getattr(Conference.services, self.service.url))) + Conference.objects.exclude(id__in=[c.id for c in self.conferences.all()]).update(services=F('services').bitand(~getattr(Conference.services, self.service.url))) def update_all_flags(self): self.update_countries_flag() diff --git a/templates/admin/service/linked_service.html b/templates/admin/service/linked_service.html index 9d65bc9c..3ecb4f54 100644 --- a/templates/admin/service/linked_service.html +++ b/templates/admin/service/linked_service.html @@ -1,162 +1,143 @@ -{% extends 'base.html' %} -{% load static %} - - {% block scripts %} - - {# selects #} - - - - - - - {% endblock %} - -{% block body %} - -{# Uses multilang.html template for translated fields #} -
{% csrf_token %} -{{ form.errors }} -
- -
- {{ form.type }}{{ form.type.errors }} -
-
-
- -
- {{ form.countries }}{{ form.countries.errors }} -
-
-
- -
- {{ form.all_countries }} -
-
- -
- -
- {{ form.expositions }}{{ form.expositions.errors }} -
-
-
- -
- {{ form.conferences }}{{ form.conferences.errors }} -
-
-
-
- - -
-
-
- - +{% extends 'base.html' %} +{% load static %} + +{% block scripts %} + + {# selects #} + + + + + + +{% endblock %} + +{% block body %} + + {# Uses multilang.html template for translated fields #} +
{% csrf_token %} +
+
+

Основная информация

+
+ + {% for f in form %} +
+ +
{{ f }} + {{ f.errors }} +
+
+ {% endfor %} +
+ + +
+
+
+ + + {% endblock %} \ No newline at end of file diff --git a/templates/admin/service/test_add.html b/templates/admin/service/test_add.html deleted file mode 100644 index 559f655a..00000000 --- a/templates/admin/service/test_add.html +++ /dev/null @@ -1,155 +0,0 @@ -{% extends 'base.html' %} -{% load static %} - - {% block scripts %} - - {# selects #} - - - - - - - {% endblock %} - -{% block body %} - -{# Uses multilang.html template for translated fields #} -
-{{ form.errors }} -
- -
- {{ form.type }} -
-
-
- -
- {{ form.countries }} -
-
-
- -
- {{ form.all_counties }} -
-
- -
- -
- {{ form.expos }} -
-
-
- -
- {{ form.confs }} -
-
-
-
- - -
-
-
- - -{% endblock %} \ No newline at end of file From 8a96c5d8cfc5f2639f179da4302524efc7cb20a6 Mon Sep 17 00:00:00 2001 From: Ivan Kovalkovskyi Date: Tue, 6 Oct 2015 16:39:46 +0300 Subject: [PATCH 05/16] minor bug in conference default description fixed --- templates/client/includes/conference/default_description.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/templates/client/includes/conference/default_description.html b/templates/client/includes/conference/default_description.html index cd2633b1..2b4dade5 100644 --- a/templates/client/includes/conference/default_description.html +++ b/templates/client/includes/conference/default_description.html @@ -2,7 +2,7 @@
{% blocktrans with name=conf.name%}

Конференция {{name}} проходит {% endblocktrans %}{% include 'client/includes/show_date_block.html' with obj=conf %} -{% blocktrans with city=conf.name country=country.name name=conf.name id=conf.city.id code=request.LANGUAGE_CODE date1=conf.data_begin|date:'j' date2=conf.data_begin|date:'Y' date3=conf.data_begin|date:'n' date4=conf.data_end|date:'j' date5=conf.data_end|date:'Y' date6=conf.data_end|date:'n' %} +{% blocktrans with city=city.name country=country.name name=conf.name id=conf.city.id code=request.LANGUAGE_CODE date1=conf.data_begin|date:'j' date2=conf.data_begin|date:'Y' date3=conf.data_begin|date:'n' date4=conf.data_end|date:'j' date5=conf.data_end|date:'Y' date6=conf.data_end|date:'n' %} в городе {{city}}, {{country}}. Посмотреть, как проехать в место проведения конференции, можно на сайте конгрессной площадки. Деловая программа {{name}} разбита на секции по дням и размещается на сайте мероприятия с подробным списком From a2c4b55f5befdf94fe7a8ad3aee2b016e62e5309 Mon Sep 17 00:00:00 2001 From: Ivan Kovalkovskyi Date: Wed, 7 Oct 2015 15:17:08 +0300 Subject: [PATCH 06/16] separate theme for blog(Article model) --- article/admin.py | 8 ++- article/forms.py | 12 ++-- article/models.py | 3 +- article/views.py | 8 +-- templates/admin/includes/admin_nav.html | 1 + .../theme/theme_blog_confirm_delete.html | 11 ++++ templates/admin/theme/theme_blog_list.html | 65 +++++++++++++++++++ templates/admin/theme/theme_blog_new.html | 49 ++++++++++++++ templates/client/article/article.html | 4 +- theme/admin.py | 43 ++++++++++-- theme/admin_urls.py | 6 ++ theme/forms.py | 17 ++++- theme/models.py | 24 +++++++ theme/views.py | 3 - 14 files changed, 227 insertions(+), 27 deletions(-) create mode 100644 templates/admin/theme/theme_blog_confirm_delete.html create mode 100644 templates/admin/theme/theme_blog_list.html create mode 100644 templates/admin/theme/theme_blog_new.html diff --git a/article/admin.py b/article/admin.py index ff178cee..377f3b13 100644 --- a/article/admin.py +++ b/article/admin.py @@ -125,12 +125,14 @@ def article_change(request, url): return render_to_response('article_add.html', args) #----------------------- -from django.views.generic import ListView, FormView +from django.views.generic import FormView +from functions.custom_views import ListView from forms import BlogForm class BlogList(ListView): model = Article - template_name = 'article/article_admin_list.html' + template_name = 'admin/article/article_admin_list.html' + paginate_by = settings.ADMIN_PAGINATION def get_queryset(self): return self.model.objects.blogs() @@ -168,7 +170,7 @@ class BlogView(FormView): if self.obj: article = self.obj data = {} - data['theme'] = [item.id for item in article.theme.all()] + data['theme'] = [item.id for item in article.blog_theme.all()] if article.exposition: data['exposition'] = article.exposition.id if article.conference: diff --git a/article/forms.py b/article/forms.py index 8810abe7..d7c2fcd8 100644 --- a/article/forms.py +++ b/article/forms.py @@ -12,14 +12,14 @@ from functions.form_check import translit_with_separator #models from models import Article from accounts.models import User -from theme.models import Theme, Tag +from theme.models import Theme, Tag, ThemeBlog from exposition.models import Exposition from conference.models import Conference class BlogForm(forms.Form): type = Article.blog - theme = forms.ModelMultipleChoiceField(label='Тематики', queryset=Theme.objects.exclude(article__id=None), required=False, + theme = forms.ModelMultipleChoiceField(label='Тематики', queryset=ThemeBlog.objects.all(), required=False, widget=forms.SelectMultiple(attrs={'style':'width: 550px'})) publish_date = forms.DateField(label=u'Дата публикации', input_formats=['%Y-%m-%d', '%d.%m.%Y'], required=False) tag = forms.CharField(label=u'Теги', widget=forms.HiddenInput(), required=False) @@ -61,9 +61,9 @@ class BlogForm(forms.Form): # fill translated fields and save object fill_with_signal(Article, article, data) # fill manytomany fields - article.theme.clear() + article.blog_theme.clear() article.tag.clear() - article.theme.add(*Theme.objects.filter(id__in=data['theme'])) + article.blog_theme.add(*ThemeBlog.objects.filter(id__in=data['theme'])) article.tag.add(*Tag.objects.filter(id__in=data['tag'])) #for item in data['theme']: # article.theme.add(item.id)#.id cause select uses queryset @@ -258,7 +258,7 @@ class BlogForm(forms.ModelForm): class ArticleFilterForm(forms.Form): theme = forms.MultipleChoiceField(label=_(u'Тематика:'), required=False, - choices=[(item.id, item.name) for item in Theme.objects.language().filter(article__type=1).exclude(article__id=None).distinct()]) + choices=[(item.id, item.name) for item in ThemeBlog.objects.language().distinct()]) tag = forms.CharField(label=_(u'Теги:'), widget=forms.HiddenInput(), required=False) ''' @@ -284,7 +284,7 @@ class BlogFilterForm(forms.Form): super(BlogFilterForm, self).__init__(*args, **kwargs) ids = [item['theme'] for item in list(Article.objects.blogs().values('theme').distinct())] self.fields['theme'] = forms.MultipleChoiceField(label=_(u'Тематика:'), required=False, - choices=[(item.id, item.name) for item in Theme.objects.language().filter(id__in=ids)]) + choices=[(item.id, item.name) for item in ThemeBlog.objects.language().filter(id__in=ids)]) class NewsFilterForm(forms.Form): diff --git a/article/models.py b/article/models.py index aa252baf..4a3e77f2 100644 --- a/article/models.py +++ b/article/models.py @@ -14,7 +14,6 @@ from functions.form_check import translit_with_separator from django.core.cache import cache - class ArticleManager(TranslationManager): cache_time = 60 def safe_get(self, **kwargs): @@ -60,7 +59,6 @@ class ArticleManager(TranslationManager): cache.set(key, blogs, self.cache_time) return blogs - return list(self.blogs().filter(publish_date__isnull=False).order_by('-main_page', '-publish_date')[:3]) class Article(TranslatableModel): """ @@ -81,6 +79,7 @@ class Article(TranslatableModel): old_id = models.IntegerField(blank=True, null=True) logo = ImageField(upload_to='articles_preview', blank=True) theme = models.ManyToManyField('theme.Theme') + blog_theme = models.ManyToManyField('theme.ThemeBlog') tag = models.ManyToManyField('theme.Tag', blank=True, null=True) author = models.ForeignKey('accounts.User', verbose_name='Автор', on_delete=models.PROTECT, related_name='articles') diff --git a/article/views.py b/article/views.py index 7b5c68ec..06932d0b 100644 --- a/article/views.py +++ b/article/views.py @@ -5,7 +5,7 @@ from functions.custom_views import ListView from django.http import HttpResponse from models import Article from forms import ArticleFilterForm -from theme.models import Tag, Theme +from theme.models import Tag, Theme, ThemeBlog from meta.views import MetadataMixin @@ -71,7 +71,7 @@ class BlogList(MetadataMixin, ListView): themes = self.request.GET.getlist('theme') if themes: - qs = qs.filter(theme__id__in=themes) + qs = qs.filter(blog_theme__id__in=themes) tags = self.request.GET.getlist('tag') if u'' in tags: @@ -180,10 +180,10 @@ class BlogsFilterCatalog(MetadataMixin, ListView): self.filter_object = tag qs = Article.objects.blogs().filter(tag=tag) else: - theme = get_object_or_404(Theme, url=slug) + theme = get_object_or_404(ThemeBlog, url=slug) self.kwargs['theme'] = theme self.filter_object = theme - qs = Article.objects.blogs().filter(theme = theme) + qs = Article.objects.blogs().filter(blog_theme = theme) year = self.kwargs.get('year') if year: diff --git a/templates/admin/includes/admin_nav.html b/templates/admin/includes/admin_nav.html index 25226d51..f70cb26a 100644 --- a/templates/admin/includes/admin_nav.html +++ b/templates/admin/includes/admin_nav.html @@ -40,6 +40,7 @@

  • Страна
  • Город
  • Тематики
  • +
  • Тематики для блогов
  • Теги
  • Услуги
  • Главная страница
  • diff --git a/templates/admin/theme/theme_blog_confirm_delete.html b/templates/admin/theme/theme_blog_confirm_delete.html new file mode 100644 index 00000000..ec7b8c9f --- /dev/null +++ b/templates/admin/theme/theme_blog_confirm_delete.html @@ -0,0 +1,11 @@ +{% extends 'base.html' %} +{% block sidebar %}{% endblock %} +{% block body %} +
    {% csrf_token %} +
    +

    Вы точно хотите удалить "{{ object.name }}" ?

    + + Нет +
    +
    +{% endblock %} \ No newline at end of file diff --git a/templates/admin/theme/theme_blog_list.html b/templates/admin/theme/theme_blog_list.html new file mode 100644 index 00000000..ad6a7dcd --- /dev/null +++ b/templates/admin/theme/theme_blog_list.html @@ -0,0 +1,65 @@ +{% extends 'admin_list.html' %} + +{% block body %} + +{#
    #} +{#
    #} +{#

    Фильтры

    #} +{#
    #} +{#
    #} +{#
    #} +{# {{ form }}#} +{##} +{# #} +{#
    #} +{#
    #} +{##} +{#
    #} + +
    +
    +

    Список тем

    +
    +
    + + + + + + + + + + + + + + + + + {% for item in object_list %} + + + + + + + + + {% endfor %} + +
    idНазвание  
    {{ item.id }}{{ item.name }} + + Изменить + + + + Удалить + +
    + Добавить тематику +
    + {# pagination #} + {% include 'admin/includes/admin_pagination.html' with page_obj=object_list %} +
    +{% endblock %} \ No newline at end of file diff --git a/templates/admin/theme/theme_blog_new.html b/templates/admin/theme/theme_blog_new.html new file mode 100644 index 00000000..9ee2b388 --- /dev/null +++ b/templates/admin/theme/theme_blog_new.html @@ -0,0 +1,49 @@ +{% extends 'base.html' %} +{% load static %} + +{% block scripts %} + + + {# selects #} + + + + + + +{% endblock %} + +{% block body %} + +
    {% csrf_token %}{{ form.errors }} +
    + {% if theme_id %} Изменить {% else %} Добавить {% endif %}тему +
    +
    +

    Информация

    +
    +
    + {% for field in form %} + + + + {% endfor %} +
    +
    + + +
    + + +
    + +
    +
    + +{% endblock %} \ No newline at end of file diff --git a/templates/client/article/article.html b/templates/client/article/article.html index e36596ee..505714e5 100644 --- a/templates/client/article/article.html +++ b/templates/client/article/article.html @@ -19,7 +19,7 @@ {% include 'client/includes/article/article_logo.html' with obj=object %}

    {{ object.main_title }}

    - {{ object.publish_date|date:"d E Y" }}{% if object.theme.all.exists %}{% include 'includes/article_theme.html' with obj=object %}{% endif %} + {{ object.publish_date|date:"d E Y" }}{% if object.blog_theme.all.exists %}{% include 'client/includes/article_theme.html' with obj=object %}{% endif %} {% if request.user.is_admin %} {% trans 'изменить' %} {% endif %} @@ -53,7 +53,7 @@ {% include 'includes/show_logo.html' with obj=blog %}

    {{ blog.main_title }}

    {{ blog.preview }}

    - {{ blog.created|date:"d E Y" }}Евгения Булавина + {{ blog.publish_date|date:"d E Y" }}Евгения Булавина
    {% endfor %} diff --git a/theme/admin.py b/theme/admin.py index da323984..8914587f 100644 --- a/theme/admin.py +++ b/theme/admin.py @@ -3,15 +3,13 @@ from django.shortcuts import render_to_response from django.http import HttpResponseRedirect, HttpResponse from django.core.context_processors import csrf from django.conf import settings -from django.forms.formsets import BaseFormSet, formset_factory -from django.forms.models import modelformset_factory -from django.contrib.contenttypes.models import ContentType +from django.views.generic import CreateView, UpdateView, DeleteView from django.contrib.auth.decorators import login_required #forms and models from forms import ThemeForm, TagForm, ThemeDeleteForm, TagDeleteForm, TagFilterForm, ThemeFilterForm -from models import Theme, Tag +from models import Theme, Tag, ThemeBlog #custom views -from functions.custom_views import objects_list, add_object, delete_object +from functions.custom_views import objects_list, add_object, delete_object, ListView from functions.views_help import get_referer from functions.admin_views import AdminListView @@ -170,4 +168,37 @@ class ThemeListView(AdminListView): class TagListView(AdminListView): template_name = 'admin/theme/tag_list.html' form_class = TagFilterForm - model = Tag \ No newline at end of file + model = Tag + + +from functions.custom_views import ListView +from django.core.urlresolvers import reverse_lazy +from .forms import ThemeBlogForm + + +class ThemeBlogListView(ListView): + template_name = 'admin/theme/theme_blog_list.html' + model = ThemeBlog + paginate_by = settings.ADMIN_PAGINATION + + +class ThemeBlogCreateView(CreateView): + template_name = "admin/theme/theme_blog_new.html" + model = ThemeBlog + form_class = ThemeBlogForm + success_url = reverse_lazy("theme_blog_all") + + +class ThemeBlogUpdateView(UpdateView): + template_name = "admin/theme/theme_blog_new.html" + model = ThemeBlog + form_class = ThemeBlogForm + success_url = reverse_lazy("theme_blog_all") + pk_url_kwarg = "theme_id" + + +class ThemeBlogDeleteView(DeleteView): + template_name = "admin/theme/theme_blog_confirm_delete.html" + model = ThemeBlog + success_url = reverse_lazy("theme_blog_all") + pk_url_kwarg = "theme_id" diff --git a/theme/admin_urls.py b/theme/admin_urls.py index c1803d4f..0caf5c87 100644 --- a/theme/admin_urls.py +++ b/theme/admin_urls.py @@ -1,19 +1,25 @@ # -*- coding: utf-8 -*- from django.conf.urls import patterns, include, url from admin import TagListView, ThemeListView +from .admin import ThemeBlogCreateView, ThemeBlogUpdateView, ThemeBlogDeleteView, ThemeBlogListView + urlpatterns = patterns('theme.admin', url(r'^theme/add.*/$', 'theme_add'), url(r'^tag/add.*/$', 'tag_add'), + url(r'^blog_theme/add/$', ThemeBlogCreateView.as_view(), name = 'theme_blog_new'), url(r'^theme/delete/(?P\d+)/$', 'theme_delete'), url(r'^tag/delete/(?P\d+)/$', 'tag_delete'), + url(r'^blog_theme/delete/(?P\d+)/$', ThemeBlogDeleteView.as_view(), name = 'theme_blog_delete'), url(r'^theme/change/(?P\d+).*/$', 'theme_change'), + url(r'^blog_theme/change/(?P\d+).*/$', ThemeBlogUpdateView.as_view(), name= "theme_blog_change"), url(r'^tag/change/(?P\d+).*/$', 'tag_change'), url(r'^theme/copy/(?P\d+).*/$', 'theme_copy'), url(r'^tag/copy/(?P\d+).*/$', 'tag_copy'), #url(r'^theme/all/$', 'theme_all'), #url(r'^tag/all/$', 'tag_all'), url(r'^theme/all/$', ThemeListView.as_view()), + url(r'^blog_theme/all/$', ThemeBlogListView.as_view(), name="theme_blog_all"), url(r'^tag/all/$', TagListView.as_view()), url(r'^tag/search/$', 'search_tag'), url(r'^tag/search-without-theme/$', 'search2'), diff --git a/theme/forms.py b/theme/forms.py index 7cd0512f..5f166b04 100644 --- a/theme/forms.py +++ b/theme/forms.py @@ -143,4 +143,19 @@ class ThemeFilterForm(AdminFilterForm): class TagFilterForm(AdminFilterForm): - model = Tag \ No newline at end of file + model = Tag + +from hvad.forms import TranslatableModelForm +from .models import ThemeBlog + + +class ThemeBlogForm(TranslatableModelForm): + class Meta: + model = ThemeBlog + fields = ['url', 'name', 'main_title', 'description', 'inflect'] + widgets = {'url':forms.TextInput(attrs={'required':False})} + + def save(self, commit= True): + if not 'url' in self.cleaned_data: + self.cleaned_data['url'] = translit_with_separator(self.cleaned_data['name']) + return super(ThemeBlogForm, self).save(commit=True) \ No newline at end of file diff --git a/theme/models.py b/theme/models.py index 50ece870..93908fd7 100644 --- a/theme/models.py +++ b/theme/models.py @@ -133,6 +133,30 @@ class Theme(TranslatableModel): parent = {} return parent + +class ThemeBlog(TranslatableModel): + + url = models.SlugField(unique=True, max_length=255) + + translations = TranslatedFields( + name=models.CharField(max_length=255), + main_title=models.CharField(max_length=255, blank=True), + description=models.TextField(blank=True) + ) + + inflect = models.CharField(max_length=255, blank=True) + + def __unicode__(self): + return self.lazy_translation_getter('name', unicode(self.pk)) + + def get_all_names(self): + return [item['name'] for item in self.translations.all().values('name')] + + def get_index_text(self): + translation.activate('ru') + return ' '.join(self.get_all_names()) + + from django.db import IntegrityError class Tag(TranslatableModel): """ diff --git a/theme/views.py b/theme/views.py index 1deadf9b..ce83a38a 100644 --- a/theme/views.py +++ b/theme/views.py @@ -21,11 +21,8 @@ def get_tag(request): def get_article_tags(request): - themes = request.GET.getlist('themes[]') term = request.GET['term'].capitalize() qs = Tag.objects.language().exclude(article=None).filter(article__type=1).distinct() - if themes: - qs = qs.filter(theme__id__in=themes).order_by('translations__name') if term: qs = qs.filter(translations__name__contains=term) result = [{'id': tag.id, 'label': '%s (%s)'%(tag.name, tag.theme.name)} for tag in qs] From e70f80d80ae1c9dbccd788dec08246a7a4bf8f32 Mon Sep 17 00:00:00 2001 From: Ivan Kovalkovskyi Date: Wed, 7 Oct 2015 16:08:57 +0300 Subject: [PATCH 07/16] conference alternative text admin support --- conference/admin.py | 4 ++-- conference/forms.py | 2 ++ templates/admin/conference/conference.html | 7 +++++++ templates/admin/conference/conference_add.html | 10 +++++++++- templates/admin/theme/theme_blog_new.html | 2 +- 5 files changed, 21 insertions(+), 4 deletions(-) diff --git a/conference/admin.py b/conference/admin.py index af2f95c5..7e22fc61 100644 --- a/conference/admin.py +++ b/conference/admin.py @@ -159,7 +159,7 @@ def conference_change(request, url): #initial StatisticFormSet StatisticFormSet = modelformset_factory(Statistic, form=StatisticForm, exclude=('conference',)) #fill form with data from database - data = {'web_page':conference.web_page, 'foundation_year': conference.foundation_year, + data = {'web_page':conference.web_page, 'place_alt': conference.place_alt, 'foundation_year': conference.foundation_year, 'data_begin':conference.data_begin, 'data_end':conference.data_end, 'currency':conference.currency, 'tax':conference.tax, 'min_price':conference.min_price, 'max_price':conference.max_price, 'link':conference.link, 'conference_id':conference.id, 'expohit': conference.expohit, @@ -233,7 +233,7 @@ class ConferenceView(AdminView): return super(ConferenceView, self).get_form(form_class) obj = self.set_obj() if obj: - data = {'web_page':obj.web_page, 'foundation_year': obj.foundation_year, + data = {'web_page':obj.web_page, 'place_alt':obj.place_alt, 'foundation_year': obj.foundation_year, 'data_begin':obj.data_begin, 'data_end':obj.data_end, 'currency':obj.currency, 'tax':obj.tax, 'min_price':obj.min_price, 'max_price':obj.max_price, 'link':obj.link, 'conference_id':obj.id, 'expohit': obj.expohit, 'periodic':obj.periodic, diff --git a/conference/forms.py b/conference/forms.py index 897f441b..4cba3c0b 100644 --- a/conference/forms.py +++ b/conference/forms.py @@ -56,6 +56,7 @@ class ConferenceCreateForm(forms.Form): place = forms.ChoiceField(label=u'Место проведения', required=False, choices=places) + place_alt = forms.CharField(label = u"Альтернативное название места", required=False) #creates select input with empty choices cause it will be filled with ajax city = forms.CharField(label=u'Город', widget=forms.HiddenInput()) @@ -160,6 +161,7 @@ class ConferenceCreateForm(forms.Form): conference.canceled = data['canceled'] conference.moved = data['moved'] conference.periodic = data['periodic'] + conference.place_alt = data['place_alt'] # generates bitfield flag = 0 if data['quality_label']: diff --git a/templates/admin/conference/conference.html b/templates/admin/conference/conference.html index 51811f7f..8d6a7f6b 100644 --- a/templates/admin/conference/conference.html +++ b/templates/admin/conference/conference.html @@ -134,6 +134,13 @@ {{ form.place.errors }}
    + {# place_alt #} +
    + +
    {{ form.place_alt }} + {{ form.place_alt.errors }} +
    +
    {# theme #}
    diff --git a/templates/admin/conference/conference_add.html b/templates/admin/conference/conference_add.html index efe93065..39fb4a90 100644 --- a/templates/admin/conference/conference_add.html +++ b/templates/admin/conference/conference_add.html @@ -47,7 +47,7 @@
    -

    Основная информация

    +

    Основная информаdция

    {# Hidden inputs uses for comparing with TmpFile objects #} @@ -99,6 +99,14 @@ {{ form.place.errors }}
    + + {# place #} +
    + +
    {{ form.place_alt }} + {{ form.place_alt.errors }} +
    +
    {# theme #}
    diff --git a/templates/admin/theme/theme_blog_new.html b/templates/admin/theme/theme_blog_new.html index 9ee2b388..fe5406b8 100644 --- a/templates/admin/theme/theme_blog_new.html +++ b/templates/admin/theme/theme_blog_new.html @@ -17,7 +17,7 @@
    {% csrf_token %}{{ form.errors }}
    - {% if theme_id %} Изменить {% else %} Добавить {% endif %}тему + {% if object %} Изменить {% else %} Добавить {% endif %}тему

    Информация

    From 9c263235dda6666273322e509b277dd2e245590b Mon Sep 17 00:00:00 2001 From: Ivan Kovalkovskyi Date: Thu, 8 Oct 2015 13:48:37 +0300 Subject: [PATCH 08/16] added possibility to define url for blog and news --- article/admin.py | 3 ++- article/forms.py | 16 ++++++++++++---- article/models.py | 8 ++------ templates/admin/article/blog_form.html | 10 +++++++++- 4 files changed, 25 insertions(+), 12 deletions(-) diff --git a/article/admin.py b/article/admin.py index 377f3b13..29b59839 100644 --- a/article/admin.py +++ b/article/admin.py @@ -142,6 +142,7 @@ class BlogList(ListView): context['blog_flag'] = True return context + class BlogView(FormView): form_class = BlogForm template_name = 'article/blog_form.html' @@ -162,7 +163,6 @@ class BlogView(FormView): form.save(author, article=self.obj) return HttpResponseRedirect(self.success_url) - def get_form(self, form_class): if self.request.POST: return super(BlogView, self).get_form(form_class) @@ -170,6 +170,7 @@ class BlogView(FormView): if self.obj: article = self.obj data = {} + data['slug'] = article.slug data['theme'] = [item.id for item in article.blog_theme.all()] if article.exposition: data['exposition'] = article.exposition.id diff --git a/article/forms.py b/article/forms.py index d7c2fcd8..e287fd45 100644 --- a/article/forms.py +++ b/article/forms.py @@ -21,9 +21,11 @@ class BlogForm(forms.Form): type = Article.blog theme = forms.ModelMultipleChoiceField(label='Тематики', queryset=ThemeBlog.objects.all(), required=False, widget=forms.SelectMultiple(attrs={'style':'width: 550px'})) + slug = forms.SlugField(label=u'URL', max_length=255, min_length=1) publish_date = forms.DateField(label=u'Дата публикации', input_formats=['%Y-%m-%d', '%d.%m.%Y'], required=False) tag = forms.CharField(label=u'Теги', widget=forms.HiddenInput(), required=False) logo = forms.ImageField(label=u'Лого', required=False) + def __init__(self, *args, **kwargs): """ create dynamical translated fields fields @@ -49,21 +51,26 @@ class BlogForm(forms.Form): def save(self, author, article=None): data = self.cleaned_data - #create new Article object or get exists + # create new Article object or get exists if not article: article = Article() article.author = author article.type = self.type + article.slug = data.get('slug') if data['logo']: article.logo = data['logo'] article.publish_date = data['publish_date'] # fill translated fields and save object fill_with_signal(Article, article, data) # fill manytomany fields - article.blog_theme.clear() + if self.type == Article.blog: + article.blog_theme.clear() + article.blog_theme.add(*ThemeBlog.objects.filter(id__in=data['theme'])) + else: + article.theme.clear() + article.theme.add(*Theme.objects.filter(id__in=data['theme'])) article.tag.clear() - article.blog_theme.add(*ThemeBlog.objects.filter(id__in=data['theme'])) article.tag.add(*Tag.objects.filter(id__in=data['tag'])) #for item in data['theme']: # article.theme.add(item.id)#.id cause select uses queryset @@ -92,7 +99,8 @@ class NewsForm(BlogForm): type = Article.news exposition = forms.CharField(label=u'Выставка', widget=forms.HiddenInput(), required=False) conference = forms.CharField(label=u'Конференция', widget=forms.HiddenInput(), required=False) - + theme = forms.ModelMultipleChoiceField(label='Тематики', queryset=Theme.objects.all(), required=False, + widget=forms.SelectMultiple(attrs={'style':'width: 550px'})) #exposition = forms.ModelChoiceField(label = u'Выставка', required=False, queryset=Exposition.objects.all()) #conference = forms.ModelChoiceField(label = u'Конференция', required=False, queryset=Conference.objects.all()) diff --git a/article/models.py b/article/models.py index 4a3e77f2..f2cf06dc 100644 --- a/article/models.py +++ b/article/models.py @@ -147,15 +147,12 @@ class Article(TranslatableModel): return self.conference return None - def save(self, *args, **kwargs): - # If no slug is provided, generates one before saving. if not self.slug: self.slug = self.generate_unique_slug() - - #Set the description field on save. - #if self.gen_description: + # Set the description field on save. + # if self.gen_description: # self.description = strip_tags(self.description_from_content()) super(Article, self).save(*args, **kwargs) @@ -188,7 +185,6 @@ class Article(TranslatableModel): #print self.lazy_translation_getter('main_title', self.pk) return u'%s'%self.lazy_translation_getter('main_title', self.pk) - def _get_next_or_previous_by_publish_date(self, is_next, **kwargs): """ Retrieves next or previous object by publish date. We implement diff --git a/templates/admin/article/blog_form.html b/templates/admin/article/blog_form.html index 16a15c83..057b565d 100644 --- a/templates/admin/article/blog_form.html +++ b/templates/admin/article/blog_form.html @@ -51,7 +51,15 @@ {{ form.publish_date.errors }}
    - + {% if not article %} +
    + +
    + {{ form.slug }} + {{ form.slug.errors }} +
    +
    + {% endif %} {# theme #}
    From db7a8f271597a34258e20d9e37ce3e31b0f697f9 Mon Sep 17 00:00:00 2001 From: Nazar Kotjuk Date: Fri, 9 Oct 2015 11:56:49 +0300 Subject: [PATCH 09/16] Linked services fixing --- exposition/models.py | 7 +++++++ service/admin_urls.py | 10 +++++----- service/models.py | 9 +++++++++ .../admin/service/linked_service_list.html | 12 +++++------- .../exposition/exposition_services.html | 17 +++++++---------- 5 files changed, 33 insertions(+), 22 deletions(-) diff --git a/exposition/models.py b/exposition/models.py index 8a38e1a9..f8a652bb 100644 --- a/exposition/models.py +++ b/exposition/models.py @@ -178,6 +178,13 @@ class Exposition(TranslatableModel, EventMixin, ExpoMixin): return list(qs) + def get_services_detail(self): + excluded = ['visit', 'tickets'] + country_ids = [item for item, bool in self.country.services if bool==True] + ids = [item for item, bool in self.services if bool==True] + qs = Service.objects.language().exclude(url__in=excluded).filter(Q(Q(url__in=country_ids) & Q(type=Service.type.expo)) | Q(url__in=ids)) + return qs + def get_parent(self): return {} def get_absolute_url(self): diff --git a/service/admin_urls.py b/service/admin_urls.py index f1816405..4b025595 100644 --- a/service/admin_urls.py +++ b/service/admin_urls.py @@ -5,8 +5,8 @@ from views import CallBackListView, VisitListView, TranslationListView, Advertis from service.admin import ServiceControlList, ServiceControl, LinkedServiceList, LinkedServiceUpdateView, LinkedServiceDeleteView urlpatterns = patterns('service.admin', - url(r'^control/list/$', ServiceControlList.as_view()), - url(r'^control/(?P.*)/$', ServiceControl.as_view()), + #url(r'^control/list/$', ServiceControlList.as_view()), + #url(r'^control/(?P.*)/$', ServiceControl.as_view()), url(r'^add.*/$', 'service_add'), url(r'^delete/(?P.*)/$', 'service_delete'), url(r'^change/(?P.*)/$', 'service_change'), @@ -18,9 +18,9 @@ urlpatterns = patterns('service.admin', url(r'order/participation/$', ParticipationListView.as_view()), url(r'order/remote/$', RemoteListView.as_view()), url(r'order/tickets/$', TicketsListView.as_view()), - url('^test/delete/(?P[a-z]*)/', LinkedServiceDeleteView.as_view(), name='linked_service_delete'), - url('^test/all/', LinkedServiceList.as_view(), name = 'linked_service_all'), - url('^test/(?P[a-z]*)/', LinkedServiceUpdateView.as_view(), name= 'linked_service_update'), + url(r'^control/delete/(?P[a-z]*)/', LinkedServiceDeleteView.as_view(), name='linked_service_delete'), + url(r'^control/all/', LinkedServiceList.as_view(), name = 'linked_service_all'), + url(r'^control/(?P[a-z]*)/', LinkedServiceUpdateView.as_view(), name= 'linked_service_update'), #ajax url(r'^get_city/$', 'get_city'), diff --git a/service/models.py b/service/models.py index 4549f10e..471bc6fa 100644 --- a/service/models.py +++ b/service/models.py @@ -238,5 +238,14 @@ class LinkedService(models.Model): self.update_expositions_flag() self.update_conferences_flag() + def countries_count(self): + if not self.exclude_countries: + return self.countries.all().count() + else: + from country.models import Country + all = Country.objects.filter().count() + excluded = self.countries.all().count() + return all - excluded + def __unicode__(self): return u'Linked service for %s'%self.service.url diff --git a/templates/admin/service/linked_service_list.html b/templates/admin/service/linked_service_list.html index eb4af0cb..4d656474 100644 --- a/templates/admin/service/linked_service_list.html +++ b/templates/admin/service/linked_service_list.html @@ -2,7 +2,7 @@ {% block body %} -
    +

    Настройки услуг

    @@ -25,17 +25,15 @@ {{ item.id }} {{ item.service.name }} - {% if item.service.type.mask == 1 %} expo {% elif item.service.type.mask == 2%} conf {% elif item.service.type.mask == 3 %} expo, conf{% endif %} - {{ item.countries.count }} + {% if item.service.type.mask == 1 %} выставки {% elif item.service.type.mask == 2%} конференции {% elif item.service.type.mask == 3 %} выставки и конференции{% endif %} + {{ item.countries_count }} {{ item.expositions.count }} {{ item.conferences.count }} - Изменить - - - Удалить + Управление + {% endfor %} diff --git a/templates/client/includes/exposition/exposition_services.html b/templates/client/includes/exposition/exposition_services.html index 5e9b936f..b98f4d71 100644 --- a/templates/client/includes/exposition/exposition_services.html +++ b/templates/client/includes/exposition/exposition_services.html @@ -2,15 +2,12 @@
    \ No newline at end of file From 114868dee3ccb04cf56e9aa96ade9bcaa14148f5 Mon Sep 17 00:00:00 2001 From: Ivan Kovalkovskyi Date: Fri, 9 Oct 2015 12:04:00 +0300 Subject: [PATCH 10/16] linked service bug fix --- service/admin.py | 9 +++++++-- service/forms.py | 4 +++- templates/admin/service/linked_service.html | 2 +- 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/service/admin.py b/service/admin.py index d91251fb..16bb9707 100644 --- a/service/admin.py +++ b/service/admin.py @@ -178,10 +178,15 @@ class LinkedServiceUpdateView(UpdateView): return self.success_url def form_valid(self, form): - self.object = form.save() - self.object.update_all_flags() + obj = form.save() + obj.countries = form.cleaned_data['countries'] + obj.expositions = form.cleaned_data['expositions'] + obj.conferences = form.cleaned_data['conferences'] + obj.save() + obj.update_all_flags() return HttpResponseRedirect(self.get_success_url()) + class LinkedServiceList(ListView): model = LinkedService template_name = 'admin/service/linked_service_list.html' diff --git a/service/forms.py b/service/forms.py index fa84b396..95460a5b 100644 --- a/service/forms.py +++ b/service/forms.py @@ -157,6 +157,7 @@ class LinkedServiceForm(forms.ModelForm): type = forms.MultipleChoiceField(choices = [(x, x) for x in list(Service.type)], widget = forms.CheckboxSelectMultiple, required=False) expositions = forms.CharField(widget=forms.HiddenInput,required=False) conferences = forms.CharField(widget=forms.HiddenInput, required=False) + countries = forms.MultipleChoiceField(choices=[(c.id, c.name) for c in list(set(Country.objects.language()))]) class Meta: model = LinkedService @@ -166,7 +167,8 @@ class LinkedServiceForm(forms.ModelForm): } def clean_countries(self): - return list(set(self.cleaned_data.get('countries'))) + countries = Country.objects.language().filter(id__in=self.cleaned_data['countries']) + return countries def clean_expositions(self): expositions = EmptyQuerySet() diff --git a/templates/admin/service/linked_service.html b/templates/admin/service/linked_service.html index 3ecb4f54..38908896 100644 --- a/templates/admin/service/linked_service.html +++ b/templates/admin/service/linked_service.html @@ -15,6 +15,7 @@ - @@ -15,25 +14,27 @@ {% block body %} - {% csrf_token %}{{ form.errors }} + {% csrf_token %}
    - {% if object %} Изменить {% else %} Добавить {% endif %}тему + {% if theme_id %} Изменить {% else %} Добавить {% endif %}тему

    Информация

    - {% for field in form %} - - - - {% endfor %} + {# name #} + {% with field='name' form=form languages=languages %} + {% include 'admin/forms/multilang.html' %} + {% endwith %} + + {# main_title #} + {% with field='main_title' form=form languages=languages %} + {% include 'admin/forms/multilang.html' %} + {% endwith %} + {# description #} + {% with field='description' form=form languages=languages %} + {% include 'admin/forms/multilang.html' %} + {% endwith %}
    diff --git a/theme/admin.py b/theme/admin.py index 8914587f..d2288161 100644 --- a/theme/admin.py +++ b/theme/admin.py @@ -182,13 +182,46 @@ class ThemeBlogListView(ListView): paginate_by = settings.ADMIN_PAGINATION -class ThemeBlogCreateView(CreateView): - template_name = "admin/theme/theme_blog_new.html" +class ThemeBlogDeleteView(DeleteView): + template_name = "admin/theme/theme_blog_confirm_delete.html" model = ThemeBlog - form_class = ThemeBlogForm success_url = reverse_lazy("theme_blog_all") + pk_url_kwarg = "theme_id" + +def blog_theme_add(request): + return add_object(request, ThemeBlogForm, 'theme_blog_new.html', reverse_lazy("theme_blog_all")) +@login_required +def blog_theme_change(request, theme_id=None): + try: + theme = ThemeBlog.objects.get(id=theme_id) + except: + return HttpResponseRedirect('theme_blog_all') + if request.POST: + form = ThemeBlogForm(request.POST) + if form.is_valid(): + form.save(theme_id) + return HttpResponseRedirect(reverse_lazy("theme_blog_all")) + else: + data = {} + for code, name in settings.LANGUAGES: + obj = ThemeBlog._meta.translations_model.objects.get(language_code = code,master__id=theme_id) #access to translated fields + data['name_%s'%code] = obj.name + data['description_%s'%code] = obj.description + data['main_title_%s'%code] = obj.main_title + form = ThemeBlogForm(data) + args = {} + args.update(csrf(request)) + args['form'] = form + args['languages'] = settings.LANGUAGES + args['theme_id'] = theme_id + + return render_to_response('admin/theme/theme_blog_new.html', args) + + + +# ====================================================== class ThemeBlogUpdateView(UpdateView): template_name = "admin/theme/theme_blog_new.html" model = ThemeBlog @@ -197,8 +230,8 @@ class ThemeBlogUpdateView(UpdateView): pk_url_kwarg = "theme_id" -class ThemeBlogDeleteView(DeleteView): - template_name = "admin/theme/theme_blog_confirm_delete.html" +class ThemeBlogCreateView(CreateView): + template_name = "admin/theme/theme_blog_new.html" model = ThemeBlog - success_url = reverse_lazy("theme_blog_all") - pk_url_kwarg = "theme_id" + form_class = ThemeBlogForm + success_url = reverse_lazy("theme_blog_all") \ No newline at end of file diff --git a/theme/admin_urls.py b/theme/admin_urls.py index 0caf5c87..423c6dc4 100644 --- a/theme/admin_urls.py +++ b/theme/admin_urls.py @@ -7,12 +7,12 @@ from .admin import ThemeBlogCreateView, ThemeBlogUpdateView, ThemeBlogDeleteView urlpatterns = patterns('theme.admin', url(r'^theme/add.*/$', 'theme_add'), url(r'^tag/add.*/$', 'tag_add'), - url(r'^blog_theme/add/$', ThemeBlogCreateView.as_view(), name = 'theme_blog_new'), + url(r'^blog_theme/add/$', 'blog_theme_add', name = 'theme_blog_new'), url(r'^theme/delete/(?P\d+)/$', 'theme_delete'), url(r'^tag/delete/(?P\d+)/$', 'tag_delete'), url(r'^blog_theme/delete/(?P\d+)/$', ThemeBlogDeleteView.as_view(), name = 'theme_blog_delete'), url(r'^theme/change/(?P\d+).*/$', 'theme_change'), - url(r'^blog_theme/change/(?P\d+).*/$', ThemeBlogUpdateView.as_view(), name= "theme_blog_change"), + url(r'^blog_theme/change/(?P\d+).*/$', 'blog_theme_change', name= "theme_blog_change"), url(r'^tag/change/(?P\d+).*/$', 'tag_change'), url(r'^theme/copy/(?P\d+).*/$', 'theme_copy'), url(r'^tag/copy/(?P\d+).*/$', 'tag_copy'), diff --git a/theme/forms.py b/theme/forms.py index 5f166b04..7571a784 100644 --- a/theme/forms.py +++ b/theme/forms.py @@ -149,7 +149,7 @@ from hvad.forms import TranslatableModelForm from .models import ThemeBlog -class ThemeBlogForm(TranslatableModelForm): +class _ThemeBlogForm(TranslatableModelForm): class Meta: model = ThemeBlog fields = ['url', 'name', 'main_title', 'description', 'inflect'] @@ -158,4 +158,34 @@ class ThemeBlogForm(TranslatableModelForm): def save(self, commit= True): if not 'url' in self.cleaned_data: self.cleaned_data['url'] = translit_with_separator(self.cleaned_data['name']) - return super(ThemeBlogForm, self).save(commit=True) \ No newline at end of file + return super(_ThemeBlogForm, self).save(commit=True) + + +class ThemeBlogForm(forms.Form): + + def __init__(self, *args, **kwargs): + super(ThemeBlogForm, self).__init__(*args, **kwargs) + # creates translated form fields, example: name_ru, name_en + # len(10) is a hack for detect if settings.LANGUAGES is not configured it return all langs + if len(settings.LANGUAGES) in range(10): + for lid, (code, name) in enumerate(settings.LANGUAGES): + # using enumerate for detect iteration number + # first iteration is a default lang so it required fields + required = True if lid == 0 else False + self.fields['name_%s' % code] = forms.CharField(label='Название', required=required) + self.fields['main_title_%s' % code] = forms.CharField(label='Заголовок', required=required) + self.fields['description_%s' % code] = forms.CharField(label='Описание', required=False, widget=CKEditorWidget)#with saving form + + def save(self, id=None): + data = self.cleaned_data + if not id: + theme = ThemeBlog() + else: + theme = ThemeBlog.objects.get(id=id) + if not getattr(theme, 'url'): + theme.url = translit_with_separator(data['name_ru'].strip()).lower() + + fill_with_signal(ThemeBlog, theme, data) + if not theme.url: + theme.url = translit_with_separator(theme.name) + theme.save() diff --git a/theme/models.py b/theme/models.py index 93908fd7..dd01de1c 100644 --- a/theme/models.py +++ b/theme/models.py @@ -273,6 +273,7 @@ def pre_save_handler(sender, **kwargs): pre_save.connect(pre_save_handler, sender=Tag) post_save.connect(post_save_handler, sender=Theme) +post_save.connect(post_save_handler, sender=ThemeBlog) post_save.connect(post_save_handler, sender=Tag) From bc10a73aa23a01beaea656224a60d586412f0348 Mon Sep 17 00:00:00 2001 From: Ivan Kovalkovskyi Date: Tue, 13 Oct 2015 14:12:21 +0300 Subject: [PATCH 15/16] conference main page --- conference/models.py | 1 + expobanner/admin.py | 54 ++++++++++++++++++-- expobanner/admin_urls.py | 6 +++ expobanner/forms.py | 32 ++++++++++++ expobanner/models.py | 8 ++- templates/admin/expobanner/default_form.html | 2 +- templates/admin/expobanner/main_list.html | 23 +++++++-- templates/admin/expobanner/paid_create.html | 33 ++++++++++++ templates/admin/includes/admin_nav.html | 1 + 9 files changed, 149 insertions(+), 11 deletions(-) diff --git a/conference/models.py b/conference/models.py index 067371db..f1173103 100644 --- a/conference/models.py +++ b/conference/models.py @@ -111,6 +111,7 @@ class Conference(TranslatableModel, EventMixin, ExpoMixin): keywords=models.CharField(max_length=250), ) + main = models.ForeignKey('expobanner.MainPage', blank=True, null=True, on_delete=models.SET_NULL) #fields saves information about creating and changing model created = models.DateTimeField(auto_now_add=True) modified = models.DateTimeField(auto_now=True) diff --git a/expobanner/admin.py b/expobanner/admin.py index 4c053c53..30c528be 100644 --- a/expobanner/admin.py +++ b/expobanner/admin.py @@ -6,9 +6,9 @@ from django.shortcuts import get_object_or_404 from django.db.models import Sum from expobanner.models import URL, BannerGroup, Banner, Paid, MainPage, Top from expobanner.forms import UrlCreateForm, BannerCreateGroupForm, BannerCreateForm, BannerGroupUpdateForm,\ - PaidCreateForm, PaidUpdateForm, TopCreateForm, BannerLinkCreateForm, MainCreateForm, MainUpdateForm, TopUpdateForm + PaidCreateForm, PaidUpdateForm, TopCreateForm, BannerLinkCreateForm, MainCreateForm, MainConfCreateForm, MainUpdateForm, TopUpdateForm from exposition.models import Exposition - +from conference.models import Conference class BannersControl(TemplateView): template_name = 'admin/expobanner/banners_control.html' @@ -203,6 +203,8 @@ class PaidStat(DetailView): return context # ---------------------------------- + + class MainList(ListView): model = Exposition template_name = 'admin/expobanner/main_list.html' @@ -227,7 +229,6 @@ class MainUpdate(UpdateView): template_name = 'admin/expobanner/default_form.html' success_url = '/admin/expobanners/main/list/' - def get_context_data(self, **kwargs): context = super(MainUpdate, self).get_context_data(**kwargs) obj = self.object @@ -235,6 +236,50 @@ class MainUpdate(UpdateView): return context +class MainConfList(ListView): + model = Conference + template_name = 'admin/expobanner/main_list.html' + paginate_by = settings.ADMIN_PAGINATION + + def get_queryset(self): + qs = self.model.objects.language().filter(main__isnull=False).order_by('-main__public') + if self.request.GET.get('onlypublic'): + qs = qs.filter(main__public=True) + return qs + + def get_context_data(self, **kwargs): + context = super(MainConfList, self).get_context_data(**kwargs) + context.update({'conf': True}) + return context + + +from django.core.urlresolvers import reverse_lazy + + +class MainConfCreate(CreateView): + form_class = MainConfCreateForm + template_name = 'admin/expobanner/paid_create.html' + success_url = reverse_lazy('expobanner-conf-list_main') + + def get_context_data(self, **kwargs): + context = super(MainConfCreate, self).get_context_data(**kwargs) + context.update({'conf': True}) + return context + + +class MainConfUpdate(UpdateView): + model = MainPage + form_class = MainUpdateForm + template_name = 'admin/expobanner/default_form.html' + success_url = reverse_lazy('expobanner-conf-list_main') + + def get_context_data(self, **kwargs): + context = super(MainConfUpdate, self).get_context_data(**kwargs) + obj = self.object + context['conference'] = obj.get_event() + return context + + def main_turn(request, pk, status): main = get_object_or_404(MainPage, pk=pk) if status == 'on': @@ -242,10 +287,11 @@ def main_turn(request, pk, status): else: main.public = False main.save() - return HttpResponseRedirect('/admin/expobanners/main/list/') + return HttpResponseRedirect(request.META['HTTP_REFERER']) from datetime import datetime + class MainStat(DetailView): model = MainPage template_name = 'admin/expobanner/main_stat.html' diff --git a/expobanner/admin_urls.py b/expobanner/admin_urls.py index cce3e1aa..0c46fcd8 100644 --- a/expobanner/admin_urls.py +++ b/expobanner/admin_urls.py @@ -36,4 +36,10 @@ urlpatterns = patterns('expobanner.admin', url(r'^main/$', MainCreate.as_view(), name='expobanner-create_main'), url(r'^main/turn/(?P\d+)/(?P.*)/$', main_turn, name='expobanner-main-turn'), url(r'^main/(?P\d+)/stat/$', MainStat.as_view(), name='expobanner_stat_main'), + # conference on main page + url(r'^main/conf/list/$', MainConfList.as_view(), name='expobanner-conf-list_main'), + url(r'^main/conf/(?P\d+)/edit/$', MainConfUpdate.as_view(), name='expobanner-conf-update_main'), + url(r'^main/conf/$', MainConfCreate.as_view(), name='expobanner-conf-create_main'), + url(r'^main/conf/turn/(?P\d+)/(?P.*)/$', main_turn, name='expobanner-conf-main-turn'), + #url(r'^main/conf/(?P\d+)/stat/$', MainStat.as_view(), name='expobanner_stat_main'), ) \ No newline at end of file diff --git a/expobanner/forms.py b/expobanner/forms.py index 84d45965..a5a12179 100644 --- a/expobanner/forms.py +++ b/expobanner/forms.py @@ -2,6 +2,7 @@ from django import forms from expobanner.models import URL, BannerGroup, Banner, Paid, Top, MainPage from exposition.models import Exposition +from conference.models import Conference from country.models import Country from ckeditor.widgets import CKEditorWidget from theme.models import Theme, Tag @@ -107,6 +108,7 @@ class PaidCreateForm(forms.ModelForm): raise forms.ValidationError(u'Такой выставки не существует') return expo + class MainCreateForm(forms.ModelForm): verbose = u'Добавить выставку на главную' exposition = forms.CharField(label=u'Выставка', widget=forms.HiddenInput()) @@ -137,6 +139,36 @@ class MainCreateForm(forms.ModelForm): return expo +class MainConfCreateForm(forms.ModelForm): + verbose = u'Добавить конференцию на главную' + conf = forms.CharField(label=u'Конференция', widget=forms.HiddenInput()) + + class Meta: + model = MainPage + fields = ['position', 'public'] + + def save(self, commit=True): + main = super(MainConfCreateForm, self).save(commit=False) + if commit: + conf = self.cleaned_data['conf'] + link = conf.get_permanent_url() + link_b = Banner.objects.create_for_paid(conf, link, 'main_page_link') + main.link = link_b + main.save() + + conf.main = main + conf.save() + return main + + def clean_conf(self): + conf_id = self.cleaned_data['conf'] + try: + conf = Conference.objects.get(id=conf_id) + except Conference.DoesNotExist: + raise forms.ValidationError(u'Такой конференции не существует') + return conf + + class PaidUpdateForm(forms.ModelForm): tickets = forms.URLField(label=u'Линк на билеты') participation = forms.URLField(label=u'Линк на участие') diff --git a/expobanner/models.py b/expobanner/models.py index 2208fc9a..8a1afabd 100644 --- a/expobanner/models.py +++ b/expobanner/models.py @@ -297,7 +297,13 @@ class MainPage(models.Model, StatMixin): try: return self.exposition_set.all()[0] except IndexError: - return None + try: + return self.conference_set.all()[0] + except IndexError: + return None + + def __unicode__(self): + return self.get_event().url def generatePassword(length=5): diff --git a/templates/admin/expobanner/default_form.html b/templates/admin/expobanner/default_form.html index 3322088e..46a441d9 100644 --- a/templates/admin/expobanner/default_form.html +++ b/templates/admin/expobanner/default_form.html @@ -51,7 +51,7 @@
    -

    {{ form.verbose }}

    +

    {% if form.verbose %} {{ form.verbose }} {% else %} {{ object.get_event }} {% endif %}

    {% for field in form %} diff --git a/templates/admin/expobanner/main_list.html b/templates/admin/expobanner/main_list.html index a06a2411..2af62ce8 100644 --- a/templates/admin/expobanner/main_list.html +++ b/templates/admin/expobanner/main_list.html @@ -4,13 +4,17 @@
    -

    Список выставок на главной

    +

    Список {% if conf %}конференций{% else %}выставок{% endif %} на главной

    {% block list_table %} + {% endif %} +
    Только опубликование @@ -19,7 +23,11 @@ - + {% if conf %} + + {% else %} + + {% endif %} @@ -31,8 +39,13 @@ - - + {% if conf %} + + + {% else %} + + + {% endif %} {% endfor %} diff --git a/templates/admin/expobanner/paid_create.html b/templates/admin/expobanner/paid_create.html index 4e3af395..ede4d3da 100644 --- a/templates/admin/expobanner/paid_create.html +++ b/templates/admin/expobanner/paid_create.html @@ -39,6 +39,39 @@ } }); + + $('#id_conf').select2({ + placeholder: 'Найти', + width: 'element', + ajax: { + url: '/admin/conference/search/', + dataType: "json", + quietMillis: 200, + multiple: true, + + data: function(term, page){ + return {term: term, + page: page}; + }, + + results: function (data) { + var results = []; + $.each(data, function(index, item){ + results.push({ + id: item.id, + text: item.label + }); + }); + return {results: results}; + } + }, + initSelection : function(element, callback) { + var id= $(element).val(); + var text = $(element).attr('data-init-text'); + callback({id: id, text:text}); + + } + }); }); {% endblock %} diff --git a/templates/admin/includes/admin_nav.html b/templates/admin/includes/admin_nav.html index f70cb26a..6286d233 100644 --- a/templates/admin/includes/admin_nav.html +++ b/templates/admin/includes/admin_nav.html @@ -107,6 +107,7 @@
  • Платные выставки
  • Выставки в топе
  • Выставки на главной
  • +
  • Конференции на главной
  • From 032d989323a1186b457c0c9bbf6524e863f9323d Mon Sep 17 00:00:00 2001 From: Nazar Kotjuk Date: Wed, 14 Oct 2015 00:41:46 +0300 Subject: [PATCH 16/16] dev fixes --- conference/models.py | 10 +++++++ exposition/models.py | 11 +++----- functions/model_mixin.py | 17 +++++------- functions/models_methods.py | 16 ++++++++++++ proj/views.py | 26 +++++++++---------- templates/admin/article/blog_form.html | 2 +- .../conference/conference_services.html | 15 +++++------ .../client/includes/index/main_events.html | 2 +- 8 files changed, 57 insertions(+), 42 deletions(-) diff --git a/conference/models.py b/conference/models.py index f1173103..8f067230 100644 --- a/conference/models.py +++ b/conference/models.py @@ -133,6 +133,13 @@ class Conference(TranslatableModel, EventMixin, ExpoMixin): return list(qs) #return list(Service.objects.language().filter(url__in=ids, type=Service.type.conference).order_by('sort')) + def get_services_detail(self): + excluded = ['tickets'] + country_ids = [item for item, bool in self.country.services if bool==True] + ids = [item for item, bool in self.services if bool==True] + qs = Service.objects.language().exclude(url__in=excluded).filter(Q(Q(url__in=country_ids) & Q(type=Service.type.conference)) | Q(url__in=ids)) + return list(qs) + def get_nearest_events(self): if self.theme.all(): theme = self.theme.all()[0] @@ -164,6 +171,9 @@ class Conference(TranslatableModel, EventMixin, ExpoMixin): def get_visit_url(self): return '/conference-visit/%s/'%self.id + def get_note_url(self): + return '/conference/add-note/%s/'%self.url + def get_note_by_user(self, user_id): note = self.note.filter(user__id=user_id) try: diff --git a/exposition/models.py b/exposition/models.py index f8a652bb..0ba5874a 100644 --- a/exposition/models.py +++ b/exposition/models.py @@ -183,7 +183,7 @@ class Exposition(TranslatableModel, EventMixin, ExpoMixin): country_ids = [item for item, bool in self.country.services if bool==True] ids = [item for item, bool in self.services if bool==True] qs = Service.objects.language().exclude(url__in=excluded).filter(Q(Q(url__in=country_ids) & Q(type=Service.type.expo)) | Q(url__in=ids)) - return qs + return list(qs) def get_parent(self): return {} @@ -292,6 +292,9 @@ class Exposition(TranslatableModel, EventMixin, ExpoMixin): def get_visit_url(self): return '/exposition-visit/%s/'%self.id + def get_note_url(self): + return '/expo/add-note/%s/'%self.url + def get_timetables_days(self): tables = self.business_program.all() days = [] @@ -313,12 +316,6 @@ class Exposition(TranslatableModel, EventMixin, ExpoMixin): def theme_ids(self): return [item['id'] for item in self.theme.all().values('id')] - def get_main_link(self): - if self.main: - return self.main.link.get_click_link() - else: - return self.get_permanent_url() - def get_top_link(self): if self.top: return self.top.link.get_click_link() diff --git a/functions/model_mixin.py b/functions/model_mixin.py index 5577ac9c..30b0a6de 100644 --- a/functions/model_mixin.py +++ b/functions/model_mixin.py @@ -5,11 +5,6 @@ from service.models import Service class ExpoMixin(object): - -# def get_index_text(self): -# names = [tr.name for tr in self.translations.all()] -# return names - def get_logo(self): logo = self.files.filter(purpose='logo') @@ -34,6 +29,12 @@ class EventMixin(object): url = '%s%s/'%(self.get_catalog_url(), self.url) return url + def get_main_link(self): + if self.main: + return self.main.link.get_click_link() + else: + return self.get_permanent_url() + def get_paid_catalog_url(self): return self.paid_new.catalog.get_click_link() @@ -45,12 +46,6 @@ class EventMixin(object): def get_logo(self): return self.logo - """ - logo = self.files.filter(purpose='logo') - if logo: - return logo[0] - return logo - """ def get_preview(self): diff --git a/functions/models_methods.py b/functions/models_methods.py index c5c45e58..943fac5b 100644 --- a/functions/models_methods.py +++ b/functions/models_methods.py @@ -39,6 +39,22 @@ class ExpoManager(TranslationManager): return result + def conf_main(self): + lang = translation.get_language() + key = 'conf_main_page_key_%s'%lang + result = cache.get(key) + if not result: + result = list(self.language(lang). + select_related('country', 'city', 'place', 'main'). + prefetch_related('tag'). + filter(main__isnull=False). + filter(main__public=True)) + cache.set(key, result, 50) + + return result + + + class CityManager(TranslationManager): diff --git a/proj/views.py b/proj/views.py index cfb06577..4746b611 100644 --- a/proj/views.py +++ b/proj/views.py @@ -1,22 +1,18 @@ # -*- coding: utf-8 -*- -from django.core.context_processors import csrf from django.shortcuts import render_to_response from django.template import RequestContext from django.views.generic import TemplateView from django.conf import settings -from exposition.models import Exposition -from theme.models import Theme -from news.models import News -from article.models import Article -from functions.cache_mixin import JitterCacheMixin, CacheMixin - -from functions.forms import ThemeSearch, PlaceSearch - -from functions.search_forms import EventSearchForm, ExpositionSearchForm -from functions.custom_views import ExpoListView +from django.utils.translation import get_language +from functions.cache_mixin import JitterCacheMixin +from functions.forms import ThemeSearch +from functions.search_forms import ExpositionSearchForm from accounts.forms import RegistrationCompleteForm, SocialRegistrationCompleteForm from meta.models import SeoText -from django.utils.translation import get_language +from theme.models import Theme +from article.models import Article +from exposition.models import Exposition +from conference.models import Conference def clear_slashes(str_): @@ -73,11 +69,13 @@ def error404(request): class MainPageView(JitterCacheMixin, TemplateView): cache_range = settings.CACHE_RANGE - template_name = 'index.html' + template_name = 'client/index.html' def get_context_data(self, **kwargs): context = super(MainPageView, self).get_context_data(**kwargs) - ev = Exposition.objects.expo_main() + ex = Exposition.objects.expo_main() + conf = Conference.objects.conf_main() + ev = ex + conf events = sorted(ev, key=lambda x: x.main.position) # update main_page counter for event in events: diff --git a/templates/admin/article/blog_form.html b/templates/admin/article/blog_form.html index 057b565d..5bf5a5de 100644 --- a/templates/admin/article/blog_form.html +++ b/templates/admin/article/blog_form.html @@ -53,7 +53,7 @@ {% if not article %}
    - +
    {{ form.slug }} {{ form.slug.errors }} diff --git a/templates/client/includes/conference/conference_services.html b/templates/client/includes/conference/conference_services.html index 829bfd97..b98f4d71 100644 --- a/templates/client/includes/conference/conference_services.html +++ b/templates/client/includes/conference/conference_services.html @@ -2,13 +2,12 @@
    \ No newline at end of file diff --git a/templates/client/includes/index/main_events.html b/templates/client/includes/index/main_events.html index 17368ba8..6fa3c0ca 100644 --- a/templates/client/includes/index/main_events.html +++ b/templates/client/includes/index/main_events.html @@ -36,7 +36,7 @@
    ВыставкаКонференцияВыставкаПозиция    
    {{ item }} {{ item.main.position }}Изменить {% if item.main.public %}отключить{% else %}включить{% endif %} Изменить {% if item.main.public %}отключить{% else %}включить{% endif %} Изменить {% if item.main.public %}отключить{% else %}включить{% endif %} Статистика