From 097949195c17a4153f5d8c818e8e17e9828f5fb2 Mon Sep 17 00:00:00 2001 From: Nazar Kotjuk Date: Wed, 23 Sep 2015 08:03:12 +0300 Subject: [PATCH 01/18] Master hot fix --- expobanner/views.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/expobanner/views.py b/expobanner/views.py index 0c5a0438..1b6f069b 100644 --- a/expobanner/views.py +++ b/expobanner/views.py @@ -27,7 +27,10 @@ def get_banners(request): good_urls = [] for u in urls: if u.regex: - url_re = re.compile(u.url) + try: + url_re = re.compile(u.url) + except: + continue if url_re.findall(url): good_urls.append(u) elif url == u.url: From 1c296bd4cba6a5d3c69216bb9f515889827d7a6b Mon Sep 17 00:00:00 2001 From: Nazar Kotjuk Date: Wed, 30 Sep 2015 11:57:28 +0300 Subject: [PATCH 02/18] Merged from develop 30.10.2015. Hot fiexes on articles and event default descriptions --- article/management/commands/articles_from_blog.py | 4 ++-- templates/client/article/article.html | 1 + templates/client/article/news.html | 2 ++ templates/client/includes/conference/default_description.html | 3 +-- templates/client/includes/exposition/default_description.html | 3 +-- 5 files changed, 7 insertions(+), 6 deletions(-) diff --git a/article/management/commands/articles_from_blog.py b/article/management/commands/articles_from_blog.py index 7380727d..f75ae65e 100644 --- a/article/management/commands/articles_from_blog.py +++ b/article/management/commands/articles_from_blog.py @@ -11,8 +11,8 @@ from theme.models import Theme,Tag class Command(BaseCommand): def handle(self, *args, **options): db = MySQLdb.connect(host="localhost", - user="kotzilla", - passwd="qazedc", + user="debian-sys-maint", + passwd="LPoEhMvzURQoH1aJ", db="expomap_old_blog", charset='utf8', cursorclass=DictCursor) diff --git a/templates/client/article/article.html b/templates/client/article/article.html index e36596ee..9f93f1e2 100644 --- a/templates/client/article/article.html +++ b/templates/client/article/article.html @@ -30,6 +30,7 @@
+ {% trans 'Источник' %}: {{ object.author }} {% if object.tag.all.exists %}
{% include 'includes/article_tags.html' with obj=object %} diff --git a/templates/client/article/news.html b/templates/client/article/news.html index 5fb34f66..8bd86a60 100644 --- a/templates/client/article/news.html +++ b/templates/client/article/news.html @@ -34,7 +34,9 @@
{% trans 'Источник' %}: {{ object.author }} {% if object.tag.all.exists %} +
{% include 'client/includes/article_tags.html' with obj=object %} +
{% endif %}
diff --git a/templates/client/includes/conference/default_description.html b/templates/client/includes/conference/default_description.html index cd2633b1..f48ae75f 100644 --- a/templates/client/includes/conference/default_description.html +++ b/templates/client/includes/conference/default_description.html @@ -9,8 +9,7 @@ докладчиков конференции. Спикеров конференции {{name}} обычно окончательно утверждают за 1-2 месяца до начала конференции.

Ваши деловые контакты на {{name}}

Добавьте конференцию {{name}} в расписание, чтобы не потерять важное событие, - где встречаются профессионалы нужной Вам отрасли. Создавайте свой календарь мероприятий, просто нажав кнопку - "Добавить в календарь".

+ где встречаются профессионалы нужной Вам отрасли. Создавайте свое расписание мероприятий.

Планируете самостоятельную поездку на {{name}} ?

Если Вам требуется размещение, мы рекомендуем посмотреть отели и цены в период проведения конференции здесь. Не забудьте проверить место и даты конференции на официальном сайте и в календаре организатора. Событие могут перенести, diff --git a/templates/client/includes/exposition/default_description.html b/templates/client/includes/exposition/default_description.html index 7a61c2da..b3a5fea3 100644 --- a/templates/client/includes/exposition/default_description.html +++ b/templates/client/includes/exposition/default_description.html @@ -13,8 +13,7 @@

Ваш личный календарь

Добавьте выставку {{ name }} в календарь, чтобы не - потерять важное событие. Создавайте свой календарь мероприятий, - просто нажав кнопку Добавить в календарь.

+ потерять важное событие. Создавайте свое расписание мероприятий.

Планируете самостоятельную поездку на {{ name }}?

Мы рекомендуем посмотреть отели и цены в период проведения выставки From a073b650bfcf9a8761b47a8c2d6ae4a616e6940f Mon Sep 17 00:00:00 2001 From: Nazar Kotjuk Date: Thu, 1 Oct 2015 17:45:30 +0300 Subject: [PATCH 03/18] Check git --- proj/settings.py | 1 + 1 file changed, 1 insertion(+) diff --git a/proj/settings.py b/proj/settings.py index f7fb9c17..35b25d31 100644 --- a/proj/settings.py +++ b/proj/settings.py @@ -4,6 +4,7 @@ import os import django from django.utils.translation import ugettext_lazy as _ + DJANGO_ROOT = os.path.dirname(os.path.realpath(django.__file__)) SITE_ROOT = os.path.split(os.path.dirname(os.path.realpath(__file__)))[0] From 639a3edd84bed15b4de865d386a86faba8ed97de Mon Sep 17 00:00:00 2001 From: Nazar Kotjuk Date: Wed, 14 Oct 2015 01:55:56 +0300 Subject: [PATCH 04/18] Merged from develop --- article/forms.py | 8 ++++---- article/views.py | 10 +++++----- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/article/forms.py b/article/forms.py index 88849b80..787b31ee 100644 --- a/article/forms.py +++ b/article/forms.py @@ -266,7 +266,7 @@ class BlogForm(forms.ModelForm): class ArticleFilterForm(forms.Form): theme = forms.MultipleChoiceField(label=_(u'Тематика:'), required=False, - choices=[(item.id, item.name) for item in ThemeBlog.objects.language().distinct()]) + choices=[(item.id, item.name) for item in Theme.objects.language().distinct()]) tag = forms.CharField(label=_(u'Теги:'), widget=forms.HiddenInput(), required=False) ''' @@ -290,7 +290,7 @@ class BlogFilterForm(forms.Form): create dynamical translated fields fields """ super(BlogFilterForm, self).__init__(*args, **kwargs) - ids = [item['theme'] for item in list(Article.objects.blogs().values('theme').distinct())] + ids = set([item['blog_theme'] for item in list(Article.objects.blogs().filter(blog_theme__isnull=False).values('blog_theme'))]) self.fields['theme'] = forms.MultipleChoiceField(label=_(u'Тематика:'), required=False, choices=[(item.id, item.name) for item in ThemeBlog.objects.language().filter(id__in=ids)]) @@ -303,6 +303,6 @@ class NewsFilterForm(forms.Form): create dynamical translated fields fields """ super(NewsFilterForm, self).__init__(*args, **kwargs) - ids = [item['theme'] for item in list(Article.objects.news().values('theme').distinct())] + ids = set([item['theme'] for item in list(Article.objects.news().values('theme'))]) self.fields['theme'] = forms.MultipleChoiceField(label=_(u'Тематика:'), required=False, - choices=[(item.id, item.name) for item in Theme.objects.language().exclude(article__id=None).filter(id__in=ids)]) \ No newline at end of file + choices=[(item.id, item.name) for item in Theme.objects.language().filter(id__in=ids)]) \ No newline at end of file diff --git a/article/views.py b/article/views.py index 06932d0b..f62d3b5c 100644 --- a/article/views.py +++ b/article/views.py @@ -4,7 +4,7 @@ from django.views.generic import DetailView from functions.custom_views import ListView from django.http import HttpResponse from models import Article -from forms import ArticleFilterForm +from forms import ArticleFilterForm, BlogFilterForm, NewsFilterForm from theme.models import Tag, Theme, ThemeBlog from meta.views import MetadataMixin @@ -37,7 +37,7 @@ class NewsList(MetadataMixin, ListView): def get_context_data(self, **kwargs): context = super(NewsList, self).get_context_data(object_list=self.object_list) if self.request.GET: - filter_form = ArticleFilterForm(self.request.GET) + filter_form = NewsFilterForm(self.request.GET) tags = self.request.GET.getlist('tag') if u'' in tags: tags.remove(u'') @@ -48,7 +48,7 @@ class NewsList(MetadataMixin, ListView): filter_form.fields['tag'].widget.attrs['data-predifined'] = json.dumps(tags) filter_form.fields['tag'].widget.attrs['value'] = '' else: - filter_form = ArticleFilterForm() + filter_form = NewsFilterForm() context['article_filter_form'] = filter_form return context @@ -87,7 +87,7 @@ class BlogList(MetadataMixin, ListView): def get_context_data(self, **kwargs): context = super(BlogList, self).get_context_data(object_list=self.object_list) if self.request.GET: - filter_form = ArticleFilterForm(self.request.GET) + filter_form = BlogFilterForm(self.request.GET) tags = self.request.GET.getlist('tag') if u'' in tags: tags.remove(u'') @@ -98,7 +98,7 @@ class BlogList(MetadataMixin, ListView): filter_form.fields['tag'].widget.attrs['data-predifined'] = json.dumps(tags) filter_form.fields['tag'].widget.attrs['value'] = '' else: - filter_form = ArticleFilterForm() + filter_form = BlogFilterForm() context['article_filter_form'] = filter_form return context From e0e95e2db1546811f1fafa69e07a8db2c6cf86c7 Mon Sep 17 00:00:00 2001 From: Ivan Kovalkovskyi Date: Thu, 15 Oct 2015 13:03:31 +0300 Subject: [PATCH 05/18] Article bug fixes --- article/admin.py | 9 +++++---- article/forms.py | 2 ++ templates/client/article/news_list.html | 2 +- templates/client/includes/article_theme.html | 4 ++-- theme/urls.py | 1 + theme/views.py | 16 +++++++++++++++- 6 files changed, 26 insertions(+), 8 deletions(-) diff --git a/article/admin.py b/article/admin.py index 15cc4268..131ff9c4 100644 --- a/article/admin.py +++ b/article/admin.py @@ -171,7 +171,10 @@ class BlogView(FormView): article = self.obj data = {} data['slug'] = article.slug - data['theme'] = [item.id for item in article.blog_theme.all()] + if self.obj.type == Article.blog: + data['theme'] = [item.id for item in article.blog_theme.all()] + else: + data['theme'] = [item.id for item in article.theme.all()] if article.exposition: data['exposition'] = article.exposition.id if article.conference: @@ -200,13 +203,10 @@ class BlogView(FormView): else: return form_class() - - def get_context_data(self, **kwargs): context = super(BlogView, self).get_context_data(**kwargs) self.set_obj() - context['article'] = self.obj if context['article']: context['file_form'] = FileForm(initial={'model': 'article.Article'}) @@ -229,6 +229,7 @@ class NewsList(ListView): context['news_flag'] = True return context + class NewsView(BlogView): form_class = NewsForm template_name = 'article/blog_form.html' diff --git a/article/forms.py b/article/forms.py index 787b31ee..dee1d954 100644 --- a/article/forms.py +++ b/article/forms.py @@ -108,8 +108,10 @@ class NewsForm(BlogForm): article = super(NewsForm, self).save(author, article) exposition = self.cleaned_data.get('exposition') conference = self.cleaned_data.get('conference') + theme = self.cleaned_data.get('theme') article.exposition = exposition article.conference = conference + article.theme = theme article.save() return article diff --git a/templates/client/article/news_list.html b/templates/client/article/news_list.html index 9e671309..c35d5838 100644 --- a/templates/client/article/news_list.html +++ b/templates/client/article/news_list.html @@ -48,7 +48,7 @@ }, tags:{ placeholder:"{% trans 'Выберите ключевые теги' %}", - url:'http://{{ request.get_host }}/theme/get-tag/' + url:'http://{{ request.get_host }}/theme/get-news-tag/' } }); diff --git a/templates/client/includes/article_theme.html b/templates/client/includes/article_theme.html index b31570bd..039ee796 100644 --- a/templates/client/includes/article_theme.html +++ b/templates/client/includes/article_theme.html @@ -1,6 +1,6 @@ -{% with theme=obj.theme.all %} - {% for theme in obj.theme.all %} +{% with theme=obj.blog_theme.all %} + {% for theme in obj.blog_theme.all %} {{ theme.name }}{% if forloop.counter != themes|length %},{% endif %} {% endfor %} {% endwith %} \ No newline at end of file diff --git a/theme/urls.py b/theme/urls.py index 88a81794..276cfe2a 100644 --- a/theme/urls.py +++ b/theme/urls.py @@ -4,4 +4,5 @@ from django.conf.urls import patterns, url urlpatterns = patterns('', url(r'^get-tag/$', 'theme.views.get_tag'), url(r'^get-article-tags/$', 'theme.views.get_article_tags'), + url(r'^get-news-tag/$', 'theme.views.get_news_tags'), ) \ No newline at end of file diff --git a/theme/views.py b/theme/views.py index ce83a38a..29efa6bf 100644 --- a/theme/views.py +++ b/theme/views.py @@ -7,7 +7,7 @@ def get_tag(request): #if request.is_ajax(): themes = request.GET.getlist('themes[]') term = request.GET['term'].capitalize() - qs = Tag.objects.language().exclude(theme__article__id=None).distinct() + qs = Tag.objects.language().distinct() if term: qs = qs.filter(translations__name__contains=term) if themes: @@ -28,4 +28,18 @@ def get_article_tags(request): result = [{'id': tag.id, 'label': '%s (%s)'%(tag.name, tag.theme.name)} for tag in qs] result = sorted(result, key=lambda x:x['label']) + return HttpResponse(json.dumps(result), content_type='application/json') + + +def get_news_tags(request): + themes = request.GET.getlist('themes[]') + term = request.GET['term'].capitalize() + qs = Tag.objects.language().exclude(article=None).filter(article__type=2).distinct() + if term: + qs = qs.filter(translations__name__contains=term) + if themes: + qs = qs.filter(theme__id__in=themes).order_by('translations__name') + result = [{'id': tag.id, 'label': '%s (%s)'%(tag.name, tag.theme.name)} for tag in qs] + result = sorted(result, key=lambda x:x['label']) + return HttpResponse(json.dumps(result), content_type='application/json') \ No newline at end of file From 728e00fff0624495e6b324112489be28dd4545c1 Mon Sep 17 00:00:00 2001 From: Ivan Kovalkovskyi Date: Mon, 19 Oct 2015 12:33:32 +0300 Subject: [PATCH 06/18] conference default description bug fix --- 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 d5cf4c6b..3d3bf72c 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=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' %} +{% blocktrans with city=conf.city.name country=conf.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 ef8898e4f90865a0627994bf5e674d5d706cea28 Mon Sep 17 00:00:00 2001 From: Nazar Kotjuk Date: Mon, 19 Oct 2015 12:34:43 +0300 Subject: [PATCH 07/18] fix --- article/forms.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/article/forms.py b/article/forms.py index dee1d954..08f243a7 100644 --- a/article/forms.py +++ b/article/forms.py @@ -57,7 +57,9 @@ class BlogForm(forms.Form): article.author = author article.type = self.type - article.slug = data.get('slug') + if not getattr(article, 'slug', None): + article.slug = data['slug'] + if data['logo']: article.logo = data['logo'] article.publish_date = data['publish_date'] From 898b0b7a9a0872a31596ce352fac726d7d73ecad Mon Sep 17 00:00:00 2001 From: Nazar Kotjuk Date: Thu, 22 Oct 2015 14:23:39 +0300 Subject: [PATCH 08/18] Fix places --- .../management/commands/exposition_en.py | 2 +- functions/admin_views.py | 4 +- import_xls/admin.py | 70 +-- import_xls/admin_urls.py | 10 +- import_xls/excel_settings.py | 501 ++++++++---------- import_xls/export_forms.py | 22 +- import_xls/import_forms.py | 173 ++++-- place_conference/admin.py | 57 ++ place_conference/admin_urls.py | 4 +- place_conference/forms.py | 53 +- place_conference/models.py | 47 +- place_exposition/forms.py | 26 +- place_exposition/models.py | 15 +- place_exposition/views.py | 2 +- templates/admin/includes/admin_nav.html | 6 +- .../place_conference/place_conference.html | 340 ++++++++++++ .../place_conference_list.html | 2 +- .../client/includes/place/place_info.html | 86 +++ .../client/includes/place/place_object.html | 408 ++++++-------- .../client/includes/place/place_services.html | 80 +++ 20 files changed, 1197 insertions(+), 711 deletions(-) create mode 100644 templates/admin/place_conference/place_conference.html create mode 100644 templates/client/includes/place/place_info.html create mode 100644 templates/client/includes/place/place_services.html diff --git a/exposition/management/commands/exposition_en.py b/exposition/management/commands/exposition_en.py index a0ae9d69..67addd68 100644 --- a/exposition/management/commands/exposition_en.py +++ b/exposition/management/commands/exposition_en.py @@ -4,7 +4,7 @@ from city.models import City from country.models import Country from place_exposition.models import PlaceExposition import xlrd, xlwt -from import_xls.excel_settings import import_settings, place_exp_sett +from import_xls.excel_settings import place_exp_sett from django.conf import settings diff --git a/functions/admin_views.py b/functions/admin_views.py index d20b361d..8a8ce342 100644 --- a/functions/admin_views.py +++ b/functions/admin_views.py @@ -128,9 +128,9 @@ class AdminListView(FormView): def get_context_data(self, **kwargs): context = super(AdminListView, self).get_context_data(**kwargs) if issubclass(self.model, TranslatableModel): - qs = self.model.objects.language('all').all().order_by('name') + qs = self.model.objects.language().all().order_by('name') else: - qs = self.model.objects.all().order_by('name') + qs = self.model.objects.all().order_by('-modified') result = paginate_results(qs, page=self.request.GET.get('page')) context['object_list'] = result return context diff --git a/import_xls/admin.py b/import_xls/admin.py index 0ceee351..c0820c30 100644 --- a/import_xls/admin.py +++ b/import_xls/admin.py @@ -1,22 +1,17 @@ # -*- coding: utf-8 -*- -from django.core.context_processors import csrf from django.shortcuts import render_to_response from django.http import HttpResponseRedirect, HttpResponse -from django.contrib.auth.decorators import login_required -from django.db.models.loading import get_model -# -import xlwt -import xlrd -# -from import_forms import ImportEventForm, ImportThemeForm, ImportTagForm, ImportOrganiserForm,\ - ImportPlaceConferenceForm, ImportPlaceExpositionForm -from export_forms import ExportEventForm, ExportOrganiserForm, ExportThemeForm, ExportTagForm,\ - ExportUserForm, ExportCompanyForm, ExportPlaceConferenceForm, ExportPlaceExpositionForm, ExportBlogForm,\ - ExportCityForm from django.views.generic import FormView, ListView, DeleteView from django.conf import settings from django.contrib import messages from django.shortcuts import get_object_or_404 +from import_xls.models import Log +from import_forms import ImportEventForm, ImportThemeForm, ImportTagForm, \ + ImportPlaceConferenceForm, ImportPlaceExpositionForm +from export_forms import ExportEventForm, ExportThemeForm, ExportTagForm,\ + ExportUserForm, ExportCompanyForm, ExportPlaceConferenceForm, ExportPlaceExpositionForm, ExportBlogForm,\ + ExportCityForm + def xls_to_response(xls, fname): response = HttpResponse(mimetype="application/ms-excel") @@ -41,7 +36,6 @@ class ImportView(FormView): return render_to_response(self.template_name, context) - class ExportView(FormView): """ abstract class @@ -57,85 +51,93 @@ class ExportView(FormView): return HttpResponseRedirect(self.success_url) return xls_to_response(workbook, f_name) -class ExportOrganiser(ExportView): - form_class = ExportOrganiserForm - success_url = '/admin/export-organiser' class ExportTheme(ExportView): form_class = ExportThemeForm success_url = '/admin/export-theme' + class ExportTag(ExportView): form_class = ExportTagForm success_url = '/admin/export-tag' + class ExportUser(ExportView): form_class = ExportUserForm success_url = '/admin/export-user' + class ExportCompany(ExportView): form_class = ExportCompanyForm success_url = '/admin/export-company' + class ExportPlaceConference(ExportView): form_class = ExportPlaceConferenceForm success_url = '/admin/export-place_conference' + class ExportPlaceExposition(ExportView): form_class = ExportPlaceExpositionForm success_url = '/admin/export-place_exposition' + class ExportBlog(ExportView): form_class = ExportBlogForm success_url = '/admin/export-blog/' + class ExportBlog(ExportView): form_class = ExportBlogForm success_url = '/admin/export-blog/' + class ExportCity(ExportView): form_class = ExportCityForm success_url = '/admin/export-city/' - -from import_xls.models import Log class ImportEvent(FormView): form_class = ImportEventForm success_url = '/admin/import-event/' template_name = 'admin/import templates/import_event.html' + def form_valid(self, form): errors = form.save_file_debug() return HttpResponseRedirect('/admin/import/log/') - #messages.success(self.request, 'Success') - #context = self.get_context_data() - #context['import_errors'] = errors - #context['form'] = form - #return render_to_response(self.template_name, context) +class ImportPlaceExposition(FormView): + form_class = ImportPlaceExpositionForm + success_url = '/admin/import-place_exposition/' + template_name = 'admin/import templates/import.html' + + def form_valid(self, form): + errors = form.save_file_debug() + return HttpResponseRedirect(self.success_url) + +class ImportPlaceConference(ImportView): + form_class = ImportPlaceConferenceForm + success_url = '/admin/import-place_conference' + + def form_valid(self, form): + errors = form.save_file_debug() + return HttpResponseRedirect(self.success_url) class ImportTheme(ImportView): form_class = ImportThemeForm success_url = '/admin/import-theme' + class ImportTag(ImportView): form_class = ImportTagForm success_url = '/admin/import-tag' -class ImportOrganiser(ImportView): - form_class = ImportOrganiserForm - success_url = '/admin/import-organiser' -class ImportPlaceExposition(ImportView): - form_class = ImportPlaceExpositionForm - success_url = '/admin/import-place_exposition' -class ImportPlaceConference(ImportView): - form_class = ImportPlaceConferenceForm - success_url = '/admin/import-place_conference' + class ExportEvent(ExportView): form_class = ExportEventForm @@ -148,6 +150,7 @@ class LogList(ListView): paginate_by = settings.ADMIN_PAGINATION template_name = 'admin/import templates/log.html' + class LogDelete(DeleteView): model = Log success_url = '/admin/import/log/' @@ -163,11 +166,12 @@ def log_file(request, log_id): response['X-Accel-Redirect'] = log.log.url return response + def work_file(request, log_id): log = get_object_or_404(Log, id=log_id) response = HttpResponse() response['content-type'] = 'application/x-executable' - filename = 'import_%s_file.xls'%str(log.id) + filename = 'import_%s_file.xls' % str(log.id) response['content-disposition'] = 'attachment;filename=%s'%filename response['X-Accel-Redirect'] = log.work_file.url return response \ No newline at end of file diff --git a/import_xls/admin_urls.py b/import_xls/admin_urls.py index 0d7af157..1aae00e4 100644 --- a/import_xls/admin_urls.py +++ b/import_xls/admin_urls.py @@ -1,25 +1,21 @@ # -*- coding: utf-8 -*- from django.conf.urls import patterns, url - -from admin import ImportTheme, ImportEvent, ImportOrganiser, ImportTag, ImportPlaceExposition, ImportPlaceConference - -from admin import ExportTheme, ExportEvent, ExportOrganiser, ExportTag, ExportPlaceExposition,\ - ExportPlaceConference, ExportCompany, ExportUser, ExportBlog, ExportCity, LogList from import_xls.admin import LogDelete +from admin import ImportTheme, ImportEvent, ImportTag, ImportPlaceExposition, ImportPlaceConference +from admin import ExportTheme, ExportEvent, ExportTag, ExportPlaceExposition,\ + ExportPlaceConference, ExportCompany, ExportUser, ExportBlog, ExportCity, LogList urlpatterns = patterns('', url(r'^import-event/$', ImportEvent.as_view()), url(r'^import-theme/$', ImportTheme.as_view()), url(r'^import-tag/$', ImportTag.as_view()), - url(r'^import-organiser/$', ImportOrganiser.as_view()), url(r'^import-place_exposition/$', ImportPlaceExposition.as_view()), url(r'^import-place_conference/$', ImportPlaceConference.as_view()), # url(r'^export-event/$', ExportEvent.as_view()), url(r'^export-theme/$', ExportTheme.as_view()), url(r'^export-tag/$', ExportTag.as_view()), - url(r'^export-organiser/$', ExportOrganiser.as_view()), url(r'^export-place_exposition/$', ExportPlaceExposition.as_view()), url(r'^export-place_conference/$', ExportPlaceConference.as_view()), url(r'^export-user/$', ExportUser.as_view()), diff --git a/import_xls/excel_settings.py b/import_xls/excel_settings.py index 936c5913..2754dd45 100644 --- a/import_xls/excel_settings.py +++ b/import_xls/excel_settings.py @@ -1,12 +1,22 @@ # -*- coding: utf-8 -*- +import urllib2 +from django.conf import settings +from django.contrib.contenttypes.models import ContentType +from django.core.validators import validate_email, URLValidator +from file.models import FileModel +from functions.files import get_alternative_filename +from place_exposition.models import EXPOSITION_TYPE +from place_exposition.models import Hall # bad practice of importing, but to many functions must be imported from .utils import * + def get_bool(value): if value: return 1 return '' + def get_int(value): if not value: return '' @@ -30,12 +40,14 @@ def get_tag(value): tag_names = [item['name'] for item in value.language('ru').all().values('name')] return ','.join(tag_names) + def get_place_type(value): for t in EXPOSITION_TYPE: if value == t[0]: return t[1] return t[0][1] + def get_periodic(value): if value: value = float(value) @@ -45,6 +57,7 @@ def get_periodic(value): return periodic.get(value, '') return '' + def get_quality(value, field): flags = {u'UFI': 'ufi', u'РСВЯ': 'rsva', u'EXPORATING': 'exporating'} v = flags.get(field) @@ -56,45 +69,6 @@ def get_quality(value, field): return '' - -place_settings=[ - {'name': 'id', 'verbose_name': u'id', 'type': get_int, 'width':1500}, - {'name': 'url', 'verbose_name': u'URL', 'type': unicode}, - {'name': 'name', 'verbose_name': u'Название', 'type': unicode}, - {'name': 'type', 'verbose_name': u'Тип', 'type': get_place_type},########## - {'name': 'main_title', 'verbose_name': u'Краткое описание', 'type': unicode}, - {'name': 'country', 'verbose_name': u'Страна', 'type': unicode}, - {'name': 'city', 'verbose_name': u'Город', 'type': unicode}, - {'name': 'address', 'verbose_name': u'Адресс', 'type': unicode}, - {'name': 'phone', 'verbose_name': u'Тел.', 'type': get_int}, - {'name': 'fax', 'verbose_name': u'Факс', 'type': get_int}, - {'name': 'web_page', 'verbose_name': u'Веб-сайт', 'type': unicode}, - {'name': 'email', 'verbose_name': u'Email', 'type': unicode}, - {'name': 'virtual_tour', 'verbose_name': u'Виртуальный тур', 'type': unicode}, - {'name': 'virtual_tour', 'verbose_name': u'Виртуальный тур', 'type': unicode}, - {'name': 'foundation_year', 'verbose_name': u'Год основания', 'type': get_int}, - {'name': 'event_in_year', 'verbose_name': u'Количество мероприятий в год', 'type': get_int}, - {'name': 'total_area', 'verbose_name': u'Общая выставочная площадь, кв. м.', 'type': get_int}, - {'name': 'closed_area', 'verbose_name': u'Закрытая выставочная площадь, кв. м.', 'type': get_int}, - {'name': 'open_area', 'verbose_name': u'Открытая выставочная площадь, кв. м.', 'type': get_int}, - {'name': 'total_pavilions', 'verbose_name': u'Количество павильонов', 'type': get_int}, - {'name': 'total_halls', 'verbose_name': u'Конференц-залы', 'type': get_int}, - {'name': 'bank', 'verbose_name': u'Банк/Банкоматы/Обмен валюты', 'type': get_bool}, - {'name': 'children_room', 'verbose_name': u'Детская комната', 'type': get_bool}, - {'name': 'disabled_service', 'verbose_name': u'Сервис для людей с ограниченными физическими возможностями', 'type': get_bool}, - {'name': 'conference_centre', 'verbose_name': u'Конгресс-центр', 'type': get_bool}, - {'name': 'business_centre', 'verbose_name': u'Бизнес-центр', 'type': get_bool}, - {'name': 'online_registration', 'verbose_name': u'On-line регистрация', 'type': get_bool}, - {'name': 'wifi', 'verbose_name': u'Wi-Fi', 'type': get_bool}, - {'name': 'cafe', 'verbose_name': u'Кафе и рестораны', 'type': get_bool}, - {'name': 'terminals', 'verbose_name': u'Информационные терминалы', 'type': get_bool}, - {'name': 'parking', 'verbose_name': u'Парковка', 'type': get_bool}, - {'name': 'press_centre', 'verbose_name': u'Пресс-центр', 'type': get_bool}, - {'name': 'mobile_application', 'verbose_name': u'Мобильное приложение', 'type': get_bool}, - -] - - def to_theme_type(st): if not st: return 15 @@ -105,37 +79,15 @@ def to_theme_type(st): return flag - - - -def to_currency(value): - if value=='USD': - return value - if value=='EUR': - return value - print(value) - return 'USD' - -def to_logo(url): - return None - -def to_photo(url): - return None - -def to_map(url): - return None - -from django.core.validators import validate_email, URLValidator - def to_url(url): validate = URLValidator() - try: validate(url) except: return '' return url + def to_email(email): try: validate_email(email) @@ -143,12 +95,6 @@ def to_email(email): return '' return email -from file.models import FileModel -import urllib2 -from django.conf import settings -from django.contrib.contenttypes.models import ContentType -from functions.files import get_alternative_filename - def save_file(obj, value, purpose): if not obj.id: @@ -178,42 +124,13 @@ def save_file(obj, value, purpose): file.save() -from file.models import Photo -def save_photo(obj, value): - if not obj.id: - return None - - urls = value.split(';') - - for url in urls: - - file_name = url.split('/')[-1] - alt_name = get_alternative_filename(settings.MEDIA_ROOT+'imgs/', file_name) - download_to = settings.MEDIA_ROOT+'photos/'+alt_name - try: - response = urllib2.urlopen(url, timeout=3) - except: - continue - - with open(download_to,'wb') as f: - f.write(response.read()) - f.close() - - - file_name ='photos/'+alt_name - content_type = ContentType.objects.get_for_model(obj) - photo = Photo(file_path=file_name, file_type='JPG', - content_type=content_type, object_id=obj.id) - photo.save() - - -from place_exposition.models import EXPOSITION_TYPE def to_type(value): for t in EXPOSITION_TYPE: if value == t[1]: return t[0] return 'Exposition complex' + def to_phone(value): if value: if isinstance(value, float) or isinstance(value, int): @@ -227,9 +144,6 @@ def to_phone(value): return value - - -from place_exposition.models import Hall def save_halls(obj, value): halls = value.split(';') res = [] @@ -266,51 +180,11 @@ def save_halls(obj, value): print('---------------------------------') - - - -place_exp_sett = { - u'ID':{u'field': u'id', u'func': to_int}, - u'Название ВЦ':{u'field': u'name', u'func': unicode}, - u'Тип':{u'field': u'type', u'func': to_type}, - u'Краткое описание':{u'field': u'main_title', u'func': unicode}, - u'Страна':{u'field': u'country', u'func': to_country}, - u'Город':{u'field': u'city_id', u'func': to_city, 'extra_values': 'country'}, - u'Описание':{u'field': u'description', u'func': unicode}, - u'Адрес':{u'field': u'adress', u'func': unicode}, - u'Тел.':{u'field': u'phone', u'func': to_phone}, - u'Факс':{u'field': u'fax', u'func': to_phone}, - u'Фото':{u'field': u'photo', u'func': save_photo, u'method': True}, - u'Лого':{u'field': u'logo', u'func': save_logo, u'method': True}, - u'Веб-сайт':{u'field': u'web_page', u'func': unicode}, - u'Email':{u'field': u'email', u'func': unicode}, - u'Карта проезда':{u'field': u'map', u'func': save_file, u'method': True, u'purpose': 'map'}, - u'Виртуальный тур':{u'field': u'virtual_tour', u'func': to_url}, - u'Год основания':{u'field': u'foundation_year', u'func': to_int}, - u'Валюта':{u'field': u'currency', u'func': to_currency}, - u'Количество мероприятий в год':{u'field': u'event_in_year', u'func': to_int}, - u'Общая выставочная площадь, кв. м.':{u'field': u'total_area', u'func': to_int}, - u'Закрытая выставочная площадь, кв. м.':{u'field': u'closed_area', u'func': to_int}, - u'Открытая выставочная площадь, кв. м.':{u'field': u'open_area', u'func': to_int}, - u'Количество павильонов':{u'field': u'total_pavilions', u'func': to_int}, - u'Площадь павильона':{u'field': u'halls', u'func': save_halls, u'method': True}, - u'Конференц-залы':{u'field': u'total_halls', u'func': to_int}, - u'Схема территории':{u'field': u'scheme', u'func': save_file, u'method': True, u'purpose': 'scheme teritory'},#сделать - u'Банк/Банкоматы/Обмен валюты':{u'field': u'bank', u'func': bool}, - u'Детская комната':{u'field': u'children_room', u'func': bool}, - u'Сервис для людей с ограниченными физическими возможностями':{u'field': u'disabled_service', u'func': bool}, - u'Конгресс-центр':{u'field': u'conference_centre', u'func': bool}, - u'Бизнес-центр':{u'field': u'business_centre', u'func': bool}, - u'On-line регистрация':{u'field': u'online_registration', u'func': bool}, - u'Wi-Fi':{u'field': u'wifi', u'func': bool}, - u'Кафе и рестораны':{u'field': u'cafe', u'func': bool}, - u'Информационные терминалы':{u'field': u'terminals', u'func': bool}, - u'Парковка':{u'field': u'parking', u'func': bool}, - u'Пресс-центр':{u'field': u'press_centre', u'func': bool}, - u'Мобильное приложение':{u'field': u'mobile_application', u'func': bool}, -} - - +def get_date(value): + try: + return value.strftime('%d.%m.%Y') + except AttributeError: + return '' article_sett = { @@ -321,66 +195,7 @@ article_sett = { u'Создана':{u'field': u'created', u'func': to_datetime} } -def get_date(value): - try: - return value.strftime('%d.%m.%Y') - except AttributeError: - return '' - - -event_export_sett = [ - {'name': 'id', 'verbose_name': u'ID', 'type': get_int, 'width':1500}, - {'name': 'url', 'verbose_name': u'Url', 'type': unicode}, - {'name': 'name', 'verbose_name': u'Название', 'type': unicode}, - {'name': 'main_title', 'verbose_name': u'Краткое описание', 'type': unicode}, - {'name': 'data_begin', 'verbose_name': u'Дата начала:(YYYY-MM-DD)', 'type': get_date}, - {'name': 'data_end', 'verbose_name': u'Дата окончания:(YYYY-MM-DD)', 'type': get_date}, - {'name': 'country', 'verbose_name': u'Страна', 'type': unicode}, - {'name': 'city', 'verbose_name': u'Город', 'type': unicode}, - {'name': 'place', 'verbose_name': u'Место проведения', 'type': get_place}, - {'name': 'theme', 'verbose_name': u'ID Тематики', 'type': get_theme, 'width':8000}, - {'name': 'tag', 'verbose_name': u'Теги', 'type': get_tag, 'width':8000}, - {'name': 'description', 'verbose_name': u'Описание события', 'type': unicode}, - {'name': 'org', 'verbose_name': u'Организатор №1', 'type': get_int}, - {'name': 'periodic', 'verbose_name': 'Периодичность', 'type': get_periodic}, - {'name': 'audience', 'verbose_name': u'Аудитория', 'type': get_audience}, - {'name': 'web_page', 'verbose_name': u'Официальный веб-сайт', 'type': unicode}, - {'name': 'products', 'verbose_name': u'Экспонируемые продукты', 'type': unicode}, - {'name': 'time', 'verbose_name': u'Время работы', 'type': unicode}, - {'name': 'logo', 'verbose_name': u'Логотип', 'type': unicode}, - {'name': 'currency', 'verbose_name': u'Валюта', 'type': unicode}, - {'name': 'price_day', 'verbose_name': u'Стоимость билета 1 день', 'type': unicode}, - {'name': 'price_all', 'verbose_name': u'Стоимость билета все дни', 'type': unicode}, - {'name': 'pre_condition', 'verbose_name': u'Условия предварительной регистрации', 'type': unicode}, - {'name': 'price_day_bar', 'verbose_name': u'Стоимость на стойке 1 день', 'type': unicode}, - {'name': 'price_all_bar', 'verbose_name': u'Стоимость на стойке все дни', 'type': unicode}, - {'name': 'stand_condition', 'verbose_name': u'Условия регистрации на стойке', 'type': unicode}, - {'name': 'visit_note', 'verbose_name': u'Примечание по посещению', 'type': unicode}, - {'name': 'price_catalog', 'verbose_name': u'Каталог', 'type': get_int}, - {'name': 'tax', 'verbose_name': u'Налог включен', 'type': get_bool, 'width':1000}, - {'name': 'foundation_year', 'verbose_name': u'Год основания', 'type': get_int}, - {'name': 'visitors', 'verbose_name': u'Посетители', 'type': get_int}, - {'name': 'members', 'verbose_name': u'Участники', 'type': get_int}, - #{'name': 'visit_note', 'verbose_name': u'Страны', 'type': unicode}, !!! delete from import - {'name': 'area', 'verbose_name': u'Площадь', 'type': get_int}, - {'name': 'min_closed_area', 'verbose_name': u'Min_Raw кв.м.', 'type': get_int}, - {'name': 'max_closed_area', 'verbose_name': u'Max_Raw кв.м.', 'type': get_int}, - {'name': 'min_closed_equipped_area', 'verbose_name': u'Min_Pack кв.м.', 'type': get_int}, - {'name': 'max_closed_equipped_area', 'verbose_name': u'Max_Pack кв.м.', 'type': get_int}, - {'name': 'max_open_area', 'verbose_name': u'Открытая площадь', 'type': get_int}, - {'name': 'min_stand_size', 'verbose_name': u'Мин. Площадь кв.м.', 'type': get_int}, - {'name': 'registration_payment', 'verbose_name': u'Регистрационный взнос', 'type': get_int}, - {'name': 'participation_note', 'verbose_name': u'Примечание по участии', 'type': unicode}, - {'name': 'application_deadline', 'verbose_name': u'Крайний срок подачи заявки', 'type': get_date}, - {'name': 'quality_label', 'verbose_name': u'UFI', 'type': get_quality}, #???? - {'name': 'quality_label', 'verbose_name': u'РСВЯ', 'type': get_quality},#??? - {'name': 'quality_label', 'verbose_name': u'EXPORATING', 'type': get_quality}, #??? - {'name': 'canceled_by_administrator', 'verbose_name': u'Отменена администратором', 'type': get_bool}, - {'name': 'expohit', 'verbose_name': u'ExpoHIT', 'type': get_bool}, - {'name': 'is_published', 'verbose_name': u'Опубликована', 'type': get_bool}, - -] - +# default export settings field_settings = [ {'name': 'id', 'verbose_name': u'ID', 'type': get_int, 'width':1500}, {'name': 'url', 'verbose_name': u'Url', 'type': unicode}, @@ -412,8 +227,6 @@ field_settings = [ {'name': 'price_catalog', 'verbose_name': u'Каталог', 'type': get_int}, {'name': 'tax', 'verbose_name': u'Налог включен', 'type': get_bool, 'width':1000}, {'name': 'foundation_year', 'verbose_name': u'Год основания', 'type': get_int}, - - {'name': 'visit_note', 'verbose_name': u'Посетители', 'type': unicode}, {'name': 'visit_note', 'verbose_name': u'Участники', 'type': unicode}, {'name': 'visit_note', 'verbose_name': u'Страны', 'type': unicode}, @@ -424,7 +237,6 @@ field_settings = [ {'name': 'visit_note', 'verbose_name': u'Max_Pack кв.м.', 'type': unicode}, {'name': 'visit_note', 'verbose_name': u'Открытая площадь', 'type': unicode}, {'name': 'visit_note', 'verbose_name': u'Мин. Площадь кв.м.', 'type': unicode}, - {'name': 'visit_note', 'verbose_name': u'Примечание по участии', 'type': unicode}, {'name': 'visit_note', 'verbose_name': u'Крайний срок подачи заявки', 'type': unicode}, {'name': 'visit_note', 'verbose_name': u'UFI', 'type': unicode}, @@ -432,21 +244,13 @@ field_settings = [ {'name': 'visit_note', 'verbose_name': u'EXPORATING', 'type': unicode}, {'name': 'canceled_by_administrator', 'verbose_name': u'Отменена администратором', 'type': get_bool}, {'name': 'visit_note', 'verbose_name': u'ExpoHIT', 'type': unicode}, - {'name': 'address', 'verbose_name': u'Адрес', 'type': unicode}, - - {'name': 'email', 'verbose_name': u'Email', 'type': unicode}, {'name': 'phone', 'verbose_name': u'Телефон', 'type': get_int}, - - {'name': 'foundation', 'verbose_name': u'Год основания', 'type': get_int}, #{'name': 'events_number', 'verbose_name': u'Год основания', 'type': get_int}, {'name': 'staff_number', 'verbose_name': u'Год основания', 'type': get_int}, {'name': 'specialization', 'verbose_name': u'Год основания', 'type': unicode}, - - - {'name': 'max_price', 'verbose_name': u'Максимальная цена', 'type': get_int}, {'name': 'min_price', 'verbose_name': u'Минимальная цена', 'type': get_int}, {'name': 'registration_payment', 'verbose_name': u'Регистрационный взнос', 'type': get_int}, @@ -459,68 +263,221 @@ field_settings = [ {'name': 'min_area', 'verbose_name': u'Минимальная площадь', 'type': get_int}, {'name': 'max_area', 'verbose_name': u'Максимальная площадь', 'type': get_int}, {'name': 'is_published', 'verbose_name': u'Опубликована', 'type': get_bool}, - ] - +# ----------------------EVENT SETTINGS ------------------------- event_sett = { - u'ID':{u'field': u'id', u'func': to_int}, - u'Url':{u'field': u'url', u'func': unicode}, - u'Название':{u'field': u'name', u'func': unicode}, - u'Краткое описание':{u'field': u'main_title', u'func': unicode}, - u'Дата начала:(YYYY-MM-DD)':{u'field': u'data_begin', u'func': to_date}, - u'Дата окончания:(YYYY-MM-DD)':{u'field': u'data_end', u'func': to_date}, - u'Страна':{u'field': u'country', u'func': to_country}, - u'Город':{u'field': u'city_id', u'func': to_city, 'extra_values': 'country'}, - u'Место проведения':{u'field': u'place', u'func': to_place}, - u'ID Тематики':{u'field': u'theme', u'func': to_theme, u'method': True},### - u'Теги':{u'field': u'tag', u'func': to_tag, u'method': True}, - u'Организатор №1':{u'field': u'org', u'func': unicode},#### + u'ID': {u'field': u'id', u'func': to_int}, + u'Url': {u'field': u'url', u'func': unicode}, + u'Название': {u'field': u'name', u'func': unicode}, + u'Краткое описание': {u'field': u'main_title', u'func': unicode}, + u'Дата начала:(YYYY-MM-DD)': {u'field': u'data_begin', u'func': to_date}, + u'Дата окончания:(YYYY-MM-DD)': {u'field': u'data_end', u'func': to_date}, + u'Страна': {u'field': u'country', u'func': to_country}, + u'Город': {u'field': u'city_id', u'func': to_city, 'extra_values': 'country'}, + u'Место проведения': {u'field': u'place', u'func': to_place}, + u'ID Тематики': {u'field': u'theme', u'func': to_theme, u'method': True},### + u'Теги': {u'field': u'tag', u'func': to_tag, u'method': True}, + u'Организатор №1': {u'field': u'org', u'func': unicode},#### #u'Организатор №2':{u'field': u'organiser', u'func': to_tag},#### - u'Описание события':{u'field': u'description', u'func': unicode}, - u'Основные темы':{u'field': u'main_themes', u'func': unicode}, - u'Условия и скидка':{u'field': u'discount_description', u'func': unicode}, - u'Периодичность':{u'field': u'periodic', u'func': to_periodic},### - u'Аудитория':{u'field': u'audience', u'func': to_audience}, - u'Официальный веб-сайт':{u'field': u'web_page', u'func': to_url}, - u'Линк на регистрацию':{u'field': u'link', u'func': to_url}, - u'Экспонируемые продукты':{u'field': u'products', u'func': unicode}, - u'Время работы':{u'field': u'time', u'func': unicode}, + u'Описание события': {u'field': u'description', u'func': unicode}, + u'Основные темы': {u'field': u'main_themes', u'func': unicode}, + u'Условия и скидка': {u'field': u'discount_description', u'func': unicode}, + u'Периодичность': {u'field': u'periodic', u'func': to_periodic},### + u'Аудитория': {u'field': u'audience', u'func': to_audience}, + u'Официальный веб-сайт': {u'field': u'web_page', u'func': to_url}, + u'Линк на регистрацию': {u'field': u'link', u'func': to_url}, + u'Экспонируемые продукты': {u'field': u'products', u'func': unicode}, + u'Время работы': {u'field': u'time', u'func': unicode}, u'Логотип':{u'field': u'logo', u'func': save_logo, u'method': True}, - u'Валюта':{u'field': u'currency', u'func': unicode}, - u'Стоимость билета 1 день':{u'field': u'price_day', u'func': unicode}, - u'Стоимость билета все дни':{u'field': u'price_all', u'func': unicode}, - u'Условия предварительной регистрации':{u'field': u'pre_condition', u'func': unicode}, - u'Стоимость на стойке 1 день':{u'field': u'price_day_bar', u'func': unicode}, - u'Стоимость на стойке все дни':{u'field': u'price_all_bar', u'func': unicode}, - u'Условия регистрации на стойке':{u'field': u'stand_condition', u'func': unicode}, - u'Примечание по посещению':{u'field': u'visit_note', u'func': unicode}, - u'Каталог':{u'field': u'price_catalog', u'func': to_int}, - u'Налог включен':{u'field': u'tax', u'func': bool}, - u'Год основания':{u'field': u'foundation_year', u'func': to_int}, - #???u'Данные за год':{u'field': u'periodic', u'func': to_int}, - u'Посетители':{u'field': u'visitors', u'func': to_int}, - u'Участники':{u'field': u'members', u'func': to_int}, - u'Страны':{u'field': u'stat_countries', u'func': unicode}, - u'Площадь':{u'field': u'area', u'func': to_int}, - u'Мин стоимость':{u'field': u'min_price', u'func': to_int}, - u'Макс стоимость':{u'field': u'max_price', u'func': to_int}, - u'Min_Raw кв.м.':{u'field': u'min_closed_area', u'func': to_int}, - u'Max_Raw кв.м.':{u'field': u'max_closed_area', u'func': to_int}, - u'Min_Pack кв.м.':{u'field': u'min_closed_equipped_area', u'func': to_int}, - u'Max_Pack кв.м.':{u'field': u'max_closed_equipped_area', u'func': to_int}, - u'Открытая площадь':{u'field': u'max_open_area', u'func': to_int}, - u'Мин. Площадь кв.м.':{u'field': u'min_stand_size', u'func': to_int}, - u'Регистрационный взнос':{u'field': u'registration_payment', u'func': to_int}, - u'Примечание по участии':{u'field': u'participation_note', u'func': unicode}, - u'Крайний срок подачи заявки':{u'field': u'application_deadline', u'func': to_date}, - u'UFI':{u'field': u'quality_label', u'func': check_quality_label, u'bitfield':True, u'label': 'ufi'}, - u'РСВЯ':{u'field': u'quality_label', u'func': check_quality_label, u'bitfield':True, u'label': 'rsva'}, - u'EXPORATING':{u'field': u'quality_label', u'func': check_quality_label, u'bitfield':True, u'label': 'exporating'}, - u'Отменена':{u'field': u'canceled', u'func': bool}, - u'ExpoHIT':{u'field': u'expohit', u'func': bool}, + u'Валюта': {u'field': u'currency', u'func': unicode}, + u'Стоимость билета 1 день': {u'field': u'price_day', u'func': unicode}, + u'Стоимость билета все дни': {u'field': u'price_all', u'func': unicode}, + u'Условия предварительной регистрации': {u'field': u'pre_condition', u'func': unicode}, + u'Стоимость на стойке 1 день': {u'field': u'price_day_bar', u'func': unicode}, + u'Стоимость на стойке все дни': {u'field': u'price_all_bar', u'func': unicode}, + u'Условия регистрации на стойке': {u'field': u'stand_condition', u'func': unicode}, + u'Примечание по посещению': {u'field': u'visit_note', u'func': unicode}, + u'Каталог': {u'field': u'price_catalog', u'func': to_int}, + u'Налог включен': {u'field': u'tax', u'func': bool}, + u'Год основания': {u'field': u'foundation_year', u'func': to_int}, + u'Посетители': {u'field': u'visitors', u'func': to_int}, + u'Участники': {u'field': u'members', u'func': to_int}, + u'Страны': {u'field': u'stat_countries', u'func': unicode}, + u'Площадь': {u'field': u'area', u'func': to_int}, + u'Мин стоимость': {u'field': u'min_price', u'func': to_int}, + u'Макс стоимость': {u'field': u'max_price', u'func': to_int}, + u'Min_Raw кв.м.': {u'field': u'min_closed_area', u'func': to_int}, + u'Max_Raw кв.м.': {u'field': u'max_closed_area', u'func': to_int}, + u'Min_Pack кв.м.': {u'field': u'min_closed_equipped_area', u'func': to_int}, + u'Max_Pack кв.м.': {u'field': u'max_closed_equipped_area', u'func': to_int}, + u'Открытая площадь': {u'field': u'max_open_area', u'func': to_int}, + u'Мин. Площадь кв.м.': {u'field': u'min_stand_size', u'func': to_int}, + u'Регистрационный взнос': {u'field': u'registration_payment', u'func': to_int}, + u'Примечание по участии': {u'field': u'participation_note', u'func': unicode}, + u'Крайний срок подачи заявки': {u'field': u'application_deadline', u'func': to_date}, + u'UFI': {u'field': u'quality_label', u'func': check_quality_label, u'bitfield':True, u'label': 'ufi'}, + u'РСВЯ': {u'field': u'quality_label', u'func': check_quality_label, u'bitfield':True, u'label': 'rsva'}, + u'EXPORATING': {u'field': u'quality_label', u'func': check_quality_label, u'bitfield':True, u'label': 'exporating'}, + u'Отменена': {u'field': u'canceled', u'func': bool}, + u'ExpoHIT': {u'field': u'expohit', u'func': bool}, +} + +event_export_sett = [ + {'name': 'id', 'verbose_name': u'ID', 'type': get_int, 'width':1500}, + {'name': 'url', 'verbose_name': u'Url', 'type': unicode}, + {'name': 'name', 'verbose_name': u'Название', 'type': unicode}, + {'name': 'main_title', 'verbose_name': u'Краткое описание', 'type': unicode}, + {'name': 'data_begin', 'verbose_name': u'Дата начала:(YYYY-MM-DD)', 'type': get_date}, + {'name': 'data_end', 'verbose_name': u'Дата окончания:(YYYY-MM-DD)', 'type': get_date}, + {'name': 'country', 'verbose_name': u'Страна', 'type': unicode}, + {'name': 'city', 'verbose_name': u'Город', 'type': unicode}, + {'name': 'place', 'verbose_name': u'Место проведения', 'type': get_place}, + {'name': 'theme', 'verbose_name': u'ID Тематики', 'type': get_theme, 'width':8000}, + {'name': 'tag', 'verbose_name': u'Теги', 'type': get_tag, 'width':8000}, + {'name': 'description', 'verbose_name': u'Описание события', 'type': unicode}, + {'name': 'org', 'verbose_name': u'Организатор №1', 'type': get_int}, + {'name': 'periodic', 'verbose_name': 'Периодичность', 'type': get_periodic}, + {'name': 'audience', 'verbose_name': u'Аудитория', 'type': get_audience}, + {'name': 'web_page', 'verbose_name': u'Официальный веб-сайт', 'type': unicode}, + {'name': 'products', 'verbose_name': u'Экспонируемые продукты', 'type': unicode}, + {'name': 'time', 'verbose_name': u'Время работы', 'type': unicode}, + {'name': 'logo', 'verbose_name': u'Логотип', 'type': unicode}, + {'name': 'currency', 'verbose_name': u'Валюта', 'type': unicode}, + {'name': 'price_day', 'verbose_name': u'Стоимость билета 1 день', 'type': unicode}, + {'name': 'price_all', 'verbose_name': u'Стоимость билета все дни', 'type': unicode}, + {'name': 'pre_condition', 'verbose_name': u'Условия предварительной регистрации', 'type': unicode}, + {'name': 'price_day_bar', 'verbose_name': u'Стоимость на стойке 1 день', 'type': unicode}, + {'name': 'price_all_bar', 'verbose_name': u'Стоимость на стойке все дни', 'type': unicode}, + {'name': 'stand_condition', 'verbose_name': u'Условия регистрации на стойке', 'type': unicode}, + {'name': 'visit_note', 'verbose_name': u'Примечание по посещению', 'type': unicode}, + {'name': 'price_catalog', 'verbose_name': u'Каталог', 'type': get_int}, + {'name': 'tax', 'verbose_name': u'Налог включен', 'type': get_bool, 'width':1000}, + {'name': 'foundation_year', 'verbose_name': u'Год основания', 'type': get_int}, + {'name': 'visitors', 'verbose_name': u'Посетители', 'type': get_int}, + {'name': 'members', 'verbose_name': u'Участники', 'type': get_int}, + #{'name': 'visit_note', 'verbose_name': u'Страны', 'type': unicode}, !!! delete from import + {'name': 'area', 'verbose_name': u'Площадь', 'type': get_int}, + {'name': 'min_closed_area', 'verbose_name': u'Min_Raw кв.м.', 'type': get_int}, + {'name': 'max_closed_area', 'verbose_name': u'Max_Raw кв.м.', 'type': get_int}, + {'name': 'min_closed_equipped_area', 'verbose_name': u'Min_Pack кв.м.', 'type': get_int}, + {'name': 'max_closed_equipped_area', 'verbose_name': u'Max_Pack кв.м.', 'type': get_int}, + {'name': 'max_open_area', 'verbose_name': u'Открытая площадь', 'type': get_int}, + {'name': 'min_stand_size', 'verbose_name': u'Мин. Площадь кв.м.', 'type': get_int}, + {'name': 'registration_payment', 'verbose_name': u'Регистрационный взнос', 'type': get_int}, + {'name': 'participation_note', 'verbose_name': u'Примечание по участии', 'type': unicode}, + {'name': 'application_deadline', 'verbose_name': u'Крайний срок подачи заявки', 'type': get_date}, + {'name': 'quality_label', 'verbose_name': u'UFI', 'type': get_quality}, #???? + {'name': 'quality_label', 'verbose_name': u'РСВЯ', 'type': get_quality},#??? + {'name': 'quality_label', 'verbose_name': u'EXPORATING', 'type': get_quality}, #??? + {'name': 'canceled_by_administrator', 'verbose_name': u'Отменена администратором', 'type': get_bool}, + {'name': 'expohit', 'verbose_name': u'ExpoHIT', 'type': get_bool}, + {'name': 'is_published', 'verbose_name': u'Опубликована', 'type': get_bool}, +] +# -----------------------END EVENT SETTINGS --------------------------------- + +# --------------PLACE EXPO SETTINGS----------------------------- + +# import +place_exp_sett = { + u'ID': {u'field': u'id', u'func': to_int}, + u'Название': {u'field': u'name', u'func': unicode}, + u'Тип': {u'field': u'type', u'func': to_type}, + u'Краткое описание': {u'field': u'main_title', u'func': unicode}, + u'Страна': {u'field': u'country', u'func': to_country}, + u'Город': {u'field': u'city_id', u'func': to_city, 'extra_values': 'country'}, + u'Описание': {u'field': u'description', u'func': unicode}, + u'Адрес': {u'field': u'adress', u'func': unicode}, + u'Тел.': {u'field': u'phone', u'func': to_phone}, + u'Факс': {u'field': u'fax', u'func': to_phone}, + u'Лого': {u'field': u'logo', u'func': save_logo, u'method': True}, + u'Веб-сайт': {u'field': u'web_page', u'func': unicode}, + u'Email': {u'field': u'email', u'func': unicode}, + u'Карта проезда': {u'field': u'map', u'func': save_file, u'method': True, u'purpose': 'map'}, + u'Виртуальный тур': {u'field': u'virtual_tour', u'func': to_url}, + u'Год основания': {u'field': u'foundation_year', u'func': to_int}, + u'Количество мероприятий в год': {u'field': u'event_in_year', u'func': to_int}, + u'Общая выставочная площадь, кв. м.': {u'field': u'total_area', u'func': to_int}, + u'Закрытая выставочная площадь, кв. м.': {u'field': u'closed_area', u'func': to_int}, + u'Открытая выставочная площадь, кв. м.': {u'field': u'open_area', u'func': to_int}, + u'Количество павильонов': {u'field': u'total_pavilions', u'func': to_int}, + u'Площадь павильона': {u'field': u'halls', u'func': save_halls, u'method': True}, + u'Конференц-залы': {u'field': u'total_halls', u'func': to_int}, + u'Схема территории': {u'field': u'scheme', u'func': save_file, u'method': True, u'purpose': 'scheme teritory'},#сделать + u'Банк/Банкоматы/Обмен валюты': {u'field': u'bank', u'func': bool}, + u'Детская комната': {u'field': u'children_room', u'func': bool}, + u'Сервис для людей с ограниченными физическими возможностями': {u'field': u'disabled_service', u'func': bool}, + u'Конгресс-центр': {u'field': u'conference_centre', u'func': bool}, + u'Бизнес-центр': {u'field': u'business_centre', u'func': bool}, + u'On-line регистрация': {u'field': u'online_registration', u'func': bool}, + u'Wi-Fi': {u'field': u'wifi', u'func': bool}, + u'Кафе и рестораны': {u'field': u'cafe', u'func': bool}, + u'Информационные терминалы': {u'field': u'terminals', u'func': bool}, + u'Парковка': {u'field': u'parking', u'func': bool}, + u'Пресс-центр': {u'field': u'press_centre', u'func': bool}, + u'Мобильное приложение': {u'field': u'mobile_application', u'func': bool}, + # place_conf settings + u'Мультимедийное оборудование': {u'field': u'multimedia_equipment', u'func': bool}, + u'Конференц-связь': {u'field': u'conference_call', u'func': bool}, + u'Оборудование для синхронного перевода': {u'field': u'translate_equipment', u'func': bool}, + u'Банкетный зал': {u'field': u'banquet_hall', u'func': bool}, + u'Кейтеринг': {u'field': u'catering', u'func': bool}, + u'Гостиница': {u'field': u'hotel', u'func': bool}, + u'Выставочный зал': {u'field': u'exposition_hall', u'func': bool}, + u'Площадь выст. зала': {u'field': u'exp_hall_area', u'func': to_int}, + u'Общая вместимость': {u'field': u'total_capacity', u'func': to_int}, + u'Количество залов': {u'field': u'amount_halls', u'func': bool}, } +# export +place_settings=[ + {'name': 'id', 'verbose_name': u'ID', 'type': get_int, 'width':1500}, + {'name': 'url', 'verbose_name': u'Url', 'type': unicode}, + {'name': 'name', 'verbose_name': u'Название', 'type': unicode}, + {'name': 'type', 'verbose_name': u'Тип', 'type': get_place_type},########## + {'name': 'main_title', 'verbose_name': u'Краткое описание', 'type': unicode}, + {'name': 'country', 'verbose_name': u'Страна', 'type': unicode}, + {'name': 'city', 'verbose_name': u'Город', 'type': unicode}, + {'name': 'adress', 'verbose_name': u'Адресс', 'type': unicode}, + {'name': 'phone', 'verbose_name': u'Тел.', 'type': get_int}, + {'name': 'fax', 'verbose_name': u'Факс', 'type': get_int}, + {'name': 'logo', 'verbose_name': u'Логотип', 'type': unicode}, + {'name': 'web_page', 'verbose_name': u'Веб-сайт', 'type': unicode}, + {'name': 'email', 'verbose_name': u'Email', 'type': unicode}, + {'name': 'virtual_tour', 'verbose_name': u'Виртуальный тур', 'type': unicode}, + {'name': 'foundation_year', 'verbose_name': u'Год основания', 'type': get_int}, + {'name': 'event_in_year', 'verbose_name': u'Количество мероприятий в год', 'type': get_int}, + {'name': 'total_area', 'verbose_name': u'Общая выставочная площадь, кв. м.', 'type': get_int}, + {'name': 'closed_area', 'verbose_name': u'Закрытая выставочная площадь, кв. м.', 'type': get_int}, + {'name': 'open_area', 'verbose_name': u'Открытая выставочная площадь, кв. м.', 'type': get_int}, + {'name': 'total_pavilions', 'verbose_name': u'Количество павильонов', 'type': get_int}, + {'name': 'total_halls', 'verbose_name': u'Конференц-залы', 'type': get_int}, + {'name': 'total_capacity', 'verbose_name': u'Общая вместимость', 'type': get_int}, + {'name': 'exposition_hall', 'verbose_name': u'Выставочный зал', 'type': get_bool}, + {'name': 'exp_hall_area', 'verbose_name': u'Площадь выст. зала', 'type': get_int}, + {'name': 'amount_halls', 'verbose_name': u'Количество залов', 'type': get_int}, + {'name': 'bank', 'verbose_name': u'Банк/Банкоматы/Обмен валюты', 'type': get_bool}, + {'name': 'children_room', 'verbose_name': u'Детская комната', 'type': get_bool}, + {'name': 'disabled_service', 'verbose_name': u'Сервис для людей с ограниченными физическими возможностями', 'type': get_bool}, + {'name': 'conference_centre', 'verbose_name': u'Конгресс-центр', 'type': get_bool}, + {'name': 'business_centre', 'verbose_name': u'Бизнес-центр', 'type': get_bool}, + {'name': 'online_registration', 'verbose_name': u'On-line регистрация', 'type': get_bool}, + {'name': 'wifi', 'verbose_name': u'Wi-Fi', 'type': get_bool}, + {'name': 'cafe', 'verbose_name': u'Кафе и рестораны', 'type': get_bool}, + {'name': 'terminals', 'verbose_name': u'Информационные терминалы', 'type': get_bool}, + {'name': 'parking', 'verbose_name': u'Парковка', 'type': get_bool}, + {'name': 'press_centre', 'verbose_name': u'Пресс-центр', 'type': get_bool}, + {'name': 'mobile_application', 'verbose_name': u'Мобильное приложение', 'type': get_bool}, + {'name': 'multimedia_equipment', 'verbose_name': u'Мультимедийное оборудование', 'type': get_bool}, + {'name': 'conference_call', 'verbose_name': u'Конференц-связь', 'type': get_bool}, + {'name': 'translate_equipment', 'verbose_name': u'Оборудование для синхронного перевода', 'type': get_bool}, + {'name': 'banquet_hall', 'verbose_name': u'Банкетный зал', 'type': get_bool}, + {'name': 'catering', 'verbose_name': u'Кейтеринг', 'type': get_bool}, + {'name': 'hotel', 'verbose_name': u'Гостиница', 'type': get_bool}, + +] +# -----------------END PLACE EXPO SETTINGS------------------------------ +# default import settings import_settings={ 'name': {'func': unicode}, 'url': {'func': unicode}, diff --git a/import_xls/export_forms.py b/import_xls/export_forms.py index 363c9ba3..4f1bf333 100644 --- a/import_xls/export_forms.py +++ b/import_xls/export_forms.py @@ -13,7 +13,7 @@ from place_exposition.models import PlaceExposition from place_conference.models import PlaceConference from django.db.models.loading import get_model import xlwt -from excel_settings import import_settings, field_settings, event_export_sett +from excel_settings import field_settings, event_export_sett languages = [code for code in settings.LANGUAGES] @@ -75,13 +75,6 @@ class ExportForm(forms.Form): return self.workbook - -class ExportOrganiserForm(ExportForm): - model = Organiser - - def get_fname(self): - return 'organisers.xls' - class ExportUserForm(ExportForm): model = User @@ -106,7 +99,9 @@ class ExportTagForm(ExportForm): from excel_settings import place_settings class ExportPlaceExpositionForm(ExportForm): + model = PlaceExposition + def export(self): data = self.cleaned_data objects = self.get_objects(data) @@ -130,21 +125,18 @@ class ExportPlaceExpositionForm(ExportForm): self.worksheet.write(0, col, field.get('verbose_name', 'default'), self.style) #self.worksheet.write(1, col, field.get('name'), self.style) self.worksheet.col(col).width = field.get('width', 3333) - if field['name']=='tag': - self.worksheet.write(row+1, col, field.get('type')(value, object.theme)) - else: - self.worksheet.write(row+1, col, field.get('type')(value)) + + self.worksheet.write(row+1, col, field.get('type')(value)) + col += 1 return self.workbook def get_fname(self): return 'places.xls' -class ExportPlaceConferenceForm(ExportForm): +class ExportPlaceConferenceForm(ExportPlaceExpositionForm): model = PlaceConference - def get_fname(self): - return 'places.xls' class ExportCompanyForm(ExportForm): model = Company diff --git a/import_xls/import_forms.py b/import_xls/import_forms.py index 8554605c..cf948bf8 100644 --- a/import_xls/import_forms.py +++ b/import_xls/import_forms.py @@ -1,18 +1,32 @@ # -*- coding: utf-8 -*- +import urllib +import json +import xlrd +from django.db import IntegrityError from django import forms from django.conf import settings +from django.db.models.loading import get_model from theme.models import Theme, Tag from place_exposition.models import PlaceExposition from place_conference.models import PlaceConference -from country.models import Country -from organiser.models import Organiser -from django.db.models.loading import get_model -import xlrd, xlwt +from import_xls.models import Log from excel_settings import import_settings from functions.form_check import translit_with_separator +from excel_settings import place_exp_sett +from import_xls.excel_settings import event_sett languages = [code for code in settings.LANGUAGES] +typical_errors = {'(1048, "Column \'city_id\' cannot be null")':u'Неправильная страна или город', + '(1048, "Column \'country_id\' cannot be null")':u'Неправильная страна или город', + '(1048, "Column \'data_end\' cannot be null")':u'НЕправильный формат или не заполнена дата окончания', + '(1048, "Column \'data_end\' cannot be null")':u'НЕправильный формат или не заполнена дата начала'} + + +def logcall(f, msg): + with open(f.file.name, 'a') as logfile: + logfile.write(msg.encode('utf8')) + class ImportForm(forms.Form): """ @@ -82,19 +96,11 @@ class ImportForm(forms.Form): object.save() -class ImportOrganiserForm(ImportForm): - model = Organiser - class ImportThemeForm(ImportForm): model = Theme -from excel_settings import place_exp_sett -from django.db import IntegrityError -import urllib, json - - def google_address(address): if address: address = address.encode('utf') @@ -112,13 +118,131 @@ def google_address(address): return '' return '' -from djutils.decorators import async -from djutils.queue.decorators import queue_command + # place class ImportPlaceExpositionForm(ImportForm): model = PlaceExposition settings = place_exp_sett + def get_row_object(self, row): + if row[0] != '': + # in first column id + try: + obj = self.model.objects.language(self.lang).get(id=int(row[0])) + except ValueError: + obj = self.model() + obj.translate(self.lang) + + except self.model.DoesNotExist: + obj = self.model(id= int(row[0])) + obj.translate(self.lang) + else: + # if id blank - its a new object + obj = self.model() + obj.translate(self.lang) + return obj + + + + def save_file_debug(self): + data = self.cleaned_data + lang, self.lang = data['language'], data['language'] + f = data['excel_file'] + book = xlrd.open_workbook(file_contents=f.read()) + sheet = book.sheet_by_index(0) + row_list = [sheet.row_values(row_number) for row_number in range(sheet.nrows)] + field_names = [name for name in row_list[0]] + model = self.model + labels = [label for label in row_list[0]] + errors = [] + + #log = Log.custom.create_log_name(f) + for row_number, row in enumerate(row_list): + if row_number == 0: + continue + #log_msg = u'[%s] %s: '%(str(row_number), row[2]) + obj = self.get_row_object(row) + methods = [] + # go through row cells + for col_number, cell in enumerate(row): + # get current label + label = labels[col_number] + + setting = event_sett.get(label) + if setting is None: + # no label in settings + continue + + if setting.get('method'): + # this cell contains data that must be written after creating object + if cell != "": + methods.append({'func': setting['func'], 'value': cell, + 'purpose': setting.get('purpose'), 'field': label}) + continue + + field_name = setting['field'] + func = setting.get('func') + if func is None: + # no function in settings + continue + + extra_value = setting.get('extra_values') + if extra_value is not None: + # if setting has extra value then + # it is some field like city, tag + # that has relation and can be created + + # in function we add language(need for relation fields) + # and extra value from object (like for city need country) + try: + extra = getattr(obj, extra_value) + except Exception: + continue + value = func(cell, 'ru', extra) + else: + value = func(cell) + + #try: + setattr(obj, field_name, value) + #except ValueError: + # continue + + if not obj.url: + obj.url = translit_with_separator(obj.name) + + # try: + obj.save() + # except IntegrityError, e: + # error = str(e) + # if typical_errors.get(error): + # error = typical_errors[error] + # if error.startswith('(1062, "Duplicate entry') and error.endswith('for key \'url\'")'): + # + # error = u'Событие с таким названием или урлом уже существует' + # + # errors.append([obj.name, error]) + # log_msg += error + # logcall(log.log, log_msg + '\n') + # continue + + for method in methods: + func = method['func'] + if method.get('purpose'): + try: + func(obj, method['value'], method['purpose']) + except: + #log_msg += '(%s: Ошибка);'%method['field'] + continue + else: + msg = func(obj, method['value']) + if msg: + #log_msg += '(%s: %s);'%(method['field'], msg) + pass + + #logcall(log.log, log_msg + '\n') + + + def save_file(self): data = self.cleaned_data lang = data['language'] @@ -234,27 +358,10 @@ class ImportPlaceExpositionForm(ImportForm): return errors - -class ImportPlaceConferenceForm(ImportForm): +class ImportPlaceConferenceForm(ImportPlaceExpositionForm): model = PlaceConference -from import_xls.excel_settings import event_sett -typical_errors = {'(1048, "Column \'city_id\' cannot be null")':u'Неправильная страна или город', - '(1048, "Column \'country_id\' cannot be null")':u'Неправильная страна или город', - '(1048, "Column \'data_end\' cannot be null")':u'НЕправильный формат или не заполнена дата окончания', - '(1048, "Column \'data_end\' cannot be null")':u'НЕправильный формат или не заполнена дата начала'} - -# event -import time -def logcall(f, msg): - with open(f.file.name, 'a') as logfile: - logfile.write(msg.encode('utf8')) - - - - -from import_xls.models import Log class ImportEventForm(ImportForm): """ extended form for importing one type of event @@ -359,8 +466,8 @@ class ImportEventForm(ImportForm): except Exception: setattr(obj, 'place_alt', cell) if not obj.url: - a = obj.name obj.url = translit_with_separator(obj.name) + obj.is_published = True try: obj.save() diff --git a/place_conference/admin.py b/place_conference/admin.py index 9fc3f793..1202bd5f 100644 --- a/place_conference/admin.py +++ b/place_conference/admin.py @@ -189,6 +189,63 @@ def conference_change(request, url): return render_to_response('place_conference_add.html', args) +from photologue.forms import PhotoForm +from functions.admin_views import AdminView +from file.forms import FileModelForm, FileForm +class PlaceConferenceView(AdminView): + form_class = ConferenceForm + model = PlaceConference + success_url = '/admin/place_conference/all/' + template_name = 'admin/place_conference/place_conference.html' + + def get_form(self, form_class): + if self.request.POST: + return super(PlaceConferenceView, self).get_form(form_class) + obj = self.set_obj() + if obj: + data = {'type': obj.type, 'address': obj.address, + 'phone': obj.phone, 'fax': obj.fax, 'web_page': obj.web_page, 'email': obj.email, + 'foundation_year': obj.foundation_year, 'total_capacity': obj.total_capacity, + 'amount_halls': obj.amount_halls, 'wifi':obj.wifi, 'multimedia_equipment': obj.multimedia_equipment, + 'conference_call':obj.conference_call, 'translate_equipment': obj.translate_equipment, + 'banquet_hall': obj.banquet_hall, 'catering': obj.catering, 'hotel': obj.hotel, + 'video_link':obj.video_link, 'logo': obj.logo, 'exposition_hall': obj.exposition_hall, + 'exp_hall_area': obj.exp_hall_area} + + data['country'] = obj.country_id + data['city'] = obj.city_id + + for code, name in settings.LANGUAGES: + trans_obj = self.model._meta.translations_model.objects.get(language_code = code,master__id=obj.id) #access to translated fields + data['name_%s'%code] = obj.name + data['main_title_%s'%code] = obj.main_title + data['description_%s'%code] = obj.description + data['adress_%s'%code] = obj.adress + data['hall_capacity_%s'%code] = obj.hall_capacity + data['title_%s'%code] = obj.title + data['keywords_%s'%code] = obj.keywords + data['descriptions_%s'%code] = obj.descriptions + data['total_year_action_%s'%code] = obj.total_year_action + + form = form_class(initial=data) + form.fields['city'].widget.attrs['data-init-text'] = obj.city.name + return form + else: + return form_class() + + + def get_context_data(self, **kwargs): + context = super(PlaceConferenceView, self).get_context_data(**kwargs) + obj = self.set_obj() + if obj: + context['file_form'] = FileForm(initial={'model': 'place_conference.PlaceConference'}) + files = FileModel.objects.filter(content_type=ContentType.objects.get_for_model(obj),object_id=getattr(obj, 'id')) + context['files'] = files + + context['photo_form'] = PhotoForm() + + return context + class PlaceConferenceListView(AdminListView): template_name = 'admin/place_conference/place_conference_list.html' form_class = PlaceConferenceFilterForm diff --git a/place_conference/admin_urls.py b/place_conference/admin_urls.py index aa45ae8a..4816e171 100644 --- a/place_conference/admin_urls.py +++ b/place_conference/admin_urls.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- from django.conf.urls import patterns, include, url -from admin import PlaceConferenceListView +from admin import PlaceConferenceListView, PlaceConferenceView urlpatterns = patterns('place_conference.admin', url(r'^add.*/$', 'conference_add'), @@ -9,4 +9,6 @@ urlpatterns = patterns('place_conference.admin', url(r'^copy/(?P.*)/$', 'place_conference_copy'), #url(r'^all/$', 'conference_all'), url(r'^all/$', PlaceConferenceListView.as_view()), + url(r'^(?P.*)/$', PlaceConferenceView.as_view()), + url(r'^$', PlaceConferenceView.as_view()), ) diff --git a/place_conference/forms.py b/place_conference/forms.py index 94b1dee6..f2e38aa5 100644 --- a/place_conference/forms.py +++ b/place_conference/forms.py @@ -28,12 +28,12 @@ class ConferenceForm(forms.Form): """ types = [(item1, item2) for item1, item2 in CONFERENCE_TYPE] type = forms.ChoiceField(label='Краткое описание', required=False, choices=types) - + logo = forms.ImageField(label='Logo', required=False, max_length=500) country = forms.ModelChoiceField(label='Страна', queryset=Country.objects.all(), empty_label=None) #creates select input with empty choices cause it will be filled with ajax - city = forms.ChoiceField(label='Город', choices=[('','')]) + city = forms.CharField(label='Город', widget=forms.HiddenInput()) - address = forms.CharField(label='Адресс', widget=LocationWidget) + address = forms.CharField(label='Адресс', widget=LocationWidget, required=False) foundation_year = forms.CharField(label='Год основания', required=False, widget=forms.TextInput(attrs={'placeholder': 'Год основания'})) phone = forms.CharField(label='Телефон', required=False, @@ -108,7 +108,7 @@ class ConferenceForm(forms.Form): """ - def save(self, id=None): + def save(self, obj=None): """ change PlaceConference model object with id = id N/A add new PlaceConference model object @@ -117,13 +117,20 @@ class ConferenceForm(forms.Form): """ data = self.cleaned_data #create new place_conference object or get exists - if not id: + if not obj: place_conference = PlaceConference() else: - place_conference = PlaceConference.objects.get(id=id) + place_conference = obj + + if not getattr(place_conference, 'url'): + if data.get('name_en'): + place_conference.url = translit_with_separator(data['name_en'].strip()).lower() + else: + place_conference.url = translit_with_separator(data['name_ru'].strip()).lower() + if data.get('logo'): + place_conference.logo = data['logo'] #simple fields - place_conference.url = translit_with_separator(data['name_ru'].strip()).lower() place_conference.type = data['type'] place_conference.address = data['address'] place_conference.phone = data['phone'] @@ -152,22 +159,9 @@ class ConferenceForm(forms.Form): fill_with_signal(PlaceConference, place_conference, data) #save files - check_tmp_files(place_conference, data['key']) - - return PlaceConference.objects.get(id=place_conference.id) - - def clean(self): - id = self.cleaned_data.get('place_conference_id') - name_ru = self.cleaned_data.get('name_ru') - - place_conference = PlaceConference.objects.filter(url=translit_with_separator(name_ru)) - if place_conference and str(place_conference[0].id) != id: - msg = 'Место проведения с таким названием уже существует' - self._errors['name_ru'] = ErrorList([msg]) - del self.cleaned_data['name_ru'] - - return self.cleaned_data + place_conference.save() + return place_conference def clean_web_page(self): """ @@ -318,4 +312,17 @@ class HallForm(forms.ModelForm): class PlaceConferenceFilterForm(AdminFilterForm): - model = PlaceConference \ No newline at end of file + model = PlaceConference + + country = forms.MultipleChoiceField(choices=[(item.id, item.name) for item in list(Country.objects.all())], + required=False, widget=forms.SelectMultiple()) + + def filter(self): + qs = super(PlaceConferenceFilterForm, self).filter() + data = self.cleaned_data + country = data['country'] + + if country: + qs = qs.filter(country_id__in=country) + + return qs \ No newline at end of file diff --git a/place_conference/models.py b/place_conference/models.py index 170a8806..03fe4f1b 100644 --- a/place_conference/models.py +++ b/place_conference/models.py @@ -1,11 +1,11 @@ # -*- coding: utf-8 -*- from django.db import models from django.contrib.contenttypes import generic -from django.db.models.signals import post_save +from django.db.models.signals import post_save, pre_save from hvad.models import TranslatableModel, TranslatedFields, TranslationManager from functions.custom_fields import EnumField from functions.custom_fields import LocationField -from functions.signal_handlers import post_save_handler +from functions.signal_handlers import post_save_handler, pre_save_handler from functions.models_methods import ExpoManager import copy from django.utils.translation import ugettext as _ @@ -15,6 +15,11 @@ from functions.model_mixin import ExpoMixin CONFERENCE_TYPE = (('Convention centre', 'Конгресс-центр'), ('Exposition centre', 'Конференц зал'),) +def logo_name(instance, filename): + url = instance.url + return '/'.join(['place_conference', url, url+'_logo.jpg']) + + class PlaceConference(TranslatableModel, ExpoMixin): """ Create PlaceConference model @@ -22,28 +27,33 @@ class PlaceConference(TranslatableModel, ExpoMixin): Uses hvad.TranslatableModel which is child of django.db.models class """ - #set manager of this model + catalog = '/places/' + place = 'place_conference' + catalog_name = _(u'Места:') + search_name = None objects = ExpoManager() url = models.SlugField(unique=True) - country = models.ForeignKey('country.Country', on_delete=models.PROTECT) - city = models.ForeignKey('city.City', on_delete=models.PROTECT, related_name='place_conferences') + country = models.ForeignKey('country.Country', on_delete=models.PROTECT, verbose_name=_(u'Страна')) + city = models.ForeignKey('city.City', on_delete=models.PROTECT, + related_name='place_conferences', verbose_name=_(u'Город')) #type uses EnumField for creating Enum type field in Mysql database - type = EnumField(values = [item1 for item1, item2 in CONFERENCE_TYPE]) + type = EnumField(values = [item1 for item1, item2 in CONFERENCE_TYPE], default=CONFERENCE_TYPE[0][0], + verbose_name=_(u'Тип')) #information + address = LocationField(verbose_name=_(u'Адресс')) # - address= LocationField(verbose_name='Адресс') - # - phone = models.BigIntegerField(blank=True, null=True) - fax = models.BigIntegerField(blank=True, null=True) - web_page = models.URLField(blank=True) - email = models.EmailField(blank=True) - foundation_year = models.PositiveIntegerField(blank=True, null=True) - total_capacity = models.PositiveIntegerField(blank=True, null=True) - amount_halls = models.PositiveIntegerField(blank=True, null=True) - exposition_hall = models.NullBooleanField() - exp_hall_area = models.PositiveIntegerField(blank=True, null=True) + phone = models.BigIntegerField(blank=True, null=True, verbose_name=_(u'Телефон')) + fax = models.BigIntegerField(blank=True, null=True, verbose_name=_(u'Факс')) + web_page = models.URLField(blank=True, verbose_name=_(u'Веб сайт')) + email = models.EmailField(blank=True, verbose_name=_(u'Email')) + foundation_year = models.PositiveIntegerField(blank=True, null=True, verbose_name=_(u'Год основания')) + total_capacity = models.PositiveIntegerField(blank=True, null=True, verbose_name=_(u'Общая вместимость')) + amount_halls = models.PositiveIntegerField(blank=True, null=True, verbose_name=_(u'Количество залов')) + exposition_hall = models.NullBooleanField(verbose_name=_(u'Выставочный зал')) + exp_hall_area = models.PositiveIntegerField(blank=True, null=True, verbose_name=_(u'Площадь выст. зала')) video_link = models.CharField(max_length=255, blank=True) + virtual_tour = models.URLField(blank=True, verbose_name=_(u'Виртуальный тур')) # wifi = models.NullBooleanField() multimedia_equipment = models.NullBooleanField() @@ -53,6 +63,7 @@ class PlaceConference(TranslatableModel, ExpoMixin): catering = models.NullBooleanField() hotel = models.NullBooleanField() # + logo = models.ImageField(verbose_name='Logo', upload_to=logo_name, blank=True, max_length=255) files = generic.GenericRelation('file.FileModel',content_type_field='content_type', object_id_field='object_id') #translations is translated fields translations = TranslatedFields( @@ -162,5 +173,5 @@ class Hall(models.Model): number = models.PositiveIntegerField(blank=True, null=True) capacity = models.PositiveIntegerField(blank=True, null=True) - +pre_save.connect(pre_save_handler, sender=PlaceConference) post_save.connect(post_save_handler, sender=PlaceConference) \ No newline at end of file diff --git a/place_exposition/forms.py b/place_exposition/forms.py index ad71fde8..c9b6cd6e 100644 --- a/place_exposition/forms.py +++ b/place_exposition/forms.py @@ -112,7 +112,7 @@ class ExpositionForm(forms.Form): else: place_exposition = obj - #simple fields + if not getattr(place_exposition, 'url'): if data.get('name_en'): place_exposition.url = translit_with_separator(data['name_en'].strip()).lower() @@ -252,30 +252,6 @@ class PlaceExpositionFormDelete(forms.ModelForm): model = PlaceExposition fields = ('url',) -''' -class HallForm(forms.ModelForm): - """ - form for Hall model - uses ModelForm cause Hall doesnt have translated fields - """ - number = forms.CharField(widget=forms.TextInput(attrs={'style': 'width:30px'}),required=False) - capacity = forms.CharField(widget=forms.TextInput(attrs={'style': 'width:60px'}), required=False) - name = forms.CharField(required=False) - class Meta: - model = Hall - exclude = ('place_exposition',) - - def clean_number(self): - cleaned_data = super(HallForm, self).clean() - number = cleaned_data.get('number').strip() - return is_positive_integer(number, 'Номер должен состоять из цифр') - - def clean_capacity(self): - cleaned_data = super(HallForm, self).clean() - capacity = cleaned_data.get('capacity').strip() - return is_positive_integer(capacity, 'Вместимость должна состоять из цифр') - -''' class HallForm(forms.Form): url = '/admin/place_exposition/add-hall/' diff --git a/place_exposition/models.py b/place_exposition/models.py index 78b329d8..0db008e7 100644 --- a/place_exposition/models.py +++ b/place_exposition/models.py @@ -39,6 +39,7 @@ class PlaceExposition(TranslatableModel, ExpoMixin): """ catalog = '/places/' + place = 'place_exposition' catalog_name = _(u'Места:') search_name = None #set manager of this model @@ -289,17 +290,3 @@ def create_place(sender, instance, created, **kwargs): pre_save.connect(pre_save_handler, sender=PlaceExposition) post_save.connect(create_place, sender=PlaceExposition) post_save.connect(post_save_handler, sender=Hall) - - - - -""" -def calculate_rating_for_translations(sender, instance, created, **kwargs): - company = instance.master - post_save.disconnect(calculate_rating_for_translations, sender=Company._meta.translations_model) - calculate_rating(company) - post_save.connect(calculate_rating_for_translations, sender=Company._meta.translations_model) - -post_save.connect(create_company, sender=Company) -post_save.connect(calculate_rating_for_translations, sender=Company._meta.translations_model) -""" \ No newline at end of file diff --git a/place_exposition/views.py b/place_exposition/views.py index ba8f939a..16115ccd 100644 --- a/place_exposition/views.py +++ b/place_exposition/views.py @@ -80,7 +80,7 @@ class PlaceDetail(JitterCacheMixin, MetadataMixin, DetailView): obj = queryset.get() except queryset.model.DoesNotExist: try: - PlaceConference.objects.get(url=slug) + obj = PlaceConference.objects.get(url=slug) except PlaceConference.DoesNotExist: raise Http404(_("No %(verbose_name)s found matching the query") % diff --git a/templates/admin/includes/admin_nav.html b/templates/admin/includes/admin_nav.html index 8de663b0..88070a6f 100644 --- a/templates/admin/includes/admin_nav.html +++ b/templates/admin/includes/admin_nav.html @@ -66,11 +66,8 @@ Импорт

@@ -78,12 +75,11 @@ Экспорт diff --git a/templates/admin/place_conference/place_conference.html b/templates/admin/place_conference/place_conference.html new file mode 100644 index 00000000..70d37f4f --- /dev/null +++ b/templates/admin/place_conference/place_conference.html @@ -0,0 +1,340 @@ +{% extends 'base.html' %} +{% load static %} +{% block styles %} +.hover{ + display:none; + margin-bottom:10px; + +} +.photo:hover .hover { + display: block; +} +{% endblock %} + +{% block scripts %} + + + {# google map не забыть скачать скрипты на локал #} + + + + + {# selects #} + + + + + {# ajax #} + + + + +{% endblock %} + +{% block body %} + +
{% csrf_token %} +
+ {% if object %} Изменить {% else %} Добавить {% endif %}место{% if object %}(на сайте){% endif %} + +
+
+

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

+
+
+ + {# name #} + {% with field='name' form=form languages=languages %} + {% include 'admin/forms/multilang.html' %} + {% endwith %} + {# type #} +
+ +
{{ form.type}} + {{ form.type.errors }} +
+
+ {# main_title #} + {% with field='main_title' form=form languages=languages %} + {% include 'admin/forms/multilang.html' %} + {% endwith %} + {# country #} +
+ +
{{ form.country }} + {{ form.country.errors }} +
+
+ {# city #} +
+ +
{{ form.city }} + {{ form.city.errors }} +
+
+ + {# logo #} +
+ +
{{ form.logo }} + {{ form.logo.errors }} +
+
+ +
+
+ +
+
+

Дополнительная информация

+
+
+ {# description #} + {% with field='description' form=form languages=languages %} + {% include 'admin/forms/multilang.html' %} + {% endwith %} + {# adress #} + {% with field='adress' form=form languages=languages %} + {% include 'admin/forms/multilang.html' %} + {% endwith %} + {# address #} +
+ +
{{ form.address }} + {{ form.address.errors }} +
+
+ + {# phone #} +
+ +
{{ form.phone}} + {{ form.phone.errors }} +
+
+ {# fax #} +
+ +
{{ form.fax}} + {{ form.fax.errors }} +
+
+ {# web_page #} +
+ +
{{ form.web_page}} + {{ form.web_page.errors }} +
+
+ {# email #} +
+ +
{{ form.email}} + {{ form.email.errors }} +
+
+ + + +
+
+
+
+

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

+
+
+ {# foundation_year #} +
+ +
{{ form.foundation_year}} + {{ form.foundation_year.errors }} +
+
+ {# total_year_action #} + {% with field='total_year_action' form=form languages=languages %} + {% include 'admin/forms/multilang.html' %} + {% endwith %} + + {# total_capacity #} +
+ +
{{ form.total_capacity}} + {{ form.total_capacity.errors }} +
+
+ + {# amount_halls #} +
+ +
{{ form.amount_halls}} + {{ form.amount_halls.errors }} +
+
+ + {# video_link #} +
+ +
{{ form.video_link}} + {{ form.video_link.errors }} +
+
+ {# exp_hall_area #} +
+ +
{{ form.exp_hall_area}} + {{ form.exp_hall_area.errors }} +
+
+ + +
+
+ + + +
+
+

Услуги

+
+
+
+ {# exposition_hall #} +
+ +
{{ form.exposition_hall}} + {{ form.exposition_hall.errors }} +
+
+ {# wifi #} +
+ +
{{ form.wifi}} + {{ form.wifi.errors }} +
+
+ {# catering #} +
+ +
{{ form.catering}} + {{ form.catering.errors }} +
+
+ {# hotel #} +
+ +
{{ form.hotel}} + {{ form.hotel.errors }} +
+
+ {# banquet_hall #} +
+ +
{{ form.banquet_hall}} + {{ form.banquet_hall.errors }} +
+
+ +
+
+ {# multimedia_equipment #} +
+ +
{{ form.multimedia_equipment}} + {{ form.multimedia_equipment.errors }} +
+
+ + {# translate_equipment #} +
+ +
{{ form.translate_equipment}} + {{ form.translate_equipment.errors }} +
+
+ {# conference_call #} +
+ +
{{ form.conference_call}} + {{ form.conference_call.errors }} +
+
+ +
+ +
+
+ +
+
+

Файлы

+
+
+ {% if object %} + {# button that shows modal window with file form #} + Добавить файл + {% else %} +

Файлы можно добавлять только после введения основных данных

+ {% endif %} + {# this div shows list of files and refreshes when new file added #} +
+ + + + + + + + + + + + + {% include 'file_list.html' with files=files %} + +
idФайлИмяНазначение
+
+ +
+
+ + {% include 'admin/includes/photogallery.html' with object=object %} + +
+
+

Мета данные

+
+
+ + {# keywords #} + {% with field='keywords' form=form languages=languages %} + {% include 'admin/forms/multilang.html' %} + {% endwith %} + {# title #} + {% with field='title' form=form languages=languages %} + {% include 'admin/forms/multilang.html' %} + {% endwith %} + {# descriptions #} + {% with field='descriptions' form=form languages=languages %} + {% include 'admin/forms/multilang.html' %} + {% endwith %} + +
+
+ + +
+ + +
+ +
+
+ + + + +{% include 'admin/includes/hall_form.html' with form=hall_form object=object %} +{% include 'admin/includes/photo_form.html' with form=photo_form object=object %} +{% include 'admin/includes/file_form.html' with file_form=file_form object=object %} + +{% endblock %} \ No newline at end of file diff --git a/templates/admin/place_conference/place_conference_list.html b/templates/admin/place_conference/place_conference_list.html index cd9c6233..b3f656ac 100644 --- a/templates/admin/place_conference/place_conference_list.html +++ b/templates/admin/place_conference/place_conference_list.html @@ -38,7 +38,7 @@ {% ifnotequal item.country None %}{{ item.country }} {% endifnotequal %} {% ifnotequal item.city None %}{{ item.city }} {% endifnotequal %} - + Изменить diff --git a/templates/client/includes/place/place_info.html b/templates/client/includes/place/place_info.html new file mode 100644 index 00000000..dc129a3d --- /dev/null +++ b/templates/client/includes/place/place_info.html @@ -0,0 +1,86 @@ +{% load i18n %} +{% load template_filters %} + +
+ + {% if place.place == 'place_exposition' %} + {% if place.total_area %} +
+
{% trans 'Общая выставочная площадь' %}
+
{{ place.total_area|int_format }} м²
+
+ {% endif %} + {% else %} + {% comment %} + {% if place.total_capacity %} +
+
{% trans 'Общая вместимость' %}
+
{{ place.total_capacity|int_format }}
+
+ {% endif %} + {% endcomment %} + {% endif %} + +
+ {% if place.closed_area %} +
+ {{ place.closed_area|int_format }} {% trans 'м²' %} + {% trans 'закрытая выставочная площадь' %} +
+ {% endif %} + {% if place.open_area %} +
+ {{ place.open_area|int_format }} {% trans 'м²' %} + {% trans 'открытая выставочная площадь' %} +
+ {% endif %} +
+
+
+
    + {% for hall in place.halls.all %} + {% if not forloop.counter|divisibleby:"2" %} +
  • {{ hall.name }} {% if hall.number %} №{{ hall.number }} {% endif %} — {{ hall.capacity }} м2
  • + {% endif %} + {% endfor %} +
+
+
+
    + {% for hall in place.halls.all %} + {% if forloop.counter|divisibleby:"2" %} +
  • {{ hall.name }} {% if hall.number %} №{{ hall.number }} {% endif %} — {{ hall.capacity }} м2
  • + {% endif %} + {% endfor %} +
+
+
+ + {% if place.total_year_action %} +
+
+ {% trans 'Ежегодно проводится' %} +
+
+ {% if place.total_year_action.isdigit %} + {% ifequal LANGUAGE_CODE 'ru' %} + {% load pymorphy_tags %} + {{ place.total_year_action }} + {{ "событие"|plural:place.total_year_action }} + {% else %} + {{ place.total_year_action }} + {% trans 'событий' %} + {% endifequal %} + + {% else %} + {{ place.total_year_action }} + {% endif %} +
+
+ {% endif %} + {% if place.foundation_year %} +
+
{% trans 'Основано в' %} {{ place.foundation_year }} {% trans 'году' %}
+
+ {% endif %} +
\ No newline at end of file diff --git a/templates/client/includes/place/place_object.html b/templates/client/includes/place/place_object.html index 4be3f158..10bb632a 100644 --- a/templates/client/includes/place/place_object.html +++ b/templates/client/includes/place/place_object.html @@ -27,10 +27,10 @@
{{ place.adress }}
- + @@ -41,53 +41,7 @@
-
-
Услуги
-
-
    - {% if place.bank %} -
  • {% trans 'Банк / банкоматы / обмен валюты' %}
  • - {% endif %} - {% if place.wifi %} -
  • Wi-Fi
  • - {% endif %} - {% if place.children_room %} -
  • {% trans 'Детская комната' %}
  • - {% endif %} - {% if place.disabled_service %} -
  • {% trans 'Сервис для инвалидов' %}
  • - {% endif %} -
-
    - {% if place.conference_centre %} -
  • {% trans 'Конгресс-центр' %}
  • - {% endif %} - {% if place.business_centre %} -
  • {% trans 'Бизнес-центр' %}
  • - {% endif %} - {% if place.online_registration %} -
  • {% trans 'Онлайн-регистрация' %}
  • - {% endif %} - {% if place.cafe %} -
  • {% trans 'Кафе и рестораны' %}
  • - {% endif %} -
-
    - {% if place.terminals %} -
  • {% trans 'Информационные терминалы' %}
  • - {% endif %} - {% if place.parking %} -
  • {% trans 'Парковка' %}
  • - {% endif %} - {% if place.press_centre %} -
  • {% trans 'Пресс-центр' %}
  • - {% endif %} - {% if place.mobile_application %} -
  • {% trans 'Мобильное приложение' %}
  • - {% endif %} -
-
-
+ {% include 'client/includes/place/place_services.html' with place=place %}
{% if place.photogallery %} {% with photos=place.photogallery.photos.all|slice:"5" %} @@ -109,228 +63,162 @@ {% endwith %} {% endif %} -
- {% if place.total_area %} -
-
{% trans 'Общая выставочная площадь' %}
-
{{ place.total_area|int_format }} м²
-
- {% endif %} -
- {% if place.closed_area %} -
- {{ place.closed_area|int_format }} {% trans 'м²' %} - {% trans 'закрытая выставочная площадь' %} -
- {% endif %} - {% if place.open_area %} -
- {{ place.open_area|int_format }} {% trans 'м²' %} - {% trans 'открытая выставочная площадь' %} -
- {% endif %} -
-
-
-
    - {% for hall in place.halls.all %} - {% if not forloop.counter|divisibleby:"2" %} -
  • {{ hall.name }} {% if hall.number %} №{{ hall.number }} {% endif %} — {{ hall.capacity }} м2
  • - {% endif %} - {% endfor %} -
-
-
-
    - {% for hall in place.halls.all %} - {% if forloop.counter|divisibleby:"2" %} -
  • {{ hall.name }} {% if hall.number %} №{{ hall.number }} {% endif %} — {{ hall.capacity }} м2
  • - {% endif %} - {% endfor %} -
-
-
-
- {% if place.total_year_action %} -
-
- {% trans 'Ежегодно проводится' %} -
-
- {% if place.total_year_action.isdigit %} - {% ifequal LANGUAGE_CODE 'ru' %} - {% load pymorphy_tags %} - {{ place.total_year_action }} - {{ "событие"|plural:place.total_year_action }} - {% else %} - {{ place.total_year_action }} - {% trans 'событий' %} - {% endifequal %} + {% include 'client/includes/place/place_info.html' with place=place %} + + {% if place.get_scheme %} +
+
+
{% trans 'Схема павильонов' %}
+ {% for scheme in place.get_scheme %} + {% ifequal scheme.file_path.url|slice:"-3:" 'pdf' %} + {% trans 'Схема в pdf' %} {% else %} - {{ place.total_year_action }} - {% endif %} -
+
+ {% endifequal %} +
+ {% endfor %}
{% endif %} - {% if place.foundation_year %} -
-
{% trans 'Основано в' %} {{ place.foundation_year }} {% trans 'году' %}
-
- {% endif %} -
- {% if place.get_scheme %} -
-
-
{% trans 'Схема павильонов' %}
- {% for scheme in place.get_scheme %} - {% ifequal scheme.file_path.url|slice:"-3:" 'pdf' %} - {% trans 'Схема в pdf' %} - {% else %} -
- {% endifequal %} -
- {% endfor %} -
- {% endif %} -
-
{% trans 'Контактная информация' %}
-
-
-
{{ place.adress }}
- - {% if place.events %} -
-
{% trans 'Список событий' %}
- -
- {% endif %} -
- {% include 'client/includes/booking_block.html' with city=place.city place=place %} -
-
-
- {% include 'client/includes/banners/detail_inner.html' %} -
- {% if place.get_nearest_places %} -
-
{% trans 'Ближайшие выставочные центры' %}
- +
+ {% endif %} +
+ {% include 'client/includes/booking_block.html' with city=place.city place=place %} +
+
+
+ {% include 'client/includes/banners/detail_inner.html' %} +
+ {% if place.get_nearest_places %} +
+
{% trans 'Ближайшие выставочные центры' %}
+ -
- {% endif %} - {% include 'client/includes/banners/detail_inner_3.html' %} +
+
+ {% if pl.total_area %} +
{{ pl.total_area }}
+ {% endif %} + +
+
+
+ + {% endfor %} + + + {% endif %} + {% include 'client/includes/banners/detail_inner_3.html' %} + {% endblock %} {% block scripts %} diff --git a/templates/client/includes/place/place_services.html b/templates/client/includes/place/place_services.html new file mode 100644 index 00000000..e4839e1d --- /dev/null +++ b/templates/client/includes/place/place_services.html @@ -0,0 +1,80 @@ +{% load i18n %} + +
+
{% trans 'Услуги' %}
+
+ {% if place.place == 'place_exposition' %} +
    + {% if place.bank %} +
  • {% trans 'Банк / банкоматы / обмен валюты' %}
  • + {% endif %} + {% if place.wifi %} +
  • Wi-Fi
  • + {% endif %} + {% if place.children_room %} +
  • {% trans 'Детская комната' %}
  • + {% endif %} + {% if place.disabled_service %} +
  • {% trans 'Сервис для инвалидов' %}
  • + {% endif %} +
+
    + {% if place.conference_centre %} +
  • {% trans 'Конгресс-центр' %}
  • + {% endif %} + {% if place.business_centre %} +
  • {% trans 'Бизнес-центр' %}
  • + {% endif %} + {% if place.online_registration %} +
  • {% trans 'Онлайн-регистрация' %}
  • + {% endif %} + {% if place.cafe %} +
  • {% trans 'Кафе и рестораны' %}
  • + {% endif %} +
+
    + {% if place.terminals %} +
  • {% trans 'Информационные терминалы' %}
  • + {% endif %} + {% if place.parking %} +
  • {% trans 'Парковка' %}
  • + {% endif %} + {% if place.press_centre %} +
  • {% trans 'Пресс-центр' %}
  • + {% endif %} + {% if place.mobile_application %} +
  • {% trans 'Мобильное приложение' %}
  • + {% endif %} +
+ {% else %} +
    + {% if place.exposition_hall %} +
  • {% trans 'Выставочный зал' %}
  • + {% endif %} + {% if place.wifi %} +
  • Wi-Fi
  • + {% endif %} + {% if place.multimedia_equipment %} +
  • {% trans 'Мультимедийное оборудование' %}
  • + {% endif %} + {% if place.conference_call %} +
  • {% trans 'Конференц-связь' %}
  • + {% endif %} +
+
    + {% if place.translate_equipment %} +
  • {% trans 'Оборудование для синхронного перевода' %}
  • + {% endif %} + {% if place.banquet_hall %} +
  • {% trans 'Банкетный зал' %}
  • + {% endif %} + {% if place.catering %} +
  • {% trans 'Кейтеринг' %}
  • + {% endif %} + {% if place.hotel %} +
  • {% trans 'Гостиница' %}
  • + {% endif %} +
+ {% endif %} +
+
\ No newline at end of file From 00d4420bc8e1d13220f0977be941be4c1440357a Mon Sep 17 00:00:00 2001 From: Nazar Kotjuk Date: Fri, 23 Oct 2015 13:41:32 +0300 Subject: [PATCH 09/18] refactor accounts --- accounts/edit_forms.py | 32 +- accounts/forms.py | 74 +-- accounts/management/__init__.py | 1 - accounts/management/commands/__init__.py | 1 - accounts/management/commands/load_accounts.py | 82 --- accounts/models.py | 127 ++--- accounts/search_indexes.py | 21 - accounts/urls.py | 22 +- accounts/user_catalog_urls.py | 7 +- accounts/views.py | 117 +---- company/management/__init__.py | 1 - company/management/commands/__init__.py | 1 - .../commands/company_from_old_db.py | 97 ---- company/management/commands/company_test.py | 77 --- functions/views_help.py | 20 +- import_xls/excel_settings.py | 2 +- registration/backends/default/views.py | 26 +- templates/client/accounts/feed.html | 11 +- templates/client/accounts/fill_company.html | 481 ------------------ templates/client/accounts/messages.html | 2 +- templates/client/accounts/new_profile.html | 436 ---------------- templates/client/accounts/profile.html | 366 ------------- 22 files changed, 122 insertions(+), 1882 deletions(-) delete mode 100644 accounts/management/__init__.py delete mode 100644 accounts/management/commands/__init__.py delete mode 100644 accounts/management/commands/load_accounts.py delete mode 100644 accounts/search_indexes.py delete mode 100644 company/management/__init__.py delete mode 100644 company/management/commands/__init__.py delete mode 100644 company/management/commands/company_from_old_db.py delete mode 100644 company/management/commands/company_test.py delete mode 100644 templates/client/accounts/fill_company.html delete mode 100644 templates/client/accounts/new_profile.html delete mode 100644 templates/client/accounts/profile.html diff --git a/accounts/edit_forms.py b/accounts/edit_forms.py index 14f2860e..cb687a90 100644 --- a/accounts/edit_forms.py +++ b/accounts/edit_forms.py @@ -1,4 +1,5 @@ # -*- coding: utf-8 -*- +# forms for editing user data from django import forms from django.utils.translation import ugettext as _ from models import User, Profile @@ -6,13 +7,16 @@ from country.models import Country from city.models import City from company.models import Company + class AvatarForm(forms.ModelForm): avatar = forms.ImageField(label=_(u'Выберите файл (GIF, JPG, PNG. Размер 100 × 100 пикселей)'), required=False, widget=forms.FileInput(attrs={'class': 'input'})) + class Meta: model = Profile fields = ('avatar',) + class NameForm(forms.ModelForm): first_name = forms.CharField(label=_(u'Введите ваше имя')) last_name = forms.CharField(label=_(u'Введите вашу фамилию')) @@ -22,17 +26,19 @@ class NameForm(forms.ModelForm): fields = ('first_name', 'last_name') def get_full_name(self): - return u'%s %s'%(self.instance.first_name, self.instance.last_name,) + return u'%s %s' % (self.instance.first_name, self.instance.last_name,) class HomeForm(forms.ModelForm): city = forms.CharField(label='Город', required=False, widget=forms.HiddenInput(attrs={'class': 'select2'})) - country = forms.ChoiceField(label=_(u'Страна'), choices=[(c.id, c.name) for c in Country.objects.all()], required=False, - widget=forms.Select(attrs={'class': 'select2'})) + country = forms.ChoiceField(label=_(u'Страна'), choices=[(c.id, c.name) for c in Country.objects.all()], + required=False, widget=forms.Select(attrs={'class': 'select2'})) + def __init__(self, *args, **kwargs): super(HomeForm, self).__init__(*args, **kwargs) if self.instance.city: + # city uses ajax select2 widget self.fields['city'].widget = forms.HiddenInput(attrs={'class': 'select2', 'data-init-text': self.instance.city.name}) class Meta: @@ -48,7 +54,6 @@ class HomeForm(forms.ModelForm): except City.DoesNotExist: return None - def clean_country(self): try: return Country.objects.get(id=self.cleaned_data['country']) @@ -56,19 +61,18 @@ class HomeForm(forms.ModelForm): return None - class WorkForm(forms.ModelForm): position = forms.CharField(label=_(u'Укажите вашу должность'), required=False, widget=forms.TextInput()) company = forms.CharField(label=_(u'Укажите вашу компанию'), required=False, - widget=forms.HiddenInput(attrs={'class': 'select2'})) + widget=forms.HiddenInput(attrs={'class': 'select2'})) def __init__(self, *args, **kwargs): super(WorkForm, self).__init__(*args, **kwargs) if self.instance.company: + # for ajax select2 widget self.fields['company'].widget = forms.HiddenInput(attrs={'class': 'select2', 'data-init-text': self.instance.company.name}) - class Meta: model = User fields = ('position', 'company') @@ -84,7 +88,8 @@ class WorkForm(forms.ModelForm): class AboutCompanyForm(forms.ModelForm): about_company = forms.CharField(label=_(u'Описание компании'), required=False, - widget=forms.Textarea(attrs={'cols':'30'})) + widget=forms.Textarea(attrs={'cols': '30'})) + class Meta: model = Profile fields = ('about_company',) @@ -99,11 +104,11 @@ class PhoneForm(forms.ModelForm): fields = ('phone', 'show_phone') def clean_phone(self): - phone = self.cleaned_data['phone'] - if not phone: + phone = self.cleaned_data['phone'] + if not phone: return - deduct = ('-','(',')','.',' ', '+') + deduct = ('-', '(', ')', '.', ' ', '+') for elem in deduct: phone = phone.replace(elem, '') if phone.isdigit(): @@ -112,7 +117,6 @@ class PhoneForm(forms.ModelForm): raise forms.ValidationError(_(u'Введите правильный телефон')) - class EmailForm(forms.ModelForm): email = forms.EmailField(label=_(u'Ваш e-mail'), required=False) @@ -120,6 +124,7 @@ class EmailForm(forms.ModelForm): model = User fields = ('email',) + class WebPageForm(forms.ModelForm): web_page = forms.URLField(label=_(u'Адрес вашего сайта'), required=False) @@ -127,17 +132,18 @@ class WebPageForm(forms.ModelForm): model = User fields = ('web_page',) + class SocialForm(forms.ModelForm): facebook = forms.CharField(label=_(u'Facebook'), required=False) twitter = forms.CharField(label=_(u'Twitter'), required=False) vk = forms.CharField(label=_(u'В контакте'), required=False) linkedin = forms.CharField(label=_(u'LinkedIn'), required=False) - class Meta: model = Profile fields = ('facebook', 'twitter', 'vk', 'linkedin') + class AboutForm(forms.ModelForm): about = forms.CharField(label=_(u'Немного о себе'), required=False, widget=forms.Textarea(attrs={'cols':'30'})) diff --git a/accounts/forms.py b/accounts/forms.py index 2e9bc922..8ab13b3e 100644 --- a/accounts/forms.py +++ b/accounts/forms.py @@ -6,16 +6,14 @@ from django.contrib.auth.forms import ReadOnlyPasswordHashField from django.forms.util import ErrorList from django.utils.translation import ugettext as _ from django.conf import settings -from models import User, Profile +from models import User +from django.db.models import Q from theme.models import Theme, Tag from country.models import Area -from django.utils import translation from country.models import Country from city.models import City from company.models import Company -from organiser.models import Organiser -# functions -from functions.form_check import translit_with_separator, is_latin +from functions.form_check import is_latin def clean_relation_field(inst, field_name, model): @@ -137,17 +135,6 @@ class UserForm(forms.ModelForm): profile.save() return user - #def clean_url(self): - # url = self.cleaned_data.get('url') - # if url: - # if User.objects.get(url=translit_with_separator(url)): - # raise forms.ValidationError('Такой урл уже занят') - # else: - # return url - - #def clean_organiser(self): - # return clean_relation_field(self, 'organiser', Organiser) - def clean_company(self): return clean_relation_field(self, 'company', Company) @@ -174,21 +161,6 @@ class UserForm(forms.ModelForm): else: raise forms.ValidationError('Введите правильный код страны') - """ - def clean_web_page(self): - cleaned_data = super(UserForm, self).clean() - web_page = cleaned_data.get('web_page') - if not web_page: - return web_page - - import socket - try: - socket.getaddrinfo(web_page, 80) - return web_page - except: - return forms.ValidationError('Введите правильный адрес страници') - """ - class ChangePasswordForm(forms.Form): """ @@ -319,24 +291,6 @@ class SocialRegistrationCompleteForm(RegistrationCompleteForm): return user -class RecoveryForm(forms.Form): - email = forms.EmailField(widget=forms.TextInput(attrs={'placeholder': _(u'Email')})) - - def get_user(self): - email = self.cleaned_data['email'] - return User.objects.get(email=email) - - def clean_email(self): - email = self.cleaned_data['email'] - try: - return User.objects.get(email=email) - except User.DoesNotExist: - raise forms.ValidationError(_(u'Пользователь с таким емейлом не зарегестрирован')) - - -from django.db.models import Q - - class UserFilterForm(forms.Form): model = User search_req = forms.CharField(label=_(u'Введите e-mail, имя или фамилию для запроса'), required=False) @@ -450,21 +404,21 @@ class FeedFilterForm(forms.Form): area = self.cleaned_data['area'] country = self.cleaned_data['co'] city = self.cleaned_data['ci'] - filter = self.filter + filter_obj = self.filter - filter.theme.clear() - filter.theme.add(*Theme.objects.filter(id__in=theme)) + filter_obj.theme.clear() + filter_obj.theme.add(*Theme.objects.filter(id__in=theme)) - filter.tag.clear() - filter.tag.add(*Tag.objects.filter(id__in=tag)) + filter_obj.tag.clear() + filter_obj.tag.add(*Tag.objects.filter(id__in=tag)) - filter.area.clear() - filter.area.add(*Area.objects.filter(id__in=area)) - filter.country.clear() - filter.country.add(*Country.objects.filter(id__in=country)) + filter_obj.area.clear() + filter_obj.area.add(*Area.objects.filter(id__in=area)) + filter_obj.country.clear() + filter_obj.country.add(*Country.objects.filter(id__in=country)) - filter.city.clear() - filter.city.add(*City.objects.filter(id__in=city)) + filter_obj.city.clear() + filter_obj.city.add(*City.objects.filter(id__in=city)) def clean_tg(self): diff --git a/accounts/management/__init__.py b/accounts/management/__init__.py deleted file mode 100644 index 3ed9fd0f..00000000 --- a/accounts/management/__init__.py +++ /dev/null @@ -1 +0,0 @@ -__author__ = 'root' diff --git a/accounts/management/commands/__init__.py b/accounts/management/commands/__init__.py deleted file mode 100644 index 3ed9fd0f..00000000 --- a/accounts/management/commands/__init__.py +++ /dev/null @@ -1 +0,0 @@ -__author__ = 'root' diff --git a/accounts/management/commands/load_accounts.py b/accounts/management/commands/load_accounts.py deleted file mode 100644 index 6d2147fb..00000000 --- a/accounts/management/commands/load_accounts.py +++ /dev/null @@ -1,82 +0,0 @@ -import os -import MySQLdb -from MySQLdb.cursors import DictCursor -from django.core.management.base import BaseCommand -from accounts.models import User - -def create_new_user(data): - email = data['email'] - firstname = data['firstname'] - lastname = data['lastname'] - position = data['position'] - web_page = data['web_page'] - fb = data['fb'] - li = data['li'] - sk = data['sk'] - about = data['about'] - password = data['password'] - url = data['url'] - if not url: - url = str(data['id']) - - user = User(username=email, first_name=firstname, last_name=lastname, email=email, - is_staff=False, is_active=True, is_superuser=False, password=password, position=position, url=url) - - try: - user.save() - except: - return - profile = user.profile - - profile.web_page = web_page - profile.facebook = fb - profile.linkedin = li - profile.skype = sk - profile.about = about - try: - profile.save() - except: - pass - - return - - -class Command(BaseCommand): - def handle(self, *args, **options): - db = MySQLdb.connect(host="localhost", - user="expomap", - passwd="7FbLtAGjse", - db="old_db", - charset='utf8', - cursorclass=DictCursor) - cursor = db.cursor() - sql = """ - SELECT customers_id as id, customers_email_address as email, customers_password as password, customers_firstname as firstname , - customers_lastname as lastname , customers_telephone as phone, customers_job as `position`, customers_web as web_page, - customers_facebook as fb, customers_linkedin as li, customers_skype as sk, customers_about as about, - url - FROM `customers` - where customers_email_address!='' - - """ - - - - - cursor.execute(sql) - result = cursor.fetchall() - - #user.password = result[0]['customers_password'] - - for res in result: - email = res['email'] - print(email) - try: - user = User.objects.get(username=email) - except User.DoesNotExist: - user = None - create_new_user(res) - if user: - password = res['password'] - user.password = password - user.save() diff --git a/accounts/models.py b/accounts/models.py index 2c83a17b..9db37057 100644 --- a/accounts/models.py +++ b/accounts/models.py @@ -1,7 +1,5 @@ # -*- coding: utf-8 -*- -import random, string from django.db import models -from django.core.validators import email_re from django.db.models import Q from django.contrib.auth.models import BaseUserManager, AbstractBaseUser, PermissionsMixin from django.core.mail import send_mail @@ -9,19 +7,9 @@ from django.utils import timezone from django.utils.translation import ugettext as _ from django.db.models.signals import post_save from django.db.models.loading import get_model -#custom functions from functions.form_check import translit_with_separator - -""" -from django.contrib.auth.hashers import check_password -from hashlib import md5 -from django.contrib.auth import get_user_model - -from django.db.models import get_model -""" - class UserManager(BaseUserManager): """ Creates and saves a User with the given email, first_name, last_name and password. @@ -31,10 +19,10 @@ class UserManager(BaseUserManager): if not email: raise ValueError('Вы должни ввести электронную почту') - user= self.model( - email = UserManager.normalize_email(email), - first_name = first_name,last_name = last_name, - username = UserManager.normalize_email(email), + user = self.model( + email=UserManager.normalize_email(email), + first_name=first_name,last_name = last_name, + username=UserManager.normalize_email(email), is_staff=False, is_active=False, is_superuser=False, last_login=now, date_joined=now, **extra_fields ) @@ -43,29 +31,6 @@ class UserManager(BaseUserManager): user.save(using=self._db) return user - def create_social_user(self, username, first_name, last_name, password=None, **extra_fields): - now = timezone.now() - # generate random password - digits = random.sample(('0', '1', '2', '3', '4', '5', '6', '7', '8', '9'), 4) - chars = random.sample(string.lowercase[:], 4) - password = chars + digits - random.shuffle(password) - password = ''.join(password) - - - user= self.model(first_name=first_name, last_name=last_name, username=username, - is_staff=False, is_active=True, is_superuser=False, - last_login=now, date_joined=now, **extra_fields) - - check = True if email_re.match(username) else False - if check: - user.email = UserManager.normalize_email(username) - - user.set_password(password) - user.save(using=self._db) - return user - - def create_superuser(self, username, first_name, last_name, password, **extra_fields): if not username: raise ValueError('Вы должни ввести электронную почту') @@ -73,9 +38,9 @@ class UserManager(BaseUserManager): username = UserManager.normalize_email(username) user = self.create_user( - email = username, - first_name = first_name,last_name = last_name, - password = password, **extra_fields + email=username, + first_name=first_name, last_name=last_name, + password=password, **extra_fields ) user.is_staff = True @@ -85,7 +50,6 @@ class UserManager(BaseUserManager): user.save(using=self._db) return user - def safe_get(self, **kwargs): model = self.model try: @@ -108,23 +72,21 @@ class User(AbstractBaseUser, PermissionsMixin): catalog = '/user/' email = models.EmailField( - verbose_name = u'Email', - max_length = 255, + verbose_name=u'Email', + max_length=255, #unique = True, - db_index = True, + db_index=True, ) username = models.CharField(verbose_name='Email', max_length=255, unique=True, db_index=True) first_name = models.CharField(verbose_name='First name', max_length=255) last_name = models.CharField(verbose_name='Last name', max_length=255) rating = models.IntegerField(default=100)# добавить индекс в базе - url = models.SlugField(blank=True)#, unique=True, null=True) - # - is_active = models.BooleanField(default=0) # СДЕЛАТЬ проверку на емейле + url = models.SlugField(blank=True) + is_active = models.BooleanField(default=0) is_staff = models.BooleanField(default=0) is_admin = models.BooleanField(default=0) - date_joined = models.DateTimeField(auto_now_add=True) - date_registered = models.DateTimeField(blank=True, null=True)# + date_registered = models.DateTimeField(blank=True, null=True) date_modified = models.DateTimeField(auto_now=True) #relations organiser = models.ForeignKey('organiser.Organiser', verbose_name='Организатор', blank=True, null=True, @@ -142,10 +104,7 @@ class User(AbstractBaseUser, PermissionsMixin): REQUIRED_FIELDS = ['first_name', 'last_name'] class Meta: - ordering=['-rating'] - - def is_organiser(self): - return bool(self.organiser) + ordering = ['-rating'] def get_full_name(self): """ @@ -154,16 +113,13 @@ class User(AbstractBaseUser, PermissionsMixin): return u'%s %s'%(self.first_name, self.last_name) def set_url(self, st): - """ - - """ self.url = translit_with_separator(u'%s'%st) def __unicode__(self): return self.email def get_short_name(self): - "Returns the short name for the user." + """Returns the short name for the user.""" return self.first_name def email_user(self, subject, message, from_email=None): @@ -172,7 +128,6 @@ class User(AbstractBaseUser, PermissionsMixin): """ send_mail(subject, message, from_email, [self.email]) - def has_perm(self, perm, obj=None): return True @@ -201,62 +156,37 @@ class User(AbstractBaseUser, PermissionsMixin): return n def get_permanent_url(self): - - if self.url: - return '/%s/'%self.url - #return self.catalog+self.url+'/' - return '/%d/'%self.id - #return self.catalog+str(self.id)+'/' - - def get_translator_url(self): if self.url: - return '/translators/%s/'%self.url - return '/translators/%d/'%self.id + return '/%s/' % self.url + return '/%d/' % self.id def get_expos(self): """ - return information about expos and them related data by 1 query + return information about expos and them related data by 1 query(reverse connection) """ return self.exposition_users.language().select_related('country', 'city', 'place').all() def get_confs(self): """ - return information about confs and them related data by 1 query + return information about confs and them related data by 1 query(reverse connection) """ return self.conference_users.language().select_related('country', 'city', 'place').all() - def get_seminars(self): - """ - return information about seminars and them related data by 1 query - - """ - return self.seminar_users.language().select_related('country', 'city').all() - def remove_from_calendar(self, data): expo = data['expo'] conf = data['conf'] - seminar = data['seminar'] - webinar = data['webinar'] calendar = self.calendar if expo: calendar.expositions.remove(*expo) if conf: calendar.conferences.remove(*conf) - if seminar: - calendar.seminars.remove(*seminar) - if webinar: - calendar.webinars.remove(*webinar) - - - class Profile(models.Model): """ stores additional information about users - """ user = models.OneToOneField(User) country = models.ForeignKey('country.Country', verbose_name='Страна', blank=True, null=True, @@ -264,7 +194,6 @@ class Profile(models.Model): city = models.ForeignKey('city.City', verbose_name='Город', blank=True, null=True, on_delete=models.PROTECT) about_company = models.TextField(verbose_name=_(u'Описание компании'), blank=True) - phone = models.BigIntegerField(verbose_name=_(u'Телефон'), blank=True, null=True) show_phone = models.NullBooleanField(verbose_name=_(u'Показывать телефон'), blank=True, null=True, default=1) web_page = models.URLField(verbose_name='Вебсайт',blank=True) @@ -275,7 +204,6 @@ class Profile(models.Model): twitter = models.URLField(verbose_name=_(u'Twitter'), blank=True,max_length=255) linkedin = models.URLField(verbose_name=_(u'LinkedIn'), blank=True, max_length=255) vk = models.URLField(verbose_name=_(u'В контакте'), blank=True, max_length=255) - # meta title = models.CharField(max_length=255, blank=True) descriptions = models.CharField(max_length=255, blank=True) @@ -354,6 +282,9 @@ class EventFilter(models.Model): to = models.DateField(blank=True, null=True) def get_queryset(self): + """ + get filtered queryset + """ Exposition = get_model('exposition', 'Exposition') qs = Exposition.enable.upcoming() themes = self.theme.all() @@ -380,9 +311,11 @@ class EventFilter(models.Model): return qs.order_by('data_begin') - - def calculate_rating(user): + """ + calculates user rating depending og user filled information + calls in post save signal of profile model + """ user_rating_fields = {'position': 5, 'company': 5, 'url': 10} profile_rating_fields = {'country': 5, 'city': 5, 'phone': 10, 'facebook': 5, 'twitter': 5, 'linkedin': 5, 'vk': 5, 'web_page': 10, 'avatar': 20, 'about': 15} @@ -396,7 +329,6 @@ def calculate_rating(user): if getattr(user, key): rating += value - for key, value in profile_rating_fields.iteritems(): if getattr(user.profile, key): rating += value @@ -409,6 +341,9 @@ def calculate_rating(user): def create_user_inf(sender, instance, created, **kwargs): + """ + create default models that is required for users + """ if created: Calendar.objects.create(user=instance) Profile.objects.create(user=instance) @@ -416,10 +351,10 @@ def create_user_inf(sender, instance, created, **kwargs): calculate_rating(instance) + def post_profile(sender, instance, created, **kwargs): user = instance.user calculate_rating(user) post_save.connect(create_user_inf, sender=User) -post_save.connect(post_profile, sender=Profile) - +post_save.connect(post_profile, sender=Profile) \ No newline at end of file diff --git a/accounts/search_indexes.py b/accounts/search_indexes.py deleted file mode 100644 index 0b9b391d..00000000 --- a/accounts/search_indexes.py +++ /dev/null @@ -1,21 +0,0 @@ -from haystack import indexes -from models import User - -""" -class UserIndex(indexes.SearchIndex, indexes.Indexable): - text = indexes.CharField(document=True, use_template=True) -# first_name = indexes.CharField(model_attr='first_name') -# last_name = indexes.CharField(model_attr='last_name') - email = indexes.NgramField(model_attr='email') - #email = indexes.CharField(model_attr='email') - - - - def get_model(self): - return User - - - def index_queryset(self, using=None): - - return self.get_model().objects.filter(is_active=True) -""" \ No newline at end of file diff --git a/accounts/urls.py b/accounts/urls.py index 2345511f..ff555df6 100644 --- a/accounts/urls.py +++ b/accounts/urls.py @@ -1,18 +1,12 @@ # -*- coding: utf-8 -*- from django.conf.urls import patterns, url from django.contrib.auth.decorators import login_required -from views import SettingsView, ProfileView, CalendarView, UserView, UserExpositionsView, UserConferenceView, UserSeminarView +from views import SettingsView, CalendarView from views import NameView, HomeView, AvatarView, WorkView, AboutCompanyView, PhoneView, WebPageView,\ SocialView, AboutView, ProfileCompanyView, Feed -# -from django.http import HttpResponse -def test(request): - return HttpResponse('123') - urlpatterns = patterns('', - url(r'^profile/$', login_required(ProfileView.as_view())), url(r'^profile/company/$', login_required(ProfileCompanyView.as_view())), url(r'^profile/settings/$', login_required(SettingsView.as_view())), url(r'^profile/calendar/remove/$', 'accounts.views.remove_from_calendar'), @@ -20,20 +14,8 @@ urlpatterns = patterns('', url(r'^profile/calendar/$', login_required(CalendarView.as_view())), url(r'^profile/feed/page/(?P\d+)/$', Feed.as_view()), url(r'^profile/feed/$', login_required(Feed.as_view())), - url(r'^user/(?P.*)/expositions/(?P\d+)/$', UserExpositionsView.as_view()), - url(r'^user/(?P.*)/expositions/$', UserExpositionsView.as_view()), - url(r'^user/(?P.*)/seminars/(?P\d+)/$', UserSeminarView.as_view()), - url(r'^user/(?P.*)/seminars/$', UserSeminarView.as_view()), - url(r'^user/(?P.*)/conferences/(?P\d+)/$', UserConferenceView.as_view()), - url(r'^user/(?P.*)/conferences/$', UserConferenceView.as_view()), - url(r'^user/(?P.*)/events/(?P\d+)/$', UserView.as_view()), - url(r'^user/(?P.*)/events/$', UserView.as_view()), - url(r'^user/(?P.*)/$', UserView.as_view()), url(r'^inactive-user/$', 'registration.backends.default.views.inactive_user_message'), - #url(r'^profile/messages/(?P.*)/$', login_required(MessagesView.as_view())), - #url(r'^profile/messages/$', login_required(MessagesView.as_view())), - # ajax url(r'^profile/update/name/$', login_required(NameView.as_view())), url(r'^profile/update/home/$', login_required(HomeView.as_view())), @@ -46,4 +28,4 @@ urlpatterns = patterns('', url(r'^profile/update/about/$', login_required(AboutView.as_view())), url(r'^profile/change-password/', 'accounts.views.change_password'), -) +) \ No newline at end of file diff --git a/accounts/user_catalog_urls.py b/accounts/user_catalog_urls.py index 60fdaf9d..1f8c302f 100644 --- a/accounts/user_catalog_urls.py +++ b/accounts/user_catalog_urls.py @@ -1,16 +1,11 @@ from django.conf.urls import patterns, url -from django.contrib.auth.decorators import login_required -from views import SettingsView, ProfileView, CalendarView, UserView, UserExpositionsView, UserConferenceView, UserSeminarView +from views import UserView, UserExpositionsView, UserConferenceView urlpatterns = patterns('', url(r'^(?P.*)/expositions/(?P\d+)/$', UserExpositionsView.as_view(), {'meta_id': 72}), url(r'^(?P.*)/expositions/$', UserExpositionsView.as_view(), {'meta_id': 72}), - url(r'^(?P.*)/seminars/(?P\d+)/$', UserSeminarView.as_view()), - url(r'^(?P.*)/seminars/$', UserSeminarView.as_view()), url(r'^(?P.*)/conferences/(?P\d+)/$', UserConferenceView.as_view(), {'meta_id': 73}), url(r'^(?P.*)/conferences/$', UserConferenceView.as_view(), {'meta_id': 73}), - url(r'^(?P.*)/events/(?P\d+)/$', UserView.as_view()), - url(r'^(?P.*)/events/$', UserView.as_view()), url(r'^(?P.*)/$', UserView.as_view(), {'meta_id': 71}), ) diff --git a/accounts/views.py b/accounts/views.py index c6cc53b5..cb486a5a 100644 --- a/accounts/views.py +++ b/accounts/views.py @@ -1,22 +1,29 @@ # -*- coding: utf-8 -*- import dateutil.relativedelta as rdelta -import json, datetime +import json +import datetime import calendar as python_calendar from django.shortcuts import get_object_or_404 from django.http import HttpResponseRedirect, HttpResponse, Http404 from django.contrib.auth.decorators import login_required from django.utils.translation import ugettext as _, get_language -from django.utils import timezone from django_messages.forms import SendForm from django.views.generic import TemplateView, FormView +from django.conf import settings from functions.custom_views import ListView +from functions.views_help import dates_range, get_user from sorl.thumbnail import get_thumbnail +from exposition.models import Exposition from .forms import ChangePasswordForm, EmailAnnouncementForm, FeedFilterForm from company.forms import CreateCompanyForm from .models import User from .edit_forms import AvatarForm, NameForm, HomeForm, WorkForm, AboutCompanyForm, PhoneForm, EmailForm,\ WebPageForm, SocialForm, AboutForm - +from company.edit_forms import NameForm as CompNameForm, HomeForm as CompHomeForm, PhoneForm as CompPhoneForm,\ + EmailForm as CompEmailForm, WebPageForm as CompWebPageForm, SocialForm as CompSocialForm,\ + TagForm as CompTagForm, DescriptionForm as CompDescr, StaffForm as CompStaff, \ + FoundationForm as CompFound, SpecializationForm as CompSpec, AddressForm as CompAddress +from meta.views import MetadataMixin class SettingsView(TemplateView): @@ -25,19 +32,14 @@ class SettingsView(TemplateView): password, email notifications, social settings, subscription """ - template_name = 'accounts/settings.html' + template_name = 'client/accounts/settings.html' + def get_context_data(self, **kwargs): context = super(SettingsView, self).get_context_data(**kwargs) context['change_password_form'] = ChangePasswordForm() context['email_announcement_form'] = EmailAnnouncementForm() return context -def dates_range(date1, date2): - delta = date2 - date1 - dates = [] - for i in range(delta.days + 1): - dates.append(date1 + datetime.timedelta(days=i)) - return dates class CalendarView(TemplateView): """ @@ -54,7 +56,6 @@ class CalendarView(TemplateView): - events - events in current months - days - days in current month - current_day - """ context = super(CalendarView, self).get_context_data(**kwargs) now = datetime.datetime.now().replace(microsecond=0, second=0, minute=0, hour=0) @@ -72,32 +73,27 @@ class CalendarView(TemplateView): number_of_days = python_calendar.monthrange(now.year, now.month)[1] # number of days in current month days = [datetime.datetime(now.year, now.month, i+1) for i in range(number_of_days)] - #context['days'] = days calendar = self.request.user.calendar # events in current month context['events'] = calendar.events_by_month(now) else: - number_of_days = python_calendar.monthrange(year, month)[1] + # days in current month days = [datetime.datetime(year, month, i+1) for i in range(number_of_days)] - # number of days in current month - #context['days'] = days + calendar = self.request.user.calendar now = now.replace(year=year, month=month, day=1) # events in current month context['events'] = calendar.events_by_month(now) - - # add days from previous mondey to next sunday - + # add days from previous monday to next sunday first_day = days[0] if first_day.weekday() != 0: past_monday = first_day + rdelta.relativedelta(days=-1, weekday=rdelta.MO(-1)) a = [past_monday + datetime.timedelta(days=x) for x in range((first_day - past_monday).days)] days = a + days - last_day = days[-1] if last_day != 6: @@ -106,9 +102,6 @@ class CalendarView(TemplateView): days += b events = context['events'] context['days'] = days - #days = context['days'] - event_in_day = False - counter = 0 dates_with_events = [] for event in events: dates_with_events += dates_range(event.data_begin, event.data_end) @@ -138,39 +131,6 @@ class CalendarView(TemplateView): return context - -class ProfileView(TemplateView): - """ - display template with user information forms - - in template forms handles dynamically by ajax - """ - template_name = 'accounts/new_profile.html' - - def get_context_data(self, **kwargs): - context = super(ProfileView, self).get_context_data(**kwargs) - user = self.request.user - profile = user.profile - - profile_forms = { - 'avatar_form': AvatarForm(instance=profile), 'name_form': NameForm(instance=user), - 'home_form': HomeForm(instance=profile), 'work_form': WorkForm(instance=user), - 'about_company_form': AboutCompanyForm(instance=profile), 'phone_form': PhoneForm(instance=profile), - 'email_form': EmailForm(instance=user), 'web_page_form': WebPageForm(instance=profile), - 'social_form': SocialForm(instance=profile), 'about_form': AboutForm(instance=profile) - } - if not user.company: - company_form = {'company_form': CreateCompanyForm()} - context.update(company_form) - - context.update(profile_forms) - return context - -from company.edit_forms import NameForm as CompNameForm, HomeForm as CompHomeForm, PhoneForm as CompPhoneForm,\ - EmailForm as CompEmailForm, WebPageForm as CompWebPageForm, SocialForm as CompSocialForm,\ - TagForm as CompTagForm, DescriptionForm as CompDescr, StaffForm as CompStaff, \ - FoundationForm as CompFound, SpecializationForm as CompSpec, AddressForm as CompAddress - class ProfileCompanyView(TemplateView): """ display template with user company information forms @@ -205,10 +165,6 @@ class ProfileCompanyView(TemplateView): return context - - - -from meta.views import MetadataMixin class UserView(MetadataMixin, TemplateView): """ display user information for another users @@ -243,8 +199,6 @@ class UserView(MetadataMixin, TemplateView): context.update(profile_forms) - - context['message_form'] = SendForm() context['member'] = user return context @@ -272,6 +226,7 @@ class BaseProfileView(ProfileInvalidView): response = {'success': True, 'rating': profile.user.rating} return HttpResponse(json.dumps(response), content_type='application/json') + class WorkView(ProfileInvalidView): """ instance user @@ -282,13 +237,11 @@ class WorkView(ProfileInvalidView): user = self.request.user form = self.form_class(self.request.POST, instance=user) user = form.save() - #company = user.company - - #response = {'success': True, 'url':company.get_permanent_url()} response = {'success': True, 'rating': user.rating} return HttpResponse(json.dumps(response), content_type='application/json') + class AvatarView(BaseProfileView): """ instance profile. save user avatar. @@ -350,6 +303,7 @@ class AboutView(BaseProfileView): """ form_class = AboutForm + class NameView(ProfileInvalidView): """ instance user @@ -364,25 +318,14 @@ class NameView(ProfileInvalidView): return HttpResponse(json.dumps(response), content_type='application/json') -from exposition.models import Exposition - - -def get_user(url): - try: - url = int(url) - user = get_object_or_404(User, id=url) - except ValueError: - user = get_object_or_404(User, url=url) - return user class UserEventView(ListView): model = Exposition - template_name = 'accounts/user_events.html' + template_name = 'client/accounts/user_events.html' paginate_by = 10 obj = None event_type = None - def get_queryset(self): url = self.kwargs.get('url') user = get_user(url) @@ -395,6 +338,7 @@ class UserEventView(ListView): context['event_type'] = self.event_type return context + class UserExpositionsView(MetadataMixin, UserEventView): """ return template with list of expos that user joined @@ -422,17 +366,6 @@ class UserConferenceView(MetadataMixin, UserEventView): self.kwargs['user_full_name'] = user.get_full_name() return user.get_confs() -class UserSeminarView(UserEventView): - """ - return template with list of seminars that user joined - """ - event_type = _(u'Семинары') - - def get_queryset(self): - url = self.kwargs.get('url') - user = get_user(url) - self.obj = user - return user.get_seminars() @login_required def change_password(request): @@ -462,10 +395,10 @@ def change_password(request): else: return HttpResponse(json.dumps(success), content_type='application/json') -from django.views.generic.edit import FormMixin + class Feed(ListView): template_name = 'client/accounts/feed.html' - paginate_by = 10 + paginate_by = settings.CLIENT_PAGINATION model = Exposition filter_form = FeedFilterForm success_url = '/profile/feed/' @@ -477,11 +410,9 @@ class Feed(ListView): form.filter_save() return HttpResponseRedirect(self.success_url) - def get_queryset(self): - filter = self.request.user.eventfilter - qs = filter.get_queryset() - + filter_obj = self.request.user.eventfilter + qs = filter_obj.get_queryset() return qs def get_context_data(self, **kwargs): diff --git a/company/management/__init__.py b/company/management/__init__.py deleted file mode 100644 index 8b137891..00000000 --- a/company/management/__init__.py +++ /dev/null @@ -1 +0,0 @@ - diff --git a/company/management/commands/__init__.py b/company/management/commands/__init__.py deleted file mode 100644 index 8b137891..00000000 --- a/company/management/commands/__init__.py +++ /dev/null @@ -1 +0,0 @@ - diff --git a/company/management/commands/company_from_old_db.py b/company/management/commands/company_from_old_db.py deleted file mode 100644 index 15d6e68a..00000000 --- a/company/management/commands/company_from_old_db.py +++ /dev/null @@ -1,97 +0,0 @@ -from django.core.management.base import BaseCommand, CommandError -from company.models import Company -from theme.models import Theme, Tag -from accounts.models import User -from functions.form_check import translit_with_separator -import datetime - -import MySQLdb -from MySQLdb.cursors import DictCursor - -def convert_to_int(st): - if not st: - return None - deduct = ('-','(',')','.',' ') - for elem in deduct: - st = st.replace(elem, '') - if st.isdigit(): - return int(st) - else: - return None - -class Command(BaseCommand): - def handle(self, *args, **options): - db = MySQLdb.connect(host="localhost", - user="root", - passwd="qazedc", - db="expomap_ru", - charset='utf8', - cursorclass=DictCursor) - - cursor = db.cursor() - sql = "select * from customers_company" - cursor.execute(sql) - - res = cursor.fetchall() - - - for c in res: - - phone = convert_to_int(c.get('phone')) - fax = convert_to_int(c.get('fax')) - url = c['url'] - if not url: - url = translit_with_separator(c.get('title')) - - - company = Company(id=c['company_id'], url=url, phone=phone, fax=fax, - email=c.get('email'), web_page=c.get('website'), twitter=c.get('twitter', '')) - - company.translate('ru') - company.name = c.get('title') - company.specialization = c.get('specialize') - company.description = c.get('about') - company.address_inf = c.get('adress') - user = User.objects.safe_get(id=user_id) - company.creator = user - print('not_saved: %s'%c['title']) - company.save() - user_id = c['customers_id'] - print('saved: %s'%str(company)) - - if user: - user.company = company - if not user.last_login: - now = datetime.datetime.now() - user.last_login = now - - user.save() - - theme = None - theme_id = c.get('otrasly') - if theme_id: - try: - theme = Theme.objects.get(id=theme_id) - except Theme.DoesNotExist: - continue - company.theme.add(theme) - - if not theme: - continue - - tags = c.get('tags') - if tags: - tags = tags.split(',') - if tags: - for tag_id in tags: - try: - tag = Tag.objects.get(id=tag_id) - except Tag.DoesNotExist: - continue - if tag.theme == theme: - company.tag.add(tag) - else: - continue - - #print(str(type(res[0]['phone']))) - print('success') \ No newline at end of file diff --git a/company/management/commands/company_test.py b/company/management/commands/company_test.py deleted file mode 100644 index a8060e93..00000000 --- a/company/management/commands/company_test.py +++ /dev/null @@ -1,77 +0,0 @@ -from django.core.management.base import BaseCommand, CommandError -from company.models import Company -from theme.models import Theme, Tag -from accounts.models import User -from functions.form_check import translit_with_separator -import datetime - -import MySQLdb -from MySQLdb.cursors import DictCursor - -def convert_to_int(st): - if not st: - return None - deduct = ('-','(',')','.',' ') - for elem in deduct: - st = st.replace(elem, '') - if st.isdigit(): - return int(st) - else: - return None - -class Command(BaseCommand): - def handle(self, *args, **options): - db = MySQLdb.connect(host="localhost", - user="root", - passwd="qazedc", - db="expomap_ru", - charset='utf8', - cursorclass=DictCursor) - - cursor = db.cursor() - sql = "select * from customers_company WHere otrasly>0" - cursor.execute(sql) - - res = cursor.fetchall() - print(len(res)) - - for c in res: - id = c['company_id'] - company = Company.objects.safe_get(id=id) - if not company: - continue - - theme_id = c.get('otrasly') - tags = c.get('tags') - - - if theme_id: - try: - theme = Theme.objects.get(id=theme_id) - except Theme.DoesNotExist: - continue - print(theme) - print(company) - company.theme.add(theme) - print('add %s theme to %s company'%(str(theme), str(company))) - print('123') - if not theme: - continue - - - tags = c.get('tags') - if tags: - tags = tags.split(',') - if tags: - for tag_id in tags: - try: - tag = Tag.objects.get(id=tag_id) - except Tag.DoesNotExist: - continue - if tag.theme == theme: - company.tag.add(tag) - print('add %s tag to %s company'%(str(tag), str(company))) - else: - continue - - diff --git a/functions/views_help.py b/functions/views_help.py index 3d764778..35e36cad 100644 --- a/functions/views_help.py +++ b/functions/views_help.py @@ -1,5 +1,8 @@ # -*- coding: utf-8 -*- import re +import datetime +from django.shortcuts import get_object_or_404 +from accounts.models import User def get_referer(request, default=None): referer = request.META.get('HTTP_REFERER') @@ -20,4 +23,19 @@ def split_params(st): if n != -1: params.append({'type': item[:n], 'url':item[n+1:]}) - return params \ No newline at end of file + return params + +def dates_range(date1, date2): + delta = date2 - date1 + dates = [] + for i in range(delta.days + 1): + dates.append(date1 + datetime.timedelta(days=i)) + return dates + +def get_user(url): + try: + url = int(url) + user = get_object_or_404(User, id=url) + except ValueError: + user = get_object_or_404(User, url=url) + return user \ No newline at end of file diff --git a/import_xls/excel_settings.py b/import_xls/excel_settings.py index 2754dd45..770e1561 100644 --- a/import_xls/excel_settings.py +++ b/import_xls/excel_settings.py @@ -426,7 +426,7 @@ place_exp_sett = { u'Выставочный зал': {u'field': u'exposition_hall', u'func': bool}, u'Площадь выст. зала': {u'field': u'exp_hall_area', u'func': to_int}, u'Общая вместимость': {u'field': u'total_capacity', u'func': to_int}, - u'Количество залов': {u'field': u'amount_halls', u'func': bool}, + u'Количество залов': {u'field': u'amount_halls', u'func': bool}, } # export place_settings=[ diff --git a/registration/backends/default/views.py b/registration/backends/default/views.py index 667ea2a3..bf4d2e1f 100644 --- a/registration/backends/default/views.py +++ b/registration/backends/default/views.py @@ -8,7 +8,8 @@ from registration import signals from registration.models import RegistrationProfile from registration.views import ActivationView as BaseActivationView from registration.views import RegistrationView as BaseRegistrationView -from django.views.generic import View +from accounts.forms import RegistrationCompleteForm, SocialRegistrationCompleteForm +from social.apps.django_app.default.models import UserSocialAuth import json @@ -248,8 +249,7 @@ def LoginView(request): else: HttpResponseRedirect('/') -from accounts.forms import RegistrationCompleteForm, RecoveryForm, SocialRegistrationCompleteForm -from social.apps.django_app.default.models import UserSocialAuth + def complete_registration(request): @@ -290,22 +290,4 @@ def acquire_email(request, template_name="registration/acquire_email.html"): def inactive_user_message(request): - return render(request, 'registration/social_registration_complete.html') - - - -def pswd_recovery(request): - #if request.is_ajax(): - response = {'success': False} - form = RecoveryForm(request.POST) - if form.is_valid(): - user = form.get_user() - user.se - response['success']=True - else: - response['errors'] = form.errors - return HttpResponse(json.dumps(response), content_type='application/json') - - #else: - # return HttpResponse('not ajax') - + return render(request, 'registration/social_registration_complete.html') \ No newline at end of file diff --git a/templates/client/accounts/feed.html b/templates/client/accounts/feed.html index 7b22e691..d3b7bd06 100644 --- a/templates/client/accounts/feed.html +++ b/templates/client/accounts/feed.html @@ -1,6 +1,7 @@ {% extends 'base_catalog.html' %} {% load i18n %} {% load static %} + {% block bread_scrumbs %} diff --git a/templates/client/includes/exposition/photo.html b/templates/client/includes/exposition/photo.html new file mode 100644 index 00000000..a21e8a3a --- /dev/null +++ b/templates/client/includes/exposition/photo.html @@ -0,0 +1,79 @@ +{% load static %} +{% load i18n %} +{% load template_filters %} + + +{% block page_body %} +
+
+
+ + +
+
+
+ +
+ {% if object.main_title %} +
+ {{ object.main_title|safe }} +
+ {% endif %} + +
+ +
+
+
+ + +
+ +{% endblock %} + +{% block photogallery %} + {% include 'client/popups/photo.html' %} +{% endblock %} +{% block scripts %} + + + +{% endblock %} diff --git a/templates/client/includes/exposition/programm.html b/templates/client/includes/exposition/programm.html index 1b6ea56c..c15b53a6 100644 --- a/templates/client/includes/exposition/programm.html +++ b/templates/client/includes/exposition/programm.html @@ -118,7 +118,7 @@ {% endif %} {% endwith %} {% with event=exposition filter=filter %} - {% include 'includes/event_steps.html' %} + {% include 'client/includes/event_steps.html' %} {% endwith %} diff --git a/templates/client/includes/exposition/statistic.html b/templates/client/includes/exposition/statistic.html index ed72dfda..6181a247 100644 --- a/templates/client/includes/exposition/statistic.html +++ b/templates/client/includes/exposition/statistic.html @@ -15,9 +15,7 @@ {% include 'client/includes/show_logo.html' %} {% endwith %} - +
{% if exposition.visitors %} {{ exposition.visitors }} diff --git a/templates/client/includes/paginator.html b/templates/client/includes/paginator.html deleted file mode 100644 index e6bf01a2..00000000 --- a/templates/client/includes/paginator.html +++ /dev/null @@ -1,47 +0,0 @@ -{% load i18n %} -{% load template_filters %} - -{% if page_obj.paginator.num_pages > 1 %} - - {% endif %} \ No newline at end of file diff --git a/templates/client/includes/place/photo.html b/templates/client/includes/place/photo.html index 207c761b..16ade109 100644 --- a/templates/client/includes/place/photo.html +++ b/templates/client/includes/place/photo.html @@ -4,7 +4,7 @@ {% block page_body %} -
+
@@ -28,7 +28,7 @@ @@ -47,7 +47,7 @@
  • - {{ photo.title }} + {{ photo.caption }}
  • {% endfor %} @@ -56,24 +56,19 @@
    - {% block paginator %} - {% with page_obj=page_obj queries=queries %} - {% include 'includes/paginator.html' %} - {% endwith %} - - {% endblock %} {% endblock %} {% block photogallery %} {% include 'client/popups/photo.html' %} {% endblock %} {% block scripts %} - + +