diff --git a/conference/models.py b/conference/models.py index 75c91e56..b79b5875 100644 --- a/conference/models.py +++ b/conference/models.py @@ -59,6 +59,7 @@ class Conference(TranslatableModel, EventMixin, ExpoMixin): blank=True, null=True, related_name='conference_tags') organiser = models.ManyToManyField('organiser.Organiser', verbose_name='Организатор', blank=True, null=True, related_name='conference_organisers') + org = models.CharField(max_length=255, blank=True, null=True) company = models.ManyToManyField('company.Company', verbose_name='Компании', blank=True, null=True, related_name='conference_companies') users = models.ManyToManyField('accounts.User', verbose_name='Посетители выставки', diff --git a/conference/views.py b/conference/views.py index ee558ea7..3363cc12 100644 --- a/conference/views.py +++ b/conference/views.py @@ -167,17 +167,7 @@ class ConferenceCountryCatalog(ConferenceCatalog): def get_filtered_qs(self): #this method used in parent get_queryset slug = self.kwargs.get('slug') - try: - country = Country.objects.get(url=slug) - except Country.DoesNotExist: - try: - country = Country.objects.get(old_url=slug) - except Country.DoesNotExist: - raise Http404 - except Country.MultipleObjectsReturned: - country = Country.objects.filter(old_url=slug)[0] - - #country = get_object_or_404(Country, url=slug) + country = get_object_or_404(Country, url=slug) self.kwargs['country'] = country self.filter_object = country qs = self.model.enable.upcoming().filter(country=country) @@ -206,16 +196,7 @@ class ConferenceThemeCatalog(ConferenceCatalog): slug = self.kwargs.get('slug') country_slug = self.kwargs.get('country_slug') city_slug = self.kwargs.get('city_slug') - try: - theme = Theme.objects.get(url=slug) - except Theme.DoesNotExist: - try: - theme = Theme.objects.get(old_url=slug) - except Theme.DoesNotExist: - raise Http404 - except Theme.MultipleObjectsReturned: - theme = Theme.objects.filter(old_url=slug)[0] - #theme = get_object_or_404(Theme, url=slug) + theme = get_object_or_404(Theme, url=slug) self.kwargs['theme'] = theme qs = self.model.enable.upcoming().filter(theme=theme) @@ -246,17 +227,7 @@ class ConferenceTagCatalog(ConferenceCatalog): def get_filtered_qs(self): #this method used in parent get_queryset slug = self.kwargs.get('slug') - try: - tag = Tag.objects.get(url=slug) - except Tag.DoesNotExist: - try: - tag = Tag.objects.get(old_url=slug) - except Tag.DoesNotExist: - raise Http404 - except Tag.MultipleObjectsReturned: - tag = Tag.objects.filter(old_url=slug)[0] - - #tag = get_object_or_404(Tag, url=slug) + tag = get_object_or_404(Tag, url=slug) self.kwargs['tag'] = tag qs = self.model.enable.upcoming().filter(tag=tag) self.filter_object = tag @@ -392,10 +363,6 @@ class ConferenceDetail(JitterCacheMixin, DetailView): return HttpResponseRedirect('/conference/city/%s/'%city.url) except City.DoesNotExist: return super(ConferenceDetail, self).dispatch(request, *args, **kwargs) - except City.MultipleObjectsReturned: - city = City.objects.filter(old_url=slug)[0] - return HttpResponseRedirect('/conference/city/%s/'%city.url) - diff --git a/core/models.py b/core/models.py index 71a83623..dad86ae2 100644 --- a/core/models.py +++ b/core/models.py @@ -1,3 +1,88 @@ -from django.db import models +# -*- coding: utf-8 -*- +from django.contrib.syndication.views import Feed +from django.shortcuts import get_object_or_404 -# Create your models here. +from exposition.models import Exposition +from theme.models import Theme +from country.models import Country +from city.models import City + +EXPO_ON_PAGE = 10 + +# nearest expositions at all + +class LatestExpositions(Feed): + title = u"Ближайшие выставки на expomap.ru" + link = '/rss/latest/' + description = u'Подписывайтесь на наш RSS-канал' + + def items(self): + return Exposition.enable.upcoming()[:EXPO_ON_PAGE] + + def item_title(self, item): + return item.name + + def item_description(self, item): + return item.main_title + + def item_link(self, item): + return '/expo/%s/'%item.url + +NUM_ITEMS_ON_PAGE = 20 + + +class CountryFeeds(Feed): + description_template = '/rss/country_feeds/' + + def get_object(self, request, slug): + return get_object_or_404(Country, url=slug) + + def title(self, obj): + return u"Ближайшие выставки %s:" % obj.inflect + + def link(self,obj): + return obj.get_permanent_url() + + def item_description(self, obj): + return obj.main_title + + def items(self, obj): + return Exposition.enable.upcoming().filter(country=obj)[:NUM_ITEMS_ON_PAGE] + + +class CityFeeds(Feed): + description_template = '/rss/city_feeds/' + + def get_object(self, request, slug): + return get_object_or_404(City, url=slug) + + def title(self, obj): + return u"Ближайшие выставки в %s: " % obj.inflect + + def link(self,obj): + return obj.get_permanent_url() + + def item_description(self, obj): + return obj.main_title + + def items(self, obj): + return Exposition.enable.upcoming().filter(city = obj)[:NUM_ITEMS_ON_PAGE] + + +class ThemeFeeds(Feed): + description_template = '/rss/theme_feeds/' + + def get_object(self, request, slug): + return get_object_or_404(Theme, url=slug) + + def title(self, obj): + return u"Ближайшие выставки %s: " % obj.inflect + + def link(self,obj): + return obj.url + + def item_description(self, obj): + return obj.main_title + + def items(self, obj): + return Exposition.enable.upcoming().filter(theme = obj)[:NUM_ITEMS_ON_PAGE] \ No newline at end of file diff --git a/core/simple_views.py b/core/simple_views.py index 45cb457b..d6fe480c 100644 --- a/core/simple_views.py +++ b/core/simple_views.py @@ -13,7 +13,7 @@ class SeminarLendingView(TemplateView): def send_to_organiser(request): - mail_send = 'expomap@mail.ru' + mail_send = 'kotzilla@ukr.net' fname = request.POST.get('name') lname = request.POST.get('surname') email = request.POST.get('email', '') @@ -31,12 +31,8 @@ def send_to_organiser(request): msg.content_subtype = "html" msg.send() redirect_to = '/service/thanks/' - if title.endswith(u'семинар'): - message = u"""Мы получили Ваш запрос и очень рады, что Вам интересно участие в семинаре Expomap. Если места еще есть, мы пришлем Вам приглашение на указанную Вами электронную почту. - Увидимся на welcome-coffee ☺""" - else: - message = u"""Благодарим за интерес к нашему семинару! За несколько дней до мероприятия мы пришлем Вам ссылку для подключения к онлайн-трансляции!""" - + message = u"""Мы получили Ваш запрос и очень рады, что Вам интересно участие в семинаре Expomap. Если места еще есть, мы пришлем Вам приглашение на указанную Вами электронную почту. +Увидимся на welcome-coffee ☺""" return HttpResponse(json.dumps({'success':True, 'redirect_to': redirect_to, 'message': message}), content_type='application/json') diff --git a/core/urls.py b/core/urls.py new file mode 100644 index 00000000..88f2e7c0 --- /dev/null +++ b/core/urls.py @@ -0,0 +1,11 @@ +from django.conf.urls import url, patterns +from models import LatestExpositions, CountryFeeds, CityFeeds, ThemeFeeds + + +urlpatterns = patterns('', + url(r'^latest/$', LatestExpositions()), + url(r'^country/(?P.*)/$', CountryFeeds()), + url(r'^city/(?P.*)/$', CityFeeds()), + url(r'^theme/(?P.*)/$', ThemeFeeds()), + +) diff --git a/exposition/management/commands/test.py b/exposition/management/commands/test.py index 757eb94b..271b6d8d 100644 --- a/exposition/management/commands/test.py +++ b/exposition/management/commands/test.py @@ -1,91 +1,20 @@ # -*- coding: utf-8 -*- -import MySQLdb -import os.path -from MySQLdb.cursors import DictCursor -from django.utils.translation import activate from django.core.management.base import BaseCommand -from django.conf import settings -from exposition.models import Exposition -from theme.models import Theme +from meta.models import MetaSetting class Command(BaseCommand): def handle(self, *args, **options): - #expos = Exposition.objects.filter(theme__isnull=True, old_url__isnull=False) - db = MySQLdb.connect(host="localhost", - user="expomap", - passwd="7FbLtAGjse", - db="old_db", - charset='utf8', - cursorclass=DictCursor) - cursor = db.cursor() - activate('ru') - expos = Exposition.enable.upcoming().filter(logo='') - #expo = Exposition.objects.get(old_url='mir-detstva-i-shkoly-2015') - #handle_expo(expo, cursor) + a = MetaSetting.objects.filter(translations__h1__contains='«').count() + qs = MetaSetting.objects.language('ru').all() + for item in qs: + item.title = item.title.replace(u'«', u'').replace(u'»', u'') + item.description = item.title.replace(u'«', u'').replace(u'»', u'') + item.h1 = item.h1.replace(u'«', u'').replace(u'»', u'') + #item.save() - for expo in expos: - handle_expo(expo, cursor) - ''' - find_old_id = """ - SELECT products.products_id - from products - LEFT JOIN `products_description` ON products.products_id=products_description.products_id - WHERE url='%s' - """ - - find_themes = "SELECT categories_id FROM `products_to_categories` WHERE `products_id` =%d" - ''' - """ - for expo in expos: - cursor.execute(find_old_id%expo.old_url) - old_ids = [item['products_id'] for item in cursor.fetchall()] - print expo.old_url - for id in old_ids: - cursor.execute(find_themes%id) - themes_ids = [item['categories_id'] for item in cursor.fetchall()] - print themes_ids - #if not themes_ids: - # continue - - - theme_qs = Theme.objects.filter(id__in=themes_ids) - #expo.theme.add(*theme_qs) - break - - print('----------------------') - """ - -def handle_expo(expo, cursor): - if expo.logo: - return - - find_old = """ - SELECT products.products_id, url, products_img1 as logo - from products - LEFT JOIN `products_description` ON products.products_id=products_description.products_id - WHERE url='%s' - """ - cursor.execute(find_old%expo.old_url) - result = cursor.fetchall() - if not result: - return - logo = result[0]['logo'] - - - if logo: - logo = logo.replace('..', '') - - print(logo) - print(os.path.isfile(settings.MEDIA_ROOT[:-1]+logo)) - if (os.path.isfile(settings.MEDIA_ROOT[:-1]+logo)): - - expo.logo = logo - expo.save() - - diff --git a/exposition/models.py b/exposition/models.py index 1171f42d..77fb9c4d 100644 --- a/exposition/models.py +++ b/exposition/models.py @@ -71,6 +71,7 @@ class Exposition(TranslatableModel, EventMixin, ExpoMixin): blank=True, null=True, related_name='exposition_tags') organiser = models.ManyToManyField('organiser.Organiser', verbose_name='Организатор', blank=True, null=True, related_name='exposition_organisers') + org = models.CharField(max_length=255, blank=True, null=True) company = models.ManyToManyField('company.Company', verbose_name='Компании', blank=True, null=True, related_name='exposition_companies') users = models.ManyToManyField('accounts.User', verbose_name='Посетители выставки', diff --git a/functions/signal_handlers.py b/functions/signal_handlers.py index 8e69b737..a0c3a07a 100644 --- a/functions/signal_handlers.py +++ b/functions/signal_handlers.py @@ -6,7 +6,8 @@ from functions.form_check import translit_with_separator def pre_save_handler(sender, **kwargs): obj = kwargs['instance'] url = getattr(obj, 'url') - if url is not None: + + if url: return if hasattr(obj, 'language_code') and obj.language_code =='en': @@ -21,21 +22,6 @@ def pre_save_handler(sender, **kwargs): obj.url = ''.join([random.choice(string.ascii_lowercase) for n in xrange(8)]) - - """ - url = getattr(obj, 'url') - if url: - try: - en_name = obj._meta.translations_model.objects.get(language_code='en', master__id=getattr(obj, 'id')) - obj.url = translit_with_separator(en_name) - except: - pass - - else: - # generate random url if url field is empty - obj.url = ''.join([random.choice(string.ascii_lowercase) for n in xrange(8)]) - """ - def post_save_handler(sender, **kwargs): """ receiver function diff --git a/import_xls/admin.py b/import_xls/admin.py index a2b43cc3..2de38d12 100644 --- a/import_xls/admin.py +++ b/import_xls/admin.py @@ -96,13 +96,17 @@ class ExportCity(ExportView): from exposition.models import Exposition class ImportEvent(FormView): form_class = ImportEventForm - success_url = '/admin/import-event' + success_url = '/admin/import-event/' + template_name = 'admin/import templates/import_event.html' def form_valid(self, form): - result = form.save_file() - Exposition.imports.create_by_dict(result[0]) + errors = form.save_file_debug() 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) - return super(ImportView, self).form_valid(form) + #return super(ImportEvent, self).form_valid(form) class ImportTheme(ImportView): form_class = ImportThemeForm diff --git a/import_xls/excel_settings.py b/import_xls/excel_settings.py index 43a30a4d..94cab89f 100644 --- a/import_xls/excel_settings.py +++ b/import_xls/excel_settings.py @@ -469,10 +469,10 @@ event_sett = { 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'Место проведения':{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'organiser', u'func': to_tag},#### + 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}, diff --git a/import_xls/import_forms.py b/import_xls/import_forms.py index de1a6aa0..27f83514 100644 --- a/import_xls/import_forms.py +++ b/import_xls/import_forms.py @@ -9,6 +9,7 @@ from organiser.models import Organiser from django.db.models.loading import get_model import xlrd, xlwt from excel_settings import import_settings +from functions.form_check import translit_with_separator languages = [code for code in settings.LANGUAGES] @@ -211,6 +212,10 @@ class ImportPlaceConferenceForm(ImportForm): 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'НЕправильный формат или не заполнена дата начала'} class ImportEventForm(ImportForm): """ @@ -221,40 +226,132 @@ class ImportEventForm(ImportForm): ('conference.Conference', 'Конференция'), ('seminar.Seminar', 'Семинар'), ('webinar.Webinar', 'Вебинар')]) - def save_file(self): - """ - save events from excel file - in language from form - """ + + def save_file_debug(self): data = self.cleaned_data lang = 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)] - # all field names in excel file (must be in second row) field_names = [name for name in row_list[0]] # model model = get_model(data['event'].split('.')[0], data['event'].split('.')[1]) - list_dicts = [] + labels = [label for label in row_list[0]] + errors = [] - for row_number, row in enumerate(row_list[1:]): - d = {} + for row_number, row in enumerate(row_list): + if row_number == 0: + continue + + if row[0] != '': + # in first column id + try: + obj = self.model.objects.language(lang).get(id=int(row[0])) + except ValueError: + obj = self.model() + obj.translate(lang) + + except self.model.DoesNotExist: + obj = self.model(id= int(row[0])) + obj.translate(lang) + else: + # if id blank - its a new event + obj = model() + obj.translate(lang) + + methods = [] for col_number, cell in enumerate(row): - # through row - field_name = field_names[col_number] - setting = event_sett.get(field_name) - if setting: - d[setting['field']] = {'value':cell} + # go through row cells + # field name current cell + label = labels[col_number] + + setting = event_sett.get(label) + + if setting is None: + 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')}) + continue + + field_name = setting['field'] + func = setting.get('func') + if func is None: + 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, theme, 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) + elif setting.get('bitfield'): + value = func(obj, cell, setting['label']) + 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]) + continue + + for method in methods: + func = method['func'] + if method.get('purpose'): + try: + func(obj, method['value'], method['purpose']) + except: + continue + else: + func(obj, method['value']) - d['lang'] = lang - list_dicts.append(d) + #------------- - return list_dicts + return errors + def save_file(self): + """ + save events from excel file + in language from form + """ + data = self.cleaned_data + lang = 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)] + # all field names in excel file (must be in second row) + field_names = [name for name in row_list[0]] + # model + model = get_model(data['event'].split('.')[0], data['event'].split('.')[1]) + list_dicts = [] for row_number, row in enumerate(row_list): # go through all rows in file @@ -320,7 +417,6 @@ class ImportEventForm(ImportForm): """ #object.save() - sadsa diff --git a/import_xls/utils.py b/import_xls/utils.py index 28babe91..de52aac3 100644 --- a/import_xls/utils.py +++ b/import_xls/utils.py @@ -33,7 +33,10 @@ def to_date(value): try: t = time.strptime(value, "%d.%m.%Y") except ValueError: - t = time.strptime(value, "%d/%m/%Y") + try: + t = time.strptime(value, "%d/%m/%Y") + except ValueError: + return None if isinstance(value, float): t = xlrd.xldate_as_tuple(value, 0)+(0,0,0) @@ -103,6 +106,7 @@ def to_tag(obj,value): def to_place(value): + value = value.replace('/', '') try: place = PlaceExposition.objects.get(url=value) return place diff --git a/proj/urls.py b/proj/urls.py index 79b1f5b1..758f565f 100644 --- a/proj/urls.py +++ b/proj/urls.py @@ -26,6 +26,7 @@ sitemaps = { handler404 = 'proj.views.error404' urlpatterns = patterns('', + url(r'^rss/', include('core.urls')), #url(r'^__debug__/', include(debug_toolbar.urls)), url(r'^sitemap-(?P
.+)\.xml$', views.sitemap, {'sitemaps': sitemaps}), url(r'^admin/', include('proj.admin_urls')), diff --git a/settings/conference_old_urls.py b/settings/conference_old_urls.py index c8abcb62..c741904a 100644 --- a/settings/conference_old_urls.py +++ b/settings/conference_old_urls.py @@ -41,5 +41,4 @@ urlpatterns = patterns('', url(r'^conference/theme-(?P.*)/page-(?P\d+)/$', old_redirect, {'redirect_url': '/conference/theme/{theme}/page/{page}/'}), url(r'^conference/theme-(?P.*)/page/(?P\d+)/$', old_redirect, {'redirect_url': '/conference/theme/{theme}/page/{page}/'}), url(r'^conference/theme-(?P.*)/$', old_redirect, {'redirect_url': '/conference/theme/{theme}/'}), - ) diff --git a/settings/old_urls.py b/settings/old_urls.py index 34139e5b..668e0e8e 100644 --- a/settings/old_urls.py +++ b/settings/old_urls.py @@ -142,10 +142,6 @@ urlpatterns = patterns('', url(r'^catalog/theme-(?P.*)/page/(?P\d+)/$', old_redirect, {'redirect_url': '/expo/theme/{theme}/page/{page}/'}), url(r'^catalog/theme-(?P.*)/$', old_redirect, {'redirect_url': '/expo/theme/{theme}/'}), url(r'^catalog/theme/$', old_redirect, {'redirect_url': '/expo/theme/'}), - - # - url(r'^catalog/time/(?P\d+)/$', old_redirect, {'redirect_url': '/expo/{year}/'}), - url(r'^catalog/time/$', old_redirect, {'redirect_url': '/expo/'}), # tag diff --git a/settings/redirect_views.py b/settings/redirect_views.py index 33569c25..3fbee5d7 100644 --- a/settings/redirect_views.py +++ b/settings/redirect_views.py @@ -15,12 +15,11 @@ class RedirectMixin(object): def get_object_url(self, key, value): Model = self.model + try: obj = Model.objects.get(old_url=value) - except Model.DoesNotExist: + except: obj = get_object_or_404(Model, url=value) - except Model.MultipleObjectsReturned: - obj = Model.objects.filter(old_url=value)[0] if obj: return {key: obj.url} else: @@ -46,12 +45,12 @@ class TagRedirect(RedirectMixin): try: obj = Model.objects.get(url=value) except Model.DoesNotExist: - if value.endswith('-expo'): + if value.endwith('-expo'): value = value.replace('-expo', '') - elif value.endswith('-conf'): + elif value.endwith('-conf'): value = value.replace('-conf', '') - obj = get_object_or_404(Model, old_url=value) + obj = get_object_or_404(old_url=value) if obj: return {key: obj.url} diff --git a/static/seminar_lending/css/main.css b/static/seminar_lending/css/main.css index 26e62299..12af0c1a 100644 --- a/static/seminar_lending/css/main.css +++ b/static/seminar_lending/css/main.css @@ -263,6 +263,7 @@ a.btn { display: block; padding-left: 22px; border-left: 1px solid #e8e8e7; + font-size:16px; } .event-program-strip .timing-table .timing .reporter img, .event-program-strip .timing-table .timing .reporter figcaption { diff --git a/templates/admin/import templates/import_event.html b/templates/admin/import templates/import_event.html index 2866f2e7..4216f0ab 100644 --- a/templates/admin/import templates/import_event.html +++ b/templates/admin/import templates/import_event.html @@ -55,6 +55,28 @@ {{ message }} {% endif %} + + {% if import_errors %} +
+ + + + + + + + + {% for error in import_errors %} + + + + + {% endfor %} + +
СобытиеОшибка
{{ error.0 }}{{ error.1 }}
+
+ {% endif %} +