diff --git a/conference/forms.py b/conference/forms.py index 0cc64a21..6e8ddb18 100644 --- a/conference/forms.py +++ b/conference/forms.py @@ -14,7 +14,7 @@ from company.models import Company from service.models import Service from place_conference.models import PlaceConference #functions -from functions.translate import populate_all, fill_trans_fields_all +from functions.translate import populate_all, fill_trans_fields_all, fill_with_signal from functions.form_check import is_positive_integer from functions.files import check_tmp_files from functions.form_check import translit_with_separator @@ -133,8 +133,7 @@ class ConferenceCreateForm(forms.Form): if data.get('place'): conference.place = PlaceConference.objects.get(id=data['place'].id)#.id cause select uses queryset - # uses because in the next loop data will be overwritten - conference.save() + fill_with_signal(Conference, conference, data) #fill manytomany fields for item in data['theme']: conference.theme.add(item.id)#.id cause select uses queryset @@ -143,15 +142,7 @@ class ConferenceCreateForm(forms.Form): conference.tag.add(item) # uses because in the next loop data will be overwritten conference.save() - #will be saved populated fields - zero_fields = {} - #fills all translated fields with data - #if saves new object, will fill city object. otherwise existing object of City model - fill_trans_fields_all(Conference, conference, data, id, zero_fields) - #autopopulate - #populate empty fields and fields which was already populated - conference_id = getattr(conference, 'id') - populate_all(Conference, data, conference_id, zero_fields) + #save files check_tmp_files(conference, data['key']) diff --git a/conference/models.py b/conference/models.py index 8d026e74..7e17f7ab 100644 --- a/conference/models.py +++ b/conference/models.py @@ -158,4 +158,46 @@ class TimeTable(TranslatableModel): #translated fields translations = TranslatedFields( name = models.CharField(verbose_name='Название', max_length=255) - ) \ No newline at end of file + ) + +from django.db.models.signals import post_save +from django.dispatch import receiver +from django.conf import settings +from functions.form_check import translit_with_separator +from functions.translate import get_translated_fields + +@receiver(post_save) +def conference_post_save_handler(sender, **kwargs): + """ + objects saves two times: + - first time Conference object + - second time ConferenceTranslation object + object must have at least one Translation + """ + + obj = kwargs['instance'] + if isinstance(obj, Conference): + # object is Exposition + if kwargs['created'] and obj.url == '': + # if url doesn't set in new object set it + obj.url = translit_with_separator(obj.name) + + # what languages must be + all_langs = [code for code, lang in settings.LANGUAGES] + # what languages are + obj_langs = obj.get_available_languages() + # + missing_languages = list(set(all_langs) - set(obj_langs)) + # get first Translation object + translation = obj.translations.all()[0] + # translated fields + fields = get_translated_fields(obj) + + for code in missing_languages: + # translate + obj.translate(code) + # go through all fields and set value + for field in fields: + setattr(obj, field, getattr(translation, field)) + + obj.save() \ No newline at end of file diff --git a/exposition/forms.py b/exposition/forms.py index 7e0fbd08..6473bec8 100644 --- a/exposition/forms.py +++ b/exposition/forms.py @@ -15,7 +15,7 @@ from city.models import City from service.models import Service from place_exposition.models import PlaceExposition #functions -from functions.translate import populate_all, fill_trans_fields_all +from functions.translate import populate_all, fill_trans_fields_all, fill_with_signal from functions.form_check import is_positive_integer from functions.files import check_tmp_files from functions.form_check import translit_with_separator @@ -145,8 +145,9 @@ class ExpositionCreateForm(forms.Form): if data.get('place'): exposition.place = PlaceExposition.objects.get(id=data['place'].id)#.id cause select uses queryset - # uses because in the next loop data will be overwritten - exposition.save() + + fill_with_signal(Exposition, exposition, data) + #fill manytomany fields for item in data['theme']: exposition.theme.add(item.id)#.id cause select uses queryset @@ -156,15 +157,6 @@ class ExpositionCreateForm(forms.Form): # uses because in the next loop data will be overwritten exposition.save() - #will be saved populated fields - zero_fields = {} - #fills all translated fields with data - #if saves new object, will fill city object. otherwise existing object of City model - fill_trans_fields_all(Exposition, exposition, data, id, zero_fields) - #autopopulate - #populate empty fields and fields which was already populated - exposition_id = getattr(exposition, 'id') - populate_all(Exposition, data, exposition_id, zero_fields) #save files check_tmp_files(exposition, data['key']) diff --git a/exposition/models.py b/exposition/models.py index 4f0589c8..13f95fbe 100644 --- a/exposition/models.py +++ b/exposition/models.py @@ -194,6 +194,10 @@ def exposition_post_save_handler(sender, **kwargs): obj = kwargs['instance'] if isinstance(obj, Exposition): # object is Exposition + if kwargs['created'] and obj.url == '': + # if url doesn't set in new object set it + obj.url = translit_with_separator(obj.name) + # what languages must be all_langs = [code for code, lang in settings.LANGUAGES] # what languages are @@ -202,8 +206,9 @@ def exposition_post_save_handler(sender, **kwargs): missing_languages = list(set(all_langs) - set(obj_langs)) # get first Translation object translation = obj.translations.all()[0] - # + # translated fields fields = get_translated_fields(obj) + for code in missing_languages: # translate obj.translate(code) @@ -211,12 +216,4 @@ def exposition_post_save_handler(sender, **kwargs): for field in fields: setattr(obj, field, getattr(translation, field)) - obj.save() - - if isinstance(obj, ExpositionTranslation): - # object is Translation - print('trans') - if obj.language_code == 'ru': - exp = Exposition.objects.get(id=obj.master_id) - exp.url = translit_with_separator(exp.name) - exp.save() \ No newline at end of file + obj.save() \ No newline at end of file diff --git a/import_xls/custom_forms.py b/import_xls/custom_forms.py index 9a711e73..c2c61643 100644 --- a/import_xls/custom_forms.py +++ b/import_xls/custom_forms.py @@ -1,7 +1,11 @@ # -*- coding: utf-8 -*- from django import forms from django.conf import settings - +from theme.models import Theme +from country.models import Country +from django.db.models.loading import get_model +import xlrd, xlwt +from excel_settings import import_settings, field_settings languages = [code for code in settings.LANGUAGES] @@ -14,12 +18,58 @@ class ImportEventForm(forms.Form): ('webinar.Webinar', 'Вебинар')]) language = forms.ChoiceField(label='Выберите язык', choices=languages) + def save_events(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[1]] + # model + model = get_model(data['event'].split('.')[0], data['event'].split('.')[1]) + + for row_number, row in enumerate(row_list): + # go through all rows in file + if row_number > 1: + # first two fields are verbose name and name + if row[0] != '': + # in first column ids + object = model.objects.language(lang).get(id=row[0]) + else: + # if id blank - its a new event + object = model() + object.translate(lang) -from theme.models import Theme -from country.models import Country -from django.db.models.loading import get_model -import StringIO -from functions.translate import get_all_fields, get_all_verbose_names + for col_number, cell in enumerate(row): + # go through row cells + # field name current cell + field_name = field_names[col_number] + setting = import_settings.get(field_name) + if setting is not None: + # if setting exist for this field + func = setting.get('func') + if func is not None: + 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) + value = func(cell, lang, getattr(object, extra_value)) + else: + value = func(cell) + + setattr(object, field_name, value) + + object.save() class ExportEventForm(forms.Form): @@ -33,6 +83,61 @@ class ExportEventForm(forms.Form): theme = forms.ModelMultipleChoiceField(label='Направление', queryset=Theme.objects.all(), required=False) country = forms.ModelMultipleChoiceField(label='Страны', queryset=Country.objects.all(), required=False) + def export_events(self): + data = self.cleaned_data + # get model + model = get_model(data['event'].split('.')[0], data['event'].split('.')[1]) + # get objects + objects = model.objects.language(data['language']).filter(data_begin__range=[data['date_from'], data['date_to']], + country__in=data['country'], + theme__in=data['theme'] + ).distinct() + + if not objects: + # not found any objects + return None + message = 'По даному запросу объектов не найдено' + args = {} + args.update(csrf(request)) + args['message'] = message + args['form'] = form + return render_to_response('export_event.html', args) + + workbook = xlwt.Workbook(encoding = 'utf8') + # new tab + worksheet = workbook.add_sheet('My Worksheet') + + # Create the Font for first rows + font = xlwt.Font() + font.name = 'Times New Roman' + font.bold = True + style = xlwt.XFStyle() + # Create the Style + style.font = font + + for row, object in enumerate(objects): + # column number + col = 0 + for field in field_settings: + try: + value = getattr(object, field['name']) + except AttributeError: + # doesnt have such field. exit from iteration + continue + + if row == 0: + # first iteration. set names. set columns width + worksheet.write(0, col, field.get('verbose_name', 'default'), style) + worksheet.write(1, col, field.get('name'), style) + worksheet.col(col).width = field.get('width', 3333) + if field['name']=='tag': + worksheet.write(row+2, col, field.get('type')(value, object.theme)) + else: + worksheet.write(row+2, col, field.get('type')(value)) + col += 1 + + return workbook + def clean_theme(self): """ diff --git a/import_xls/excel_settings.py b/import_xls/excel_settings.py index 3a3b0161..55dc7ac9 100644 --- a/import_xls/excel_settings.py +++ b/import_xls/excel_settings.py @@ -1,6 +1,7 @@ # -*- coding: utf-8 -*- -import xlwt -import datetime +from country.models import Country +from city.models import City +from theme.models import Theme, Tag def get_bool(value): if value: @@ -24,6 +25,25 @@ def get_audience(value): else: return '' +def get_theme(value): + objects = value.all() + return ', '.join(str(obj) for obj in objects) + + +def get_tag(tag, theme): + tags = tag.all() + themes = theme.all() + result = '' + for theme in themes: + # list of tags with current theme + tag_list = [str(tag) for tag in tags if tag.theme == theme] + + result += '['+','.join(tag_list)+']' + + return result + + + field_settings = [ {'name': 'id', 'verbose_name': 'id', 'type': get_int, 'width':1500}, {'name': 'url', 'verbose_name': 'url', 'type': str}, @@ -35,6 +55,8 @@ field_settings = [ {'name': 'audience', 'verbose_name': 'Аудитория', 'type': get_audience}, {'name': 'country', 'verbose_name': 'Страна', 'type': str}, {'name': 'city', 'verbose_name': 'Город', 'type': str}, + {'name': 'theme', 'verbose_name': 'Тематика', 'type': get_theme}, + {'name': 'tag', 'verbose_name': 'Теги', 'type': get_tag}, {'name': 'periodic', 'verbose_name': 'Периодичность', 'type': str}, {'name': 'web_page', 'verbose_name': 'Веб страница', 'type': str}, {'name': 'time', 'verbose_name': 'Время проведения', 'type': str}, @@ -70,7 +92,7 @@ def to_int(val): except ValueError: return None -from country.models import Country + from hvad.utils import get_translation_aware_manager def to_country(value): try: @@ -81,7 +103,7 @@ def to_country(value): return None -from city.models import City + def to_city(value, lang, country): try: # get city by name @@ -112,6 +134,30 @@ def to_audience(value): except: return 'None' + + +def to_theme(value, lang='ru'): + theme_names = value.split(', ') + theme_objects = [] + for name in theme_names: + try: + theme = Theme.objects.get(name=name) + except: + theme = Theme() + theme.translate(lang) + theme.name = name + theme.save() + + theme_objects.append(theme) + + return theme_objects + +#def to_tag(value): + + + + + import_settings={ 'name': {'func': str, }, 'url': {'func': str}, @@ -122,6 +168,7 @@ import_settings={ 'audience': {'func': to_audience}, 'country': {'func': to_country}, 'city': {'func': to_city, 'extra_values': 'country'}, + 'theme': {'func': to_theme}, 'periodic': {'func': str}, 'web_page': {'func': str}, 'time': {'func': str}, @@ -142,39 +189,4 @@ import_settings={ 'max_area': {'func': to_int}, 'is_published': {'func': bool}, 'canceled_by_administrator': {'func': bool} -} - -""" -def get_cell(field_name): - return {#'id': int(value), - 'url': str, - 'name': str, - 'data_begin': str, - 'data_end': str, - 'main_title': str, - 'description': str, - 'audience': to_audience, - 'country': to_country, - 'city': to_city, - #'periodic': str(value), - 'web_page': str, - 'time': str, - 'products': str, - 'foundation_year': to_int, - 'tax': bool, - 'currency': str, - 'max_price': to_int, - 'min_price': to_int, - 'registration_payment': to_int, - 'min_closed_area': to_int, - 'max_closed_area': to_int, - 'min_closed_equipped_area': to_int, - 'max_closed_equipped_area': to_int, - 'min_open_area': to_int, - 'max_open_area': to_int, - 'min_area': to_int, - 'max_area': to_int, - 'is_published': bool, - 'canceled_by_administrator': bool - }.get(field_name) -""" \ No newline at end of file +} \ No newline at end of file diff --git a/import_xls/views.py b/import_xls/views.py index bb72c28d..618ed9d5 100644 --- a/import_xls/views.py +++ b/import_xls/views.py @@ -18,72 +18,17 @@ def import_event(request): form = ImportEventForm() args.update(csrf(request)) args['form'] = form + if request.POST: + form = ImportEventForm(request.POST, request.FILES) if form.is_valid(): - lang = request.POST['language'] - f = form.cleaned_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[1]] - - # model - model = get_model(request.POST['event'].split('.')[0], request.POST['event'].split('.')[1]) - for row_number, row in enumerate(row_list): - - if row_number > 1: - # first two fields are verbose name and name - if row[0] != '': - object = model.objects.language(lang).get(id=row[0]) - else: - object = model() - object.translate(lang) - for col_number, cell in enumerate(row): - field_name = field_names[col_number] - setting = import_settings.get(field_name) - if setting is not None: - # if setting exist for this field - func = setting.get('func') - if func is not None: - 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) - value = func(cell, lang, getattr(object, extra_value)) - else: - value = func(cell) - - setattr(object, field_name, value) - object.save() - - """ - func = get_cell(field_names[col_number]) - if not func: - pass - else: - if field_name in relation_fields: - value = func(cell, lang) - else: - value = func(cell) - setattr(object, field_names[col_number], value) - """ - -# object.save() - else: - pass + + form.save_events() args['message'] = 'Success' return render_to_response('import_event.html', args) - - - return render_to_response('import_event.html', args) @@ -99,7 +44,12 @@ def export_event(request): if request.POST: form = ExportEventForm(request.POST) if form.is_valid(): - + workbook = form.export_events() + if workbook is None: + pass + else: + return xls_to_response(workbook, 'My Worksheet.xls') + """ data = form.cleaned_data # get model model = get_model(data['event'].split('.')[0], data['event'].split('.')[1]) @@ -148,8 +98,9 @@ def export_event(request): worksheet.write(row+2, col, field.get('type')(value)) col += 1 + """ - return xls_to_response(workbook, 'My Worksheet.xls') + #return xls_to_response(workbook, 'My Worksheet.xls') else: form = ExportEventForm() diff --git a/seminar/forms.py b/seminar/forms.py index f3602823..1d73f02f 100644 --- a/seminar/forms.py +++ b/seminar/forms.py @@ -14,7 +14,7 @@ from accounts.models import User from company.models import Company from service.models import Service #functions -from functions.translate import populate_all, fill_trans_fields_all +from functions.translate import fill_with_signal from functions.form_check import is_positive_integer from functions.files import check_tmp_files from functions.custom_fields import LocationWidget @@ -123,8 +123,7 @@ class SeminarCreateForm(forms.Form): if data.get('city'): seminar.city = City.objects.get(id=data['city']) - # uses because in the next loop data will be overwritten - seminar.save() + fill_with_signal(Seminar, seminar, data) #fill manytomany fields for item in data['theme']: seminar.theme.add(item.id)#.id cause select uses queryset @@ -132,17 +131,8 @@ class SeminarCreateForm(forms.Form): for item in data['tag']: seminar.tag.add(item) - # uses because in the next loop data will be overwritten seminar.save() - #will be saved populated fields - zero_fields = {} - #fills all translated fields with data - #if saves new object, will fill city object. otherwise existing object of City model - fill_trans_fields_all(Seminar, seminar, data, id, zero_fields) - #autopopulate - #populate empty fields and fields which was already populated - seminar_id = getattr(seminar, 'id') - populate_all(Seminar, data, seminar_id, zero_fields) + #save files check_tmp_files(seminar, data['key']) diff --git a/seminar/models.py b/seminar/models.py index 624f6fe3..f0f4bfcc 100644 --- a/seminar/models.py +++ b/seminar/models.py @@ -139,4 +139,47 @@ class Seminar(TranslatableModel): duplicate.save() - return duplicate \ No newline at end of file + return duplicate + + +from django.db.models.signals import post_save +from django.dispatch import receiver +from django.conf import settings +from functions.form_check import translit_with_separator +from functions.translate import get_translated_fields + +@receiver(post_save) +def seminar_post_save_handler(sender, **kwargs): + """ + objects saves two times: + - first time Seminar object + - second time SeminarTranslation object + object must have at least one Translation + """ + + obj = kwargs['instance'] + if isinstance(obj, Seminar): + # object is Exposition + if kwargs['created'] and obj.url == '': + # if url doesn't set in new object set it + obj.url = translit_with_separator(obj.name) + + # what languages must be + all_langs = [code for code, lang in settings.LANGUAGES] + # what languages are + obj_langs = obj.get_available_languages() + # + missing_languages = list(set(all_langs) - set(obj_langs)) + # get first Translation object + translation = obj.translations.all()[0] + # translated fields + fields = get_translated_fields(obj) + + for code in missing_languages: + # translate + obj.translate(code) + # go through all fields and set value + for field in fields: + setattr(obj, field, getattr(translation, field)) + + obj.save() \ No newline at end of file diff --git a/theme/forms.py b/theme/forms.py index 2b545984..9c301040 100644 --- a/theme/forms.py +++ b/theme/forms.py @@ -8,7 +8,7 @@ from bitfield.forms import BitFieldCheckboxSelectMultiple, BitFormField from django.conf import settings from ckeditor.widgets import CKEditorWidget -from functions.translate import fill_trans_fields, populate, ZERO_LANGUAGE, populate_all, fill_trans_fields_all +from functions.translate import fill_with_signal @@ -53,20 +53,10 @@ class ThemeForm(forms.Form): flag = reduce(lambda x,y: x|y, (getattr(Theme.types, item) for item in data['types'])) theme.types = flag - # uses because in the next loop data will be overwritten - theme.save() + fill_with_signal(Theme, theme, data) - #populate fields with zero language - zero_fields = {} - - fill_trans_fields_all(Theme, theme, data, id, zero_fields) - - #autopopulate - #populate empty fields and fields which was already populated - theme_id = getattr(theme, 'id') - populate_all(Theme, data, theme_id, zero_fields) def clean_types(self): """ @@ -115,18 +105,7 @@ class TagForm(forms.Form): if data.get('theme'): tag.theme = Theme.objects.get(id=data['theme']) - # uses because in the next loop data will be overwritten - tag.save() - - #populate fields with zero language - zero_fields = {} - - fill_trans_fields_all(Tag, tag, data, id, zero_fields) - - #autopopulate - #populate empty fields and fields which was already populated - tag_id = getattr(tag, 'id') - populate_all(Tag, data, tag_id, zero_fields) + fill_with_signal(Tag, tag, data) class ThemeDeleteForm(forms.ModelForm): diff --git a/theme/models.py b/theme/models.py index 699cb475..2cd74799 100644 --- a/theme/models.py +++ b/theme/models.py @@ -149,4 +149,42 @@ class Tag(TranslatableModel): duplicate.save() - return duplicate \ No newline at end of file + return duplicate + + +from django.db.models.signals import post_save +from django.dispatch import receiver +from django.conf import settings +from functions.translate import get_translated_fields + +@receiver(post_save) +def theme_post_save_handler(sender, **kwargs): + """ + objects saves two times: + - first time Exposition object + - second time ExpositionTranslation object + object must have at least one Translation + """ + + obj = kwargs['instance'] + if isinstance(obj, Theme) or isinstance(obj, Tag): + # object is Theme or Tag + # what languages must be + all_langs = [code for code, lang in settings.LANGUAGES] + # what languages are + obj_langs = obj.get_available_languages() + # + missing_languages = list(set(all_langs) - set(obj_langs)) + # get first Translation object + translation = obj.translations.all()[0] + # translated fields + fields = get_translated_fields(obj) + + for code in missing_languages: + # translate + obj.translate(code) + # go through all fields and set value + for field in fields: + setattr(obj, field, getattr(translation, field)) + + obj.save() \ No newline at end of file diff --git a/webinar/forms.py b/webinar/forms.py index 8cf6346b..706a579c 100644 --- a/webinar/forms.py +++ b/webinar/forms.py @@ -16,7 +16,7 @@ from functions.form_check import translit_with_separator #functions -from functions.translate import populate_all, fill_trans_fields_all +from functions.translate import fill_with_signal from functions.form_check import is_positive_integer class WebinarCreateForm(forms.Form): @@ -108,8 +108,7 @@ class WebinarCreateForm(forms.Form): webinar.tax = data['tax'] webinar.min_price = data['min_price'] webinar.max_price = data['max_price'] - # uses because in the next loop data will be overwritten - webinar.save() + fill_with_signal(Webinar, webinar, data) #fill manytomany fields for item in data['theme']: webinar.theme.add(item) @@ -119,15 +118,7 @@ class WebinarCreateForm(forms.Form): # uses because in the next loop data will be overwritten webinar.save() - #will be saved populated fields - zero_fields = {} - #fills all translated fields with data - #if saves new object, will fill city object. otherwise existing object of City model - fill_trans_fields_all(Webinar, webinar, data, id, zero_fields) - #autopopulate - #populate empty fields and fields which was already populated - webinar_id = getattr(webinar, 'id') - populate_all(Webinar, data, webinar_id, zero_fields) + #save files check_tmp_files(webinar, data['key']) diff --git a/webinar/models.py b/webinar/models.py index 466a3a06..a89ab002 100644 --- a/webinar/models.py +++ b/webinar/models.py @@ -136,4 +136,47 @@ class Webinar(TranslatableModel): duplicate.save() - return duplicate \ No newline at end of file + return duplicate + + +from django.db.models.signals import post_save +from django.dispatch import receiver +from django.conf import settings +from functions.form_check import translit_with_separator +from functions.translate import get_translated_fields + +@receiver(post_save) +def webinar_post_save_handler(sender, **kwargs): + """ + objects saves two times: + - first time Webinar object + - second time WebinarTranslation object + object must have at least one Translation + """ + + obj = kwargs['instance'] + if isinstance(obj, Webinar): + # object is Exposition + if kwargs['created'] and obj.url == '': + # if url doesn't set in new object set it + obj.url = translit_with_separator(obj.name) + + # what languages must be + all_langs = [code for code, lang in settings.LANGUAGES] + # what languages are + obj_langs = obj.get_available_languages() + # + missing_languages = list(set(all_langs) - set(obj_langs)) + # get first Translation object + translation = obj.translations.all()[0] + # translated fields + fields = get_translated_fields(obj) + + for code in missing_languages: + # translate + obj.translate(code) + # go through all fields and set value + for field in fields: + setattr(obj, field, getattr(translation, field)) + + obj.save() \ No newline at end of file