create functiton that fill translated fields when model has signal for it

remotes/origin/1203
Nazar Kotjuk 12 years ago
parent 0efd66e73a
commit 1c04be5964
  1. 22
      city/forms.py
  2. 3
      city/models.py
  3. 42
      country/forms.py
  4. 42
      country/models.py
  5. 50
      exposition/models.py
  6. 38
      functions/translate.py
  7. 112
      import_xls/excel_settings.py
  8. 84
      import_xls/views.py
  9. 7
      templates/admin/import templates/import_event.html

@ -9,7 +9,7 @@ from models import City
from country.models import Country
from directories.models import Iata
#functions
from functions.translate import fill_trans_fields_all, populate_all
from functions.translate import fill_trans_fields_all, populate_all, fill_with_signal
from functions.form_check import is_positive_integer, translit_with_separator
from functions.files import check_tmp_files
@ -84,26 +84,16 @@ class CityForm(forms.Form):
city.phone_code = data['phone_code']
city.population = data['population']
if data.get('code_IATA'):
city.code_IATA = Iata.objects.get(id=data['code_IATA'].id)#.id cause select uses queryset
if data.get('country'):
city.country = Country.objects.get(id=data['country'].id)#.id cause select uses queryset
# uses because in the next loop data will be overwritten
# url generate for city: "country_name-city_name"
city.url = '%s-'%translit_with_separator(city.country.name) + translit_with_separator(data['name_ru']).lower()
city.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(City, city, data, id, zero_fields)
#autopopulate
#populate empty fields and fields which was already populated
city_id = getattr(city, 'id')
populate_all(City, data, city_id, zero_fields)
# fill translated fields and save object
fill_with_signal(City, city, data)
#save files
check_tmp_files(city, data['key'])

@ -91,5 +91,6 @@ def city_post_save_handler(sender, **kwargs):
print('trans')
if obj.language_code == 'ru':
city = City.objects.get(id=obj.master_id)
city.url = translit_with_separator(obj.name)
country = city.country
city.url = '%s-%s'%(translit_with_separator(country.name), translit_with_separator(obj.name))
city.save()

@ -8,7 +8,7 @@ from django.forms.util import ErrorList
from models import Country, City
from directories.models import Language, Currency, Iata
#functions
from functions.translate import populate_all, fill_trans_fields_all
from functions.translate import fill_with_signal
from functions.files import check_tmp_files
from functions.form_check import is_positive_integer, translit_with_separator
@ -130,38 +130,6 @@ class CountryForm(forms.Form):
country.language.clear()
country.currency.clear()
all_langs = [code for code, lang in settings.LANGUAGES]
# fields in translations model that doesn't need
bad_fields = ['id', 'language_code', 'master_id']
# translated fields
fields = [field.name for field in Country.translations.related.editable_fields() if field.name not in bad_fields]
# translate to first language(require)
if not id:
country.translate(all_langs[0])
# go through all fields and set value
for field in fields:
setattr(country, field, data.get('%s_%s'%(field, all_langs[0])))
# first save method call signal that fill require language to all translated fields
country.save()
else:
# require translation. uses for substitution unfilled form fields
require_transl = Country._meta.translations_model.objects.get(language_code = all_langs[0],master__id=getattr(country, 'id'))
for code in all_langs[1:]:
# fill translation objects
# start from second language
obj = Country._meta.translations_model.objects.get(language_code = code,master__id=getattr(country, 'id'))
for field in fields:
val = data.get('%s_%s'%(field, code))
if val == '':
# get value from require translation
setattr(obj, field, getattr(require_transl, field))
else:
setattr(obj, field, val)
obj.save()
country.url = translit_with_separator(data['name_ru']).lower()
country.population = data['population']
@ -173,9 +141,8 @@ class CountryForm(forms.Form):
if data.get('capital'):
country.capital = City.objects.get(id=data['capital'])
# uses because in the next loop data will be overwritten
country.save()
# fill translated fields and save object
fill_with_signal(Country, country, data)
#fill manytomany fields
for item in data['language']:
@ -187,10 +154,7 @@ class CountryForm(forms.Form):
for item in data['currency']:
country.currency.add(item.id)#.id cause select uses queryset
# uses because in the next loop data will be overwritten
country.save()
#save files
check_tmp_files(country, data['key'])

@ -66,23 +66,11 @@ class Country(TranslatableModel):
)
"""
def __init__(self, **kwargs):
name = kwargs.get('name')
if name:
for code, language in settings.LANGUAGES:
self.translate(code)
self.name = name
else:
pass
"""
def __unicode__(self):
return self.lazy_translation_getter('name', unicode(self.pk))
from django.db.models.signals import pre_save, post_save
#from models import Country
from django.db.models.signals import post_save
from models import Country
from django.dispatch import receiver
from django.conf import settings
from functions.form_check import translit_with_separator
@ -90,7 +78,7 @@ from functions.form_check import translit_with_separator
from functions.translate import get_translated_fields
@receiver(post_save)
@receiver(post_save, sender=Country)
def country_post_save_handler(sender, **kwargs):
"""
objects saves two times:
@ -120,30 +108,10 @@ def country_post_save_handler(sender, **kwargs):
setattr(obj, field, getattr(translation, field))
obj.save()
if isinstance(obj, CountryTranslation):
# object is Translation
print('success')
if obj.language_code == 'ru':
country = Country.objects.get(id=obj.master_id)
country.url = translit_with_separator(obj.name)
country.save()
#if not obj.url:
# obj.url = translit_with_separator(obj.name)
# obj.save()
"""
if kwargs['created']:
print(obj.name)
if not obj.url:
obj.url = translit_with_separator(obj.name)
obj.save()
"""
"""
if not obj.title:
# len(10) is a hack for detect if settings.LANGUAGES is not configured it return all langs
if len(settings.LANGUAGES) in range(10):
for code, name in settings.LANGUAGES:
obj.translate(code)
obj.title = '111'
obj.save()
"""
country.save()

@ -171,4 +171,52 @@ class TimeTable(TranslatableModel):
#translated fields
translations = TranslatedFields(
name = models.CharField(verbose_name='Название', max_length=255)
)
)
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 exposition_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, Exposition):
# object is Exposition
# 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]
#
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()
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()

@ -91,6 +91,44 @@ def populate_all(Model, data={}, id=None, zero_fields={}):
obj.save()
def fill_with_signal(model, obj, data):
all_langs = [code for code, lang in settings.LANGUAGES]
# fields in translations model that doesn't need
bad_fields = ['id', 'language_code', 'master_id']
# translated fields
fields = [field.name for field in model.translations.related.editable_fields() if field.name not in bad_fields]
# translate to first language(require)
if not obj.id:
# new object
# translate into first language
obj.translate(all_langs[0])
# go through all fields and set value
for field in fields:
setattr(obj, field, data.get('%s_%s'%(field, all_langs[0])))
# first save method call signal that fill require language to all translated fields
obj.save()
# require translation. uses for substitution unfilled form fields
require_transl = model._meta.translations_model.objects.get(language_code = all_langs[0],master__id=getattr(obj, 'id'))
for code in all_langs[1:]:
# fill translation objects
# start from second language
trans_obj = model._meta.translations_model.objects.get(language_code = code,master__id=getattr(obj, 'id'))
for field in fields:
val = data.get('%s_%s'%(field, code))
if val == '':
# get value from require translation
setattr(trans_obj, field, getattr(require_transl, field))
else:
setattr(trans_obj, field, val)
trans_obj.save()
def get_translated_fields(obj, exclude_fields=[]):
"""
get translated fields

@ -59,6 +59,7 @@ field_settings = [
def to_int(val):
"""
Reverse function to get_int
@ -81,7 +82,7 @@ def to_country(value):
from city.models import City
def to_city(value, lang=None, country=None):
def to_city(value, lang, country):
try:
# get city by name
objects = get_translation_aware_manager(City)
@ -91,18 +92,12 @@ def to_city(value, lang=None, country=None):
except IndexError:
# not found
# try to create new city
city = City()
city = City(country=country)
city.translate(lang)
city.name = value
city.save()
return city
AUDIENCE1 = ((None,'Не выбрано'),
('experts', 'Специалисты'),
('experts and consumers', 'Специалисты и потребители'),
('general public', 'Широкая публика'))
return city
def to_audience(value):
try:
@ -113,40 +108,73 @@ def to_audience(value):
elif value == 'Широкая публика':
return 'general public'
else:
return ''
return 'None'
except:
return ''
def get_cell(field_name, value, lang=None):
return 'None'
import_settings={
'name': {'func': str, },
'url': {'func': str},
'data_begin': {'func': str},
'data_end': {'func': str},
'main_title': {'func': str},
'description': {'func': str},
'audience': {'func': to_audience},
'country': {'func': to_country},
'city': {'func': to_city, 'extra_values': 'country'},
'periodic': {'func': str},
'web_page': {'func': str},
'time': {'func': str},
'products': {'func': str},
'foundation_year': {'func': to_int},
'tax': {'func': bool},
'currency': {'func': str},
'max_price': {'func': to_int},
'min_price': {'func': to_int},
'registration_payment': {'func': to_int},
'min_closed_area': {'func': to_int},
'max_closed_area': {'func': to_int},
'min_closed_equipped_area': {'func': to_int},
'max_closed)equipped_area': {'func': to_int},
'min_open_area': {'func': to_int},
'max_open_area': {'func': to_int},
'min_area': {'func': to_int},
'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(value),
'name': str(value),
'data_begin': str(value),
'data_end': str(value),
'main_title': str(value),
'description': str(value),
'audience': to_audience(value),
'country': to_country(value),
'city': to_city(value, lang=lang),
'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(value),
'time': str(value),
'products': str(value),
'foundation_year': to_int(value),
'tax': bool(value),
'currency': str(value),
'max_price': to_int(value),
'min_price': to_int(value),
'registration_payment': to_int(value),
'min_closed_area': to_int(value),
'max_closed_area': to_int(value),
'min_closed_equipped_area': to_int(value),
'max_closed_equipped_area': to_int(value),
'min_open_area': to_int(value),
'max_open_area': to_int(value),
'min_area': to_int(value),
'max_area': to_int(value),
'is_published': bool(value),
'canceled_by_administrator': bool(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)
"""

@ -9,45 +9,9 @@ import xlwt
import xlrd
#
from custom_forms import ImportEventForm, ExportEventForm
from excel_settings import field_settings, get_cell
"""
import_settings = [
{'name': 'id'},
{'name': 'url'},
{'name': 'name'},
{'name': 'data_begin'},
{'name': 'data_end'},
{'name': 'main_title'},
{'name': 'description'},
{'name': 'audience'},
{'name': 'country'},
{'name': 'city'},
{'name': 'periodic'},
{'name': 'web_page'},
{'name': 'time'},
{'name': 'products'},
{'name': 'foundation_year'},
{'name': 'tax'},
{'name': 'currency'},
{'name': 'max_price'},
{'name': 'min_price'},
{'name': 'registration_payment'},
{'name': 'min_closed_area'},
{'name': 'max_closed_area'},
{'name': 'min_closed_equipped_area'},
{'name': 'max_closed_equipped_area'},
{'name': 'min_open_area'},
{'name': 'max_open_area'},
{'name': 'min_area'},
{'name': 'max_area'},
{'name': 'is_published'},
{'name': 'canceled_by_administrator'}
]
"""
from excel_settings import field_settings, import_settings
relation_fields = ['city']
@login_required
def import_event(request):
args = {}
@ -57,6 +21,7 @@ def import_event(request):
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)
@ -67,18 +32,49 @@ def import_event(request):
# model
model = get_model(request.POST['event'].split('.')[0], request.POST['event'].split('.')[1])
for row_number, row in enumerate(row_list):
# first two fields are verbose name and name
if row_number > 1:
object = model.objects.language(request.POST['language']).get(id=row[0])
# 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):
value = get_cell(field_names[col_number], cell, request.POST['language'])
#
if not value:
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()
# object.save()
else:
pass

@ -32,7 +32,14 @@
</div>
</div>
<div class="alert">
<p>Поле id менять для редактирования старого события</p>
<hr>
<p>Для создания нового события оставить поле id пустым</p>
<hr>
<p>Город должен быть после страны, а тег после тематики</p>
</div>
<div class="controls">
<input class="btn btn-large btn-primary" type="submit" value="Импорт">
<input class="btn btn-large" type="reset" value="Отмена">

Loading…
Cancel
Save