owerwrite all

remotes/origin/1203
Nazar Kotyuk 12 years ago
parent 11cccfafdc
commit 9f520b7140
  1. 6
      accounts/admin_urls.py
  2. 4
      accounts/forms.py
  3. 36
      accounts/models.py
  4. 14
      accounts/search_indexes.py
  5. 20
      article/models.py
  6. 2
      article/signals.py
  7. 1
      city/admin.py
  8. 28
      city/forms.py
  9. 39
      city/models.py
  10. 5
      city/signals.py
  11. 13
      company/forms.py
  12. 64
      company/models.py
  13. 2
      company/signals.py
  14. 10
      company/urls.py
  15. 22
      company/views.py
  16. 56
      conference/admin.py
  17. 108
      conference/forms.py
  18. 100
      conference/models.py
  19. 2
      conference/signals.py
  20. 15
      conference/urls.py
  21. 70
      conference/views.py
  22. 0
      core/__init__.py
  23. 3
      core/models.py
  24. 16
      core/tests.py
  25. 77
      core/views.py
  26. 16
      country/admin.py
  27. 20
      country/forms.py
  28. 36
      country/models.py
  29. 8
      country/signals.py
  30. 99
      exposition/admin.py
  31. 262
      exposition/forms.py
  32. 215
      exposition/models.py
  33. 15
      exposition/search_indexes.py
  34. 2
      exposition/signals.py
  35. 18
      exposition/urls.py
  36. 118
      exposition/views.py
  37. 2
      file/forms.py
  38. 2
      file/models.py
  39. 4
      functions/__init__.py
  40. 3
      functions/custom_fields.py
  41. 156
      functions/custom_views.py
  42. 30
      functions/files.py
  43. 2
      functions/form_check.py
  44. 18
      functions/forms.py
  45. 61
      functions/model_mixin.py
  46. 27
      functions/models_methods.py
  47. 9
      functions/signal_additional_func.py
  48. 42
      functions/signal_handlers.py
  49. 13
      functions/views_help.py
  50. 111
      import_xls/admin.py
  51. 25
      import_xls/admin_urls.py
  52. 221
      import_xls/excel_settings.py
  53. 172
      import_xls/export_forms.py
  54. 237
      import_xls/import_forms.py
  55. 64
      import_xls/views.py
  56. BIN
      media/imgs/.jpg
  57. BIN
      media/imgs/cl-logo-1.png
  58. BIN
      media/imgs/cl-logo-1_1.png
  59. BIN
      media/imgs/cl-logo-1_2.png
  60. BIN
      media/imgs/cl-logo-1_3.png
  61. BIN
      media/imgs/cl-logo-1_4.png
  62. BIN
      media/imgs/cl-logo-1_5.png
  63. BIN
      media/imgs/cl-logo-2.png
  64. BIN
      media/imgs/cl-logo-2_1.1.png
  65. BIN
      media/imgs/cl-logo-2_1.png
  66. BIN
      media/imgs/cl-logo-3.png
  67. BIN
      media/imgs/cl-logo-3_5.1.png
  68. BIN
      media/imgs/cl-logo-3_5.2.png
  69. BIN
      media/imgs/cl-logo-3_5.png
  70. BIN
      media/imgs/mp-phg-1.png
  71. BIN
      media/imgs/part-logo-1.png
  72. BIN
      media/imgs/part-logo-1_1.png
  73. BIN
      media/imgs/pl-logo-2.png
  74. BIN
      media/js/tiny_mce/plugins/emoticons/img/smiley-cool.gif
  75. BIN
      media/js/tiny_mce/plugins/emoticons/img/smiley-cry.gif
  76. BIN
      media/js/tiny_mce/plugins/emoticons/img/smiley-embarassed.gif
  77. BIN
      media/js/tiny_mce/plugins/emoticons/img/smiley-foot-in-mouth.gif
  78. BIN
      media/js/tiny_mce/plugins/emoticons/img/smiley-frown.gif
  79. BIN
      media/js/tiny_mce/plugins/emoticons/img/smiley-innocent.gif
  80. BIN
      media/js/tiny_mce/plugins/emoticons/img/smiley-kiss.gif
  81. BIN
      media/js/tiny_mce/plugins/emoticons/img/smiley-laughing.gif
  82. BIN
      media/js/tiny_mce/plugins/emoticons/img/smiley-money-mouth.gif
  83. BIN
      media/js/tiny_mce/plugins/emoticons/img/smiley-sealed.gif
  84. BIN
      media/js/tiny_mce/plugins/emoticons/img/smiley-smile.gif
  85. BIN
      media/js/tiny_mce/plugins/emoticons/img/smiley-surprised.gif
  86. BIN
      media/js/tiny_mce/plugins/emoticons/img/smiley-tongue-out.gif
  87. BIN
      media/js/tiny_mce/plugins/emoticons/img/smiley-undecided.gif
  88. BIN
      media/js/tiny_mce/plugins/emoticons/img/smiley-wink.gif
  89. BIN
      media/js/tiny_mce/plugins/emoticons/img/smiley-yell.gif
  90. BIN
      media/js/tiny_mce/skins/lightgray/img/anchor.gif
  91. BIN
      media/js/tiny_mce/skins/lightgray/img/loader.gif
  92. BIN
      media/js/tiny_mce/skins/lightgray/img/object.gif
  93. BIN
      media/js/tiny_mce/skins/lightgray/img/trans.gif
  94. BIN
      media/js/tiny_mce/skins/lightgray/img/wline.gif
  95. BIN
      media/tmp_files/.jpg
  96. BIN
      media/tmp_files/cl-logo-1.png
  97. BIN
      media/tmp_files/cl-logo-1_1.png
  98. BIN
      media/tmp_files/cl-logo-1_2.png
  99. BIN
      media/tmp_files/cl-logo-2.png
  100. BIN
      media/tmp_files/cl-logo-3.png
  101. Some files were not shown because too many files have changed in this diff Show More

@ -2,9 +2,9 @@
from django.conf.urls import patterns, url
urlpatterns = patterns('',
url(r'^registration/$', 'accounts.admin.registration'),
url(r'^create_admin/$', 'accounts.admin.create_admin'),
url(r'^create_md5user/$', 'accounts.admin.create_md5'),
#url(r'^registration/$', 'accounts.admin.registration'),
#url(r'^create_admin/$', 'accounts.admin.create_admin'),
#url(r'^create_md5user/$', 'accounts.admin.create_md5'),
url(r'^change/(.*)/$', 'accounts.admin.user_change'),
# url(r'^change/(?P<user_id>\d+).*/$', 'accounts.views.user_change'),
url(r'^all/$', 'accounts.admin.user_all'),

@ -58,7 +58,7 @@ class UserChangeForm(forms.ModelForm):
return self.initial['password']
class UserForm(forms.ModelForm):
email = forms.EmailField(widget=forms.TextInput(attrs={'disabled' : True}))
email = forms.EmailField(widget=forms.TextInput(attrs={'disabled' : True}), required=False)
country = forms.ModelChoiceField(label='Страна', queryset=Country.objects.all(), empty_label=None, required=False)
city = forms.ModelChoiceField(label='Город', queryset=City.objects.all(), empty_label='', required=False)
company = forms.ModelChoiceField(label='Компания', queryset=Company.objects.all(), empty_label='', required=False)
@ -153,7 +153,7 @@ class ChangePasswordForm(forms.Form):
return data
class EmailAnnouncementForm(forms.Form):
data = [(1, _(u'Получать приглашения, сообщения и другю корреспонденцию от пользователей Expomap')),
data = [(1, _(u'Получать приглашения, сообщения и другую корреспонденцию от пользователей Expomap')),
(2, _(u'Получать обзор событий')),
(3, _(u'Получать новости'))]
announcement = forms.MultipleChoiceField(choices=data, widget=forms.CheckboxSelectMultiple())

@ -4,10 +4,11 @@ from hvad.models import TranslatableModel, TranslatedFields
from django.contrib.auth.models import BaseUserManager, AbstractBaseUser, PermissionsMixin
from django.core.mail import send_mail
from django.utils import timezone
from django.utils.translation import ugettext as _
from django.db.models.signals import post_save
#custom functions
from functions.form_check import translit_with_separator
from functions.translate import fill_trans_fields_all, populate_all
"""
from django.contrib.auth.hashers import check_password
@ -70,7 +71,7 @@ class User(AbstractBaseUser, PermissionsMixin):
"""
email = models.EmailField(
verbose_name = 'Электронная почта',
verbose_name = u'Электронная почта',
max_length = 255,
unique = True,
db_index = True,
@ -100,15 +101,16 @@ class User(AbstractBaseUser, PermissionsMixin):
on_delete=models.PROTECT)
company = models.ForeignKey('company.Company', blank=True, null=True, on_delete=models.PROTECT, related_name='users')
#other user information
phone = models.PositiveIntegerField(verbose_name='Телефон', blank=True, null=True)
# other user information
phone = models.BigIntegerField(verbose_name='Телефон', blank=True, null=True)
position = models.CharField(verbose_name='Должность', max_length=255, blank=True)
about = models.TextField(verbose_name='О себе', blank=True)
avatar = models.ImageField(verbose_name='Фото', upload_to='/accounts/avatar/', blank=True)
web_page = models.CharField(verbose_name='Вебсайт', max_length=255, blank=True)
social = models.TextField(verbose_name='Социальные страници', blank=True)
social = models.TextField(verbose_name='Социальные страницы', blank=True)
skype = models.CharField(blank=True, max_length=50)
#meta
# meta
title = models.CharField(max_length=255, blank=True)
descriptions = models.CharField(max_length=255, blank=True)
keywords = models.CharField(max_length=255, blank=True)
@ -149,6 +151,28 @@ class User(AbstractBaseUser, PermissionsMixin):
def has_module_perms(self, app_label):
return True
def get_events_number(self):
expositions = self.exposition_users.all()
conferences = self.conference_users.all()
seminars = self.seminar_users.all()
webinars = self.webinar_users.all()
return len(list(expositions)+list(conferences)+list(seminars)+list(webinars))
class Calendar(models.Model):
user = models.OneToOneField(User)
expositions = models.ManyToManyField('exposition.Exposition', null=True)
conferences = models.ManyToManyField('conference.Conference', null=True)
seminars = models.ManyToManyField('seminar.Seminar', null=True)
webinars = models.ManyToManyField('webinar.Webinar', null=True)
def create_user_calendar(sender, instance, created, **kwargs):
if created:
Calendar.objects.create(user=instance)
post_save.connect(create_user_calendar, sender=User)
#need import after User Model, because User imported in "organiser.models"
from organiser.models import Organiser

@ -0,0 +1,14 @@
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')
def get_model(self):
return User
def index_queryset(self, using=None):
return self.get_model().objects.all()

@ -58,9 +58,19 @@ class Article(TranslatableModel):
#already has copy this instance
return
ignore_fields = ['id', 'master', 'language_code']
duplicate.translate('ru')
tr = self._meta.translations_model.objects.get(language_code = 'ru',master__id=self.pk)
for field in duplicate._translated_field_names:
if field in ignore_fields:
continue
setattr(duplicate, field, getattr(tr, field))
duplicate.save()
# but lost all ManyToMany relations and Translations.
'''
# copy relations
for field in self._meta.many_to_many:
source = getattr(self, field.attname)
@ -83,5 +93,11 @@ class Article(TranslatableModel):
setattr(duplicate, field, getattr(tr, field))
duplicate.save()
'''
return duplicate
from django.db.models.signals import post_save
from functions.signal_handlers import post_save_handler
return duplicate
post_save.connect(post_save_handler, sender=Article)

@ -3,4 +3,4 @@ from django.db.models.signals import post_save
from models import Article
from functions.signal_handlers import post_save_handler
post_save.connect(post_save_handler, sender=Article)
#post_save.connect(post_save_handler, sender=Article)

@ -67,6 +67,7 @@ def city_change(request, url):
for code, name in settings.LANGUAGES:
obj = City._meta.translations_model.objects.get(language_code = code,master__id=city_id) #access to translated fields
data['name_%s' % code] = obj.name
data['region_%s' % code] = obj.region
data['description_%s' % code] = obj.description
data['famous_places_%s' % code] = obj.famous_places
data['shoping_%s' % code] = obj.shoping

@ -4,6 +4,7 @@ from django.conf import settings
from ckeditor.widgets import CKEditorWidget
from django.core.exceptions import ValidationError
from django.forms.util import ErrorList
from django.utils.translation import get_language as lang
#models
from models import City
from country.models import Country
@ -23,13 +24,14 @@ class CityForm(forms.Form):
save function saves data in City object. If it doesnt exist create new object
"""
country = forms.ModelChoiceField(label='Страна', queryset=Country.objects.all(), empty_label=None)
country = forms.ModelChoiceField(label='Страна',
queryset=Country.objects.filter(translations__language_code=lang()).order_by('translations__name'),
empty_label=None)
population = forms.CharField(label='Население', required=False,
widget=forms.TextInput(attrs={'placeholder':'Население'}))
phone_code = forms.CharField(label='Код города', required=False,
widget=forms.TextInput(attrs={'placeholder':'Код города'}))
code_IATA = forms.ModelChoiceField(label='Код IATA', queryset=Iata.objects.all(), empty_label=None, required=False)
country = forms.ModelChoiceField(label='Страна', queryset=Country.objects.all(), empty_label=None)
#field for comparing tmp files
key = forms.CharField(required=False, widget=forms.HiddenInput())
#
@ -49,6 +51,7 @@ class CityForm(forms.Form):
# first iteration is a default lang so it required fields
required = True if lid == 0 else False
self.fields['name_%s' % code] = forms.CharField(label='Название', required=required)
self.fields['region_%s' % code] = forms.CharField(label='Регион', required=False)
self.fields['description_%s' % code] = forms.CharField(label='Описание',
required=False, widget=CKEditorWidget)
self.fields['famous_places_%s' % code] = forms.CharField(label='Знаменитые места',
@ -79,20 +82,28 @@ class CityForm(forms.Form):
else:
city = City()
city.phone_code = data.get('phone_code')
city.phone_code = data['phone_code']
city.population = data.get('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
city.country = data['country']# .id cause select uses queryset
#city.country = Country.objects.get(id=data['country'].id)# .id cause select uses queryset
# url generate for city: "country_name-city_name"
city.url = '%s-'%translit_with_separator(city.country.name) + translit_with_separator(data['name_ru']).lower()
if data.get('name_en'):
city.url = '%s-'%translit_with_separator(city.country.name) + translit_with_separator(data['name_en']).lower()
else:
city.url = '%s-'%translit_with_separator(city.country.name) + translit_with_separator(data['name_ru']).lower()
#city.url = '%s'%translit_with_separator(data['name_ru'].strip()).lower()
#city.save()
# fill translated fields and save object
fill_with_signal(City, city, data)
city.save()
# save files
check_tmp_files(city, data['key'])
@ -100,11 +111,16 @@ class CityForm(forms.Form):
def clean(self):
id = self.cleaned_data.get('city_id')
name_ru = self.cleaned_data.get('name_ru')
name_en = self.cleaned_data.get('name_en')
country = self.cleaned_data.get('country')
city = City.objects.filter(
url='%s-%s'%(translit_with_separator(country.name), translit_with_separator(name_ru))
url='%s-%s'%(translit_with_separator(country.name), translit_with_separator(name_en))
)
if not city:
city = City.objects.filter(
url='%s-%s'%(translit_with_separator(country.name), translit_with_separator(name_ru))
)
if city and str(city[0].id) != id:
msg = 'Город с таким названием уже существует'
self._errors['name_ru'] = ErrorList([msg])

@ -1,22 +1,22 @@
# -*- coding: utf-8 -*-
from django.db import models
from django.db.models.signals import post_save, pre_save
from django.dispatch import receiver
from hvad.models import TranslatableModel, TranslatedFields
from hvad.models import TranslatableModel, TranslatedFields, TranslationManager
from bitfield import BitField
# my models
# models
from directories.models import Iata
from service.models import Service
from settings.models import Setting
# custom dunctions
# custom functions
from functions.db import db_table_exists
from functions.form_check import translit_with_separator
from functions.signal_additional_func import fill_missing_languages, fill_meta_information
from functions.signal_handlers import post_save_handler
from functions.models_methods import ExpoManager
#check if table exist and create flags if true
flags = [str(item.id) for item in Service.objects.all()] if db_table_exists('service_service') else []
class City(TranslatableModel):
"""
Create City model
@ -24,6 +24,7 @@ class City(TranslatableModel):
Uses hvad.TranslatableModel which is child of django.db.models class
"""
objects = ExpoManager()
services = BitField(flags=flags)
@ -37,6 +38,7 @@ class City(TranslatableModel):
#translated fields
translations = TranslatedFields(
name = models.CharField(max_length=50),
region = models.CharField(max_length=255),
transport = models.TextField(blank=True),
description = models.TextField(blank=True),
famous_places = models.TextField(blank=True),
@ -54,25 +56,6 @@ class City(TranslatableModel):
return self.lazy_translation_getter('name', self.pk)
@receiver(post_save)
def city_post_save_handler(sender, **kwargs):
"""
objects saves two times:
- first time Country object
- second time CountryTranslation object
object must have at least one Translation
"""
obj = kwargs['instance']
if isinstance(obj, City):
fill_missing_languages(obj)
fill_meta_information(obj)
"""
if isinstance(obj, CityTranslation):
# object is Translation - set url
if obj.language_code == 'ru':
city = City.objects.get(id=obj.master_id)
country = city.country
city.url = '%s-%s'%(translit_with_separator(country.name), translit_with_separator(obj.name))
city.save()
"""
post_save.connect(post_save_handler, sender=City)

@ -1,8 +1,3 @@
# -*- coding: utf-8 -*-
from django.db.models.signals import post_save
from models import City
from functions.signal_handlers import post_save_handler
post_save.connect(post_save_handler, sender=City)

@ -4,6 +4,7 @@ from django.conf import settings
from ckeditor.widgets import CKEditorWidget
from django.core.exceptions import ValidationError
from django.forms.util import ErrorList
from django.core.validators import validate_email, URLValidator
#models
from models import Company
from country.models import Country
@ -155,14 +156,14 @@ class CompanyForm(forms.Form):
cleaned_data = super(CompanyForm, self).clean()
web_page = cleaned_data.get('web_page')
if not web_page:
return web_page
return ''
import socket
validate = URLValidator()
try:
socket.getaddrinfo(web_page, 80)
return web_page
except:
return forms.ValidationError('Введите правильный адрес страници')
validate(web_page)
except(ValidationError),e:
raise ValidationError(e.messages[0])
return web_page
def clean_phone(self):
"""

@ -1,31 +1,29 @@
# -*- coding: utf-8 -*-
from django.db import models
from hvad.models import TranslatableModel, TranslatedFields, TranslationManager
from django.contrib.contenttypes import generic
#
from functions.custom_fields import LocationField
from functions.models_methods import ExpoManager
from functions.model_mixin import ExpoMixin
class CompanyManager(TranslationManager):
def safe_get(self, **kwargs):
model = self.model
try:
return model.objects.get(**kwargs)
except:
return None
class Company(TranslatableModel):
class Company(TranslatableModel, ExpoMixin):
"""
Create Company model
Uses hvad.TranslatableModel which is child of django.db.models class
"""
objects = CompanyManager()
objects = ExpoManager()
files = generic.GenericRelation('file.FileModel', content_type_field='content_type', object_id_field='object_id')
url = models.SlugField()
#relations
creator = models.ForeignKey('accounts.User', verbose_name='Создатель', related_name='created_company')
creator = models.ForeignKey('accounts.User', verbose_name='Создатель', related_name='created_company',
blank=True, null=True)
theme = models.ManyToManyField('theme.Theme', verbose_name='Отрасль',
blank=True, null=True, related_name='companies')
tag = models.ManyToManyField('theme.Tag', verbose_name='Теги', blank=True, null=True, related_name='companies')
@ -37,14 +35,14 @@ class Company(TranslatableModel):
address = LocationField(verbose_name='Адрес', blank=True)
staff_number = models.CharField(verbose_name='Количество сотрудников', max_length=50, blank=True)
phone = models.FloatField(verbose_name='Телефон', blank=True, null=True)
fax = models.FloatField(verbose_name='Факс', blank=True, null=True)
phone = models.BigIntegerField(verbose_name='Телефон', blank=True, null=True)
fax = models.BigIntegerField(verbose_name='Факс', blank=True, null=True)
web_page = models.CharField(verbose_name='Веб-сайт',max_length=255, blank=True)
email = models.EmailField(verbose_name='Email', blank=True)
social = models.TextField(verbose_name='Социальные страници', blank=True)
foundation = models.PositiveIntegerField(verbose_name='Год основания', blank=True, null=True)
#translation fields
translation = TranslatedFields(
translations = TranslatedFields(
name = models.CharField(verbose_name='Название компании', max_length=255),
specialization = models.CharField(verbose_name='Специализация', max_length=255, blank=True),
description = models.TextField(verbose_name='О компании', blank=True),
@ -60,4 +58,42 @@ class Company(TranslatableModel):
def __unicode__(self):
return self.lazy_translation_getter('name', self.pk)
return self.lazy_translation_getter('name', self.pk)
def get_catalog_url(self):
return '/members/'
def get_permanent_url(self):
url = '%smember-%s'%(self.get_catalog_url(), self.url)
return url
def get_expositions_number(self):
return len(self.exposition_companies.all())
def get_conferences_number(self):
return len(self.conference_companies.all())
def get_seminars_number(self):
return len(self.seminar_companies.all())
def get_webinars_number(self):
return len(self.webinar_companies.all())
def get_events_number(self):
expositions = self.exposition_companies.all()
conferences = self.conference_companies.all()
seminars = self.seminar_companies.all()
webinars = self.webinar_companies.all()
return len(list(expositions)+list(conferences)+list(seminars)+list(webinars))
def get_events(self):
expositions = self.exposition_companies.all()
conferences = self.conference_companies.all()
seminars = self.seminar_companies.all()
webinars = self.webinar_companies.all()
return list(expositions)+ list(conferences)+list(seminars)+list(webinars)
from django.db.models.signals import post_save
from functions.signal_handlers import post_save_handler
post_save.connect(post_save_handler, sender=Company)

@ -3,4 +3,4 @@ from django.db.models.signals import post_save
from models import Company
from functions.signal_handlers import post_save_handler
post_save.connect(post_save_handler, sender=Company)
#post_save.connect(post_save_handler, sender=Company)

@ -0,0 +1,10 @@
# -*- coding: utf-8 -*-
from django.conf.urls import patterns, url
from views import CompanyView
urlpatterns = patterns('',
url(r'members/(?P<params>.*)/(?P<page>\d+)/$', CompanyView.as_view()),
url(r'members/(?P<page>\d+)/$', CompanyView.as_view()),
url(r'members/(?P<params>.*)/$', CompanyView.as_view()),
url(r'members/$', CompanyView.as_view()),
)

@ -0,0 +1,22 @@
# -*- coding: utf-8 -*-
from django.http import HttpResponse
from models import Company
from functions.custom_views import ExpoListView
import json
class CompanyView(ExpoListView):
model = Company
template_name = 'company_catalog.html'
class CompanyExposition(CompanyView):
template_name = 'test_list.html'
def get_queryset(self):
params = self.get_params()
for param in params:
if param.get('type') == 'event':
company = Company.objects.safe_get(url=param.get('url'))
#query = exp.users
self.params = params
return company.exposition_companies.all()

@ -8,8 +8,8 @@ from django.forms.models import modelformset_factory
from django.contrib.contenttypes.models import ContentType
from django.contrib.auth.decorators import login_required
#models and forms
from models import Conference, TimeTable
from forms import ConferenceChangeForm, ConferenceCreateForm, ConferenceDeleteForm, TimeTableForm
from models import Conference, TimeTable, Statistic
from forms import ConferenceChangeForm, ConferenceCreateForm, ConferenceDeleteForm, TimeTableForm, StatisticForm
from theme.models import Tag
from city.models import City
from file.models import FileModel, TmpFile
@ -72,6 +72,8 @@ def conference_add(request):
If form is posted redirect on the page of all conferences.
"""
# formset of StatisticForm
StatisticFormSet = formset_factory(StatisticForm)
#if form would be not valid key must be same
if request.POST.get('key'):
key = request.POST['key']
@ -85,12 +87,20 @@ def conference_add(request):
#set choices filled by ajax
form.fields['tag'].choices = [(item.id, item.name) for item in Tag.objects.all()]
form.fields['city'].choices = [(item.id, item.name) for item in City.objects.filter(country=request.POST['country'])]
if form.is_valid():
form.save()
#
formset_statistic = StatisticFormSet(request.POST)
if form.is_valid() and formset_statistic.is_valid():
conference = form.save()
for item in formset_statistic.forms:
#saves forms if its valid and not empty
if item.is_valid() and item.has_changed():
statistic = item.save(commit=False)
statistic.conference = conference
statistic.save()
return HttpResponseRedirect('/admin/conference/all/')
else:
form = ConferenceCreateForm(initial={'key': key})
formset_statistic = StatisticFormSet()
args = {}
args.update(csrf(request))
@ -99,6 +109,7 @@ def conference_add(request):
args['languages'] = settings.LANGUAGES
args['file_form'] = file_form
args['files'] = TmpFile.objects.filter(key=key)
args['formset_statistic'] = formset_statistic
return render_to_response('conference_add.html', args)
@ -123,20 +134,36 @@ def conference_change(request, url):
return HttpResponseRedirect('/admin/conference/all/')
if request.POST:
StatisticFormSet = formset_factory(StatisticForm)
form = ConferenceChangeForm(request.POST)
#set choices filled by ajax
form.fields['tag'].choices = [(item.id, item.name) for item in Tag.objects.all()]
form.fields['city'].choices = [(item.id, item.name) for item in City.objects.filter(country=request.POST['country'])]
if form.is_valid():
form.save(getattr(conference, 'id'))
formset_statistic = StatisticFormSet(request.POST)
if form.is_valid() and formset_statistic.is_valid():
conference = form.save(getattr(conference, 'id'))
#delete old halls
Statistic.objects.filter(conference=getattr(conference, 'id')).delete()
for item in formset_statistic.forms:
#saves new statistic if its valid and not empty
if item.is_valid() and item.has_changed():
statistic = item.save(commit=False)
statistic.conference = conference
statistic.save()
return HttpResponseRedirect('/admin/conference/all/')
else:
#initial StatisticFormSet
StatisticFormSet = modelformset_factory(Statistic, form=StatisticForm, exclude=('conference',))
#fill form with data from database
data = {'web_page':conference.web_page, 'foundation_year': conference.foundation_year,
'data_begin':conference.data_begin, 'data_end':conference.data_end, 'currency':conference.currency,
'tax':conference.tax, 'min_price':conference.min_price, 'max_price':conference.max_price,
'link':conference.link, 'conference_id':conference.id}
'link':conference.link, 'conference_id':conference.id, 'expohit': conference.expohit,
'discount': conference.discount,'canceled': conference.canceled, 'moved': conference.moved,
'visitors': conference.visitors, 'members': conference.members,
'quality_label': [item for item, bool in conference.quality_label if bool==True]}
if conference.country:
data['country'] = conference.country.id
@ -157,7 +184,7 @@ def conference_change(request, url):
data['main_title_%s' % code] = obj.main_title
data['time_%s' % code] = obj.time
data['main_themes_%s' % code] = obj.main_themes
data['discount_%s' % code] = obj.discount
data['discount_description_%s' % code] = obj.discount_description
data['title_%s' % code] = obj.title
data['keywords_%s' % code] = obj.keywords
data['descriptions_%s' % code] = obj.descriptions
@ -166,6 +193,10 @@ def conference_change(request, url):
#set choices filled by ajax
form.fields['city'].choices = [(item.id, item.name) for item in City.objects.filter(country=data['country'])]
form.fields['tag'].choices = [(item.id, item.name) for item in Tag.objects.filter(theme__in=data['theme'])]
#get existing statistic
statistic = Statistic.objects.filter(conference=getattr(conference, 'id'))
#fill HallFormSet
formset_statistic = StatisticFormSet(queryset=statistic)
args = {}
args.update(csrf(request))
@ -173,11 +204,10 @@ def conference_change(request, url):
args['form'] = form
args['languages'] = settings.LANGUAGES
args['file_form'] = file_form
args['formset_statistic'] = formset_statistic
#get list of files which connected with specific model object
args['files'] = FileModel.objects.filter(content_type=ContentType.objects.get_for_model(conference), object_id=getattr(conference, 'id'))
args['obj_id'] = getattr(conference, 'id')
return render_to_response('conference_add.html', args)
return render_to_response('conference_add.html', args)

@ -3,8 +3,9 @@ from django import forms
from django.conf import settings
from ckeditor.widgets import CKEditorWidget
from django.forms.util import ErrorList
from django.core.validators import validate_email, URLValidator
#models
from models import Conference, TimeTable, CURRENCY
from models import Conference, TimeTable, CURRENCY, Statistic
from country.models import Country
from city.models import City
from theme.models import Theme
@ -45,11 +46,20 @@ class ConferenceCreateForm(forms.Form):
web_page = forms.CharField(label='Веб страница', required=False)
link = forms.CharField(label='Линк на регистрацию', required=False)
foundation_year = forms.CharField(label='Год основания', required=False)
members = forms.CharField(label='Посетители', required=False)
visitors = forms.CharField(label='Участники', required=False)
discount = forms.CharField(label='Cкидка(%)', required=False)
#
currency = forms.ChoiceField(label='Валюта', choices=currencies, required=False)
tax = forms.BooleanField(label='Налог включен', initial=True, required=False)
min_price = forms.CharField(label='Минимальная цена', required=False)
max_price = forms.CharField(label='Максимальная цена', required=False)
expohit = forms.BooleanField(label='Expohit', required=False)
canceled = forms.BooleanField(label='Отменена', required=False)
moved = forms.BooleanField(label='Перенесена', required=False)
quality_label = forms.MultipleChoiceField(label='Тип', required=False,
choices=[('ufi', 'UFI'), ('rsva', 'РСВЯ'), ('exporating', 'ExpoRating')],
widget=forms.CheckboxSelectMultiple())
#field for comparing tmp files
key = forms.CharField(required=False, widget=forms.HiddenInput())
#
@ -77,14 +87,14 @@ class ConferenceCreateForm(forms.Form):
required=False, widget=CKEditorWidget)
self.fields['main_themes_%s' % code] = forms.CharField(label='Основные темы',
required=False, widget=CKEditorWidget)
self.fields['discount_%s' % code] = forms.CharField(label='Условия и скидки',
self.fields['discount_description_%s' % code] = forms.CharField(label='Описание скидки',
required=False, widget=CKEditorWidget)
#meta data
self.fields['title_%s' % code] = forms.CharField(label='Тайтл', required=required, max_length=255,
self.fields['title_%s' % code] = forms.CharField(label='Тайтл', required=False, max_length=255,
widget=forms.TextInput(attrs={'style':'width: 550px'}))
self.fields['keywords_%s' % code] = forms.CharField(label='Дескрипшен', required=required, max_length=255,
self.fields['keywords_%s' % code] = forms.CharField(label='Дескрипшен', required=False, max_length=255,
widget=forms.TextInput(attrs={'style':'width: 550px'}))
self.fields['descriptions_%s' % code] = forms.CharField(label='Кейвордс', required=required, max_length=255,
self.fields['descriptions_%s' % code] = forms.CharField(label='Кейвордс', required=False, max_length=255,
widget=forms.TextInput(attrs={'style':'width: 550px'}))
@ -118,12 +128,26 @@ class ConferenceCreateForm(forms.Form):
conference.link = data['link']
conference.web_page= data['web_page']
conference.foundation_year = data['foundation_year']
conference.members = data['members']
conference.visitors = data['visitors']
#
conference.currency = data['currency']
conference.tax = data['tax']
conference.min_price = data['min_price']
conference.max_price = data['max_price']
conference.discount = data['discount']
conference.expohit = data['expohit']
conference.canceled = data['canceled']
conference.moved = data['moved']
# generates bitfield
flag = 0
if data['quality_label']:
flag = reduce(lambda x,y: x|y, (getattr(Conference.quality_label, item) for item in data['quality_label']))
conference.quality_label = flag
if data.get('country'):
conference.country = Country.objects.get(id=data['country'].id)#.id cause select uses queryset
@ -147,6 +171,7 @@ class ConferenceCreateForm(forms.Form):
#save files
check_tmp_files(conference, data['key'])
return conference
def clean(self):
id = self.cleaned_data.get('conference_id')
@ -167,30 +192,31 @@ class ConferenceCreateForm(forms.Form):
cleaned_data = super(ConferenceCreateForm, self).clean()
web_page = cleaned_data.get('web_page')
if not web_page:
return web_page
return ''
import socket
validate = URLValidator()
try:
socket.getaddrinfo(web_page, 80)
return web_page
except:
raise forms.ValidationError('Введите правильный адрес страници')
validate(web_page)
except(forms.ValidationError),e:
raise forms.ValidationError(e.messages[0])
return web_page
def clean_link(self):
"""
checking link
"""
cleaned_data = super(ConferenceCreateForm, self).clean()
link = cleaned_data.get('link')
if not link:
return link
return ''
import socket
validate = URLValidator()
try:
socket.getaddrinfo(link, 80)
return link
except:
raise forms.ValidationError('Введите правильный адрес страници')
validate(link)
except(forms.ValidationError),e:
raise forms.ValidationError(e.messages[0])
return link
def clean_foundation_year(self):
@ -201,6 +227,22 @@ class ConferenceCreateForm(forms.Form):
foundation_year = cleaned_data.get('foundation_year').strip()
return is_positive_integer(foundation_year)
def clean_visitors(self):
"""
checking visitors
"""
cleaned_data = super(ConferenceCreateForm, self).clean()
visitors = cleaned_data.get('visitors').strip()
return is_positive_integer(visitors)
def clean_members(self):
"""
checking members
"""
cleaned_data = super(ConferenceCreateForm, self).clean()
members = cleaned_data.get('members').strip()
return is_positive_integer(members)
def clean_min_price(self):
"""
checking min_price
@ -217,6 +259,14 @@ class ConferenceCreateForm(forms.Form):
max_price = cleaned_data.get('max_price').strip()
return is_positive_integer(max_price)
def clean_discount(self):
"""
checking discount
"""
cleaned_data = super(ConferenceCreateForm, self).clean()
discount = cleaned_data.get('discount').strip()
return is_positive_integer(discount)
class ConferenceChangeForm(ConferenceCreateForm):
"""
@ -236,6 +286,30 @@ class ConferenceDeleteForm(forms.ModelForm):
model = Conference
fields = ('url',)
class StatisticForm(forms.ModelForm):
year = forms.CharField(widget=forms.TextInput(attrs={'style': 'width:70px'}))
visitors = forms.CharField(widget=forms.TextInput(attrs={'style': 'width:70px'}), required=False)
members = forms.CharField(widget=forms.TextInput(attrs={'style': 'width:70px'}), required=False)
class Meta:
model = Statistic
exclude = ('conference')
def clean_year(self):
cleaned_data = super(StatisticForm, self).clean()
year = cleaned_data.get('year').strip()
return is_positive_integer(year)
def clean_members(self):
cleaned_data = super(StatisticForm, self).clean()
members = cleaned_data.get('members').strip()
return is_positive_integer(members)
def clean_visitors(self):
cleaned_data = super(StatisticForm, self).clean()
visitors = cleaned_data.get('visitors').strip()
return is_positive_integer(visitors)
class TimeTableForm(forms.Form):
"""

@ -1,32 +1,31 @@
# -*- coding: utf-8 -*-
from django.db import models
from django.db.models.signals import post_save, pre_save
from django.contrib.contenttypes import generic
from hvad.models import TranslatableModel, TranslatedFields, TranslationManager
from functions.signal_handlers import post_save_handler, pre_save_handler
import copy
from bitfield import BitField
from service.models import Service
from functions.db import db_table_exists
#custom functions
from functions.custom_fields import EnumField
from functions.models_methods import ExpoManager
from functions.model_mixin import EventMixin
class ConferenceManager(TranslationManager):
def safe_get(self, **kwargs):
model = self.model
try:
return model.objects.get(**kwargs)
except:
return None
# check if table exist and create flags if true
flags = [str(item.id) for item in Service.objects.all()] if db_table_exists('service_service') else []
CURRENCY = ('RUB', 'USD', 'EUR')
class Conference(TranslatableModel):
class Conference(TranslatableModel, EventMixin):
"""
Create Conference model
Uses hvad.TranslatableModel which is child of django.db.models class
"""
#set manager of this model
objects = ConferenceManager()
objects = ExpoManager()
url = models.SlugField(unique=True)
data_begin = models.DateField(verbose_name='Дата начала')
@ -43,23 +42,34 @@ class Conference(TranslatableModel):
organiser = models.ManyToManyField('organiser.Organiser', verbose_name='Организатор',
blank=True, null=True, related_name='conference_organisers')
company = models.ManyToManyField('company.Company', verbose_name='Компании',
blank=True, null=True, related_name='conference_compamies')
blank=True, null=True, related_name='conference_companies')
users = models.ManyToManyField('accounts.User', verbose_name='Посетители выставки',
blank=True, null=True, related_name='conference_users')
#!service has bitfield uncomment when country data will be filled
services = BitField(flags=flags)
#service = models.ManyToManyField('service.Service', verbose_name='Услуги', blank=True, null=True)
web_page = models.CharField(verbose_name='Вебсайт', max_length=255, blank=True)
link = models.CharField(verbose_name='Линк на регистрацию', max_length=255, blank=True)
foundation_year = models.PositiveIntegerField(verbose_name='Год основания', blank=True, null=True)
quality_label = BitField(flags=['ufi', 'rsva', 'exporating'])
discount = models.PositiveIntegerField(verbose_name='Скидка', blank=True, null=True)
#
currency = EnumField(values=CURRENCY, default='RUB')
tax = models.BooleanField(verbose_name='Налог', default=1)
min_price = models.PositiveIntegerField(verbose_name='Минимальная цена', blank=True, null=True)
max_price = models.PositiveIntegerField(verbose_name='Максимальная цена', blank=True, null=True)
#administrator can cancel conference
expohit = models.BooleanField(verbose_name='Expohit', default=0)
canceled_by_administrator = models.BooleanField(default=0)
canceled = models.BooleanField(default=0)
moved = models.BooleanField(default=0)
#can publish not immediately
is_published = models.BooleanField(default=0)
files = generic.GenericRelation('file.FileModel', content_type_field='content_type', object_id_field='object_id')
# statistic
foundation_year = models.PositiveIntegerField(verbose_name='Год основания', blank=True, null=True)
visitors = models.PositiveIntegerField(verbose_name='Посетитеил', blank=True, null=True)
members = models.PositiveIntegerField(verbose_name='Участники', blank=True, null=True)
#translated fields
translations = TranslatedFields(
name = models.CharField(verbose_name='Название', max_length=255),
@ -67,7 +77,7 @@ class Conference(TranslatableModel):
description=models.TextField(verbose_name='Описание', blank=True),
main_themes=models.TextField(verbose_name='Основные темы', blank=True),
time=models.TextField(verbose_name='Время работы', blank=True),
discount=models.TextField(verbose_name='Условия и Скидки', blank=True),
discount_description=models.TextField(verbose_name='Описание скидки', blank=True),
#-----meta data
title=models.CharField(max_length=250),
descriptions=models.CharField(max_length=250),
@ -78,25 +88,17 @@ class Conference(TranslatableModel):
created = models.DateTimeField(auto_now_add=True)
modified = models.DateTimeField(auto_now=True)
#audience = EnumField(values=AUDIENCE)
#mark
views = models.PositiveIntegerField(null=True)
def __unicode__(self):
return self.lazy_translation_getter('name', unicode(self.pk))
def on(self):
self.is_published = True
self.canceled_by_administrator = False
self.save()
def get_nearest_events(self):
conferences = Conference.objects.all()[:5]
return conferences
def off(self):
self.is_published = False
self.canceled_by_administrator = True
self.save()
def cancel(self):
self.canceled_by_administrator = True
def get_catalog_url(self):
return '/conferences/'
def clone(self):
"""
@ -118,6 +120,16 @@ class Conference(TranslatableModel):
duplicate.is_published = False
duplicate.cancel_by_administrator = False
ignore_fields = ['id', 'master', 'language_code']
duplicate.translate('ru')
tr = self._meta.translations_model.objects.get(language_code = 'ru',master__id=self.pk)
for field in duplicate._translated_field_names:
if field in ignore_fields:
continue
setattr(duplicate, field, getattr(tr, field))
duplicate.save()
# but lost all ManyToMany relations and Translations.
@ -128,23 +140,20 @@ class Conference(TranslatableModel):
for item in source.all():
destination.add(item)
# copy translations
languages = self.get_available_languages()
ignore_fields = ['id', 'master', 'language_code']
for code in languages:
duplicate.translate(code)
tr = self._meta.translations_model.objects.get(language_code = code,master__id=self.pk)
for field in duplicate._translated_field_names:
return duplicate
if field in ignore_fields:
continue
def get_calendar_url(self):
return '/conference-add-calendar/%s/'%self.id
setattr(duplicate, field, getattr(tr, field))
def get_visit_url(self):
return '/conference-visit/%s/'%self.id
duplicate.save()
return duplicate
class Statistic(models.Model):
conference = models.ForeignKey(Conference, related_name='statistic')
year = models.PositiveIntegerField(verbose_name='Год')
members = models.PositiveIntegerField(verbose_name='Посетители')
visitors = models.PositiveIntegerField(verbose_name='Участники')
class TimeTable(TranslatableModel):
@ -158,4 +167,7 @@ class TimeTable(TranslatableModel):
#translated fields
translations = TranslatedFields(
name = models.CharField(verbose_name='Название', max_length=255)
)
)
pre_save.connect(pre_save_handler, sender=Conference)
post_save.connect(post_save_handler, sender=Conference)

@ -3,4 +3,4 @@ from django.db.models.signals import post_save
from models import Conference
from functions.signal_handlers import post_save_handler
post_save.connect(post_save_handler, sender=Conference)
#post_save.connect(post_save_handler, sender=Conference)

@ -0,0 +1,15 @@
# -*- coding: utf-8 -*-
from django.conf.urls import patterns, include, url
from views import ConferenceView
urlpatterns = patterns('',
url(r'conferences/(?P<params>.*)/(?P<page>\d+)/$', ConferenceView.as_view()),
url(r'conferences/(?P<page>\d+)/$', ConferenceView.as_view()),
url(r'conferences/(?P<params>.*)/$', ConferenceView.as_view()),
url(r'conferences/$', ConferenceView.as_view()),
#
url(r'conference-add-calendar/(?P<id>\d+)/$', 'conference.views.conference_add_calendar'),
url(r'conference-remove-calendar/(?P<id>\d+)/$', 'conference.views.conference_remove_calendar'),
url(r'conference-visit/(?P<id>\d+)/$', 'conference.views.conference_visit'),
url(r'conference-unvisit/(?P<id>\d+)/$', 'conference.views.conference_unvisit'),
)

@ -0,0 +1,70 @@
# -*- coding: utf-8 -*-
from django.http import HttpResponse
from models import Conference
from functions.custom_views import ExpoListView
import json
class ConferenceView(ExpoListView):
model = Conference
template_name = 'event_catalog.html'
def conference_add_calendar(request, id):
args = {'success': False}
user = request.user
if user.is_authenticated():
conf = Conference.objects.safe_get(id=id)
if conf:
user.calendar.conferences.add(conf)
args['success'] = True
else:
args['not_authorized'] = True
args['success'] = True
return HttpResponse(json.dumps(args), content_type='application/json')
def conference_remove_calendar(request, id):
args = {'success': False}
if request.user:
user = request.user
conf = Conference.objects.safe_get(id=id)
if conf:
user.calendar.conferences.remove(conf)
args['success'] = True
else:
args['not_authorized'] = True
args['success'] = True
return HttpResponse(json.dumps(args), content_type='application/json')
def conference_visit(request, id):
args = {'success': False}
user = request.user
if user.is_authenticated():
conf = Conference.objects.safe_get(id=id)
if conf:
conf.users.add(user)
args['success'] = True
else:
args['not_authorized'] = True
args['success'] = True
return HttpResponse(json.dumps(args), content_type='application/json')
def conference_unvisit(request, id):
args = {'success': False}
user = request.user
if user.is_authenticated():
conf = Conference.objects.safe_get(id=id)
if conf:
conf.users.remove(user)
else:
args['not_authorized'] = True
args['success'] = True
return HttpResponse(json.dumps(args), content_type='application/json')

@ -0,0 +1,3 @@
from django.db import models
# Create your models here.

@ -0,0 +1,16 @@
"""
This file demonstrates writing tests using the unittest module. These will pass
when you run "manage.py test".
Replace this with more appropriate tests for your application.
"""
from django.test import TestCase
class SimpleTest(TestCase):
def test_basic_addition(self):
"""
Tests that 1 + 1 always equals 2.
"""
self.assertEqual(1 + 1, 2)

@ -0,0 +1,77 @@
# -*- coding: utf-8 -*-
from country.models import Country
from city.models import City
from place_exposition.models import PlaceExposition
from place_conference.models import PlaceConference
from django.views.generic import ListView
from functions.views_help import split_params
from django.utils.translation import ugettext as _
class PlaceListView(ListView):
paginate_by = 2
params = None
single_page = False
template_name = 'place_catalog_test.html'
model = 'places'
def get_params(self):
model_names = {'places': _(u'Места')}
model_alternative_name = {'places': 'place'}
params = [{'type':'model', 'url':self.model, 'name': model_names.get(self.model),
'alternative_name': model_alternative_name.get(self.model)}]
st = self.kwargs.get('params')
if st:
params = params + split_params(st)
return params
def get_queryset(self):
pl_ex = PlaceExposition.objects.all()
pl_conf = PlaceConference.objects.all()
params = self.get_params()
for param in params:
if param.get('type') == 'country':
country = Country.objects.safe_get(url=param.get('url'))
if country:
param['name'] = country.name
pl_ex = pl_ex.filter(country=country)
pl_conf = pl_conf.filter(country=country)
if param.get('type') == 'city':
city = City.objects.safe_get(url=param.get('url'))
if city:
param['name'] = city.name
pl_ex = pl_ex.filter(city=city)
pl_conf = pl_conf.filter(city=city)
if param.get('type') == 'place':
pl_ex = pl_ex.filter(url=param.get('url'))
if pl_ex:
query = pl_ex
else:
query = pl_conf.filter(url=param.get('url'))
self.single_page = True
if query:
param['name'] = query[0].name
#if self.request:
# views = query[0].views
# query.update(views=views+1)
self.params = params
return query
self.params = params
return list(pl_ex) + list(pl_conf)
def get_context_data(self, **kwargs):
context = super(PlaceListView, self).get_context_data(**kwargs)
context['filter'] = self.params
context['single_page'] = self.single_page
return context

@ -13,12 +13,26 @@ from forms import CountryForm, CountryDeleteForm
from file.models import FileModel, TmpFile
from file.forms import FileModelForm
#custom views
from functions.custom_views import objects_list, add_object_with_file, delete_object
from functions.custom_views import objects_list, add_object_with_file, delete_object, filtered_list
from functions.forms import AdminSearchForm
from hvad.utils import get_translation_aware_manager
def country_all(request):
"""
Return list of all countries with pagination
"""
if request.GET:
form = AdminSearchForm(request.POST)
if form.is_valid():
s_name = request.GET.get('search_name')
query = get_translation_aware_manager(Country)
objects = query.filter(name__contains=s_name).distinct()
#return HttpResponse(objects)
#objects = Country.objects.all()
return filtered_list(request, objects, 'country_all.html', 1000)
return objects_list(request, Country, 'country_all.html')
def country_add(request):

@ -2,10 +2,11 @@
from django import forms
from django.conf import settings
from ckeditor.widgets import CKEditorWidget
from tinymce.widgets import TinyMCE
from django.core.exceptions import ValidationError
from django.forms.util import ErrorList
#models
from models import Country, City
from models import Country, City, REGIONS
from directories.models import Language, Currency, Iata
#functions
from functions.translate import fill_with_signal
@ -45,14 +46,14 @@ class CountryForm(forms.Form):
#
population = forms.CharField(label='Население(млн)', required=False,
widget=forms.TextInput(attrs={'placeholder':'Население(млн)'}))
teritory = forms.CharField(label='Територия(км2)', required=False,
teritory = forms.CharField(label='Территория(км2)', required=False,
widget=forms.TextInput(attrs={'placeholder':'Територия(км2)'}))# km2
timezone = forms.ChoiceField(label='Часовые пояса', required=False, choices=tz, initial=99)
phone_code = forms.CharField(label='Код страны', required=False,
widget=forms.TextInput(attrs={'placeholder':'Код страны'}))
time_delivery = forms.CharField(label='Срок выдачи', required=False,
widget=forms.TextInput(attrs={'placeholder':'Срок выдачи'}))
region = forms.ChoiceField(label='Регион', choices=((item, item) for item in Country.REGIONS))
region = forms.ChoiceField(label='Регион', choices=((item, item) for item in REGIONS))
#services = forms.MultipleChoiceField(label='Сервисы', required=False, choices=);
#field for comparing tmp files
@ -61,7 +62,7 @@ class CountryForm(forms.Form):
country_id = forms.CharField(required=False, widget=forms.HiddenInput)
def __init__(self, *args, **kwargs ):
def __init__(self, *args, **kwargs):
"""
creates dynamical translated fields and fills select fields
@ -95,17 +96,17 @@ class CountryForm(forms.Form):
widget=forms.TextInput(attrs={'style':'width: 550px'}))
# check if exists cities connected with country
countries = City.objects.filter(country = country_id)
countries = City.objects.language().filter(country = country_id).order_by('name')
countries_list = [(item.id, item.name) for item in countries]
if country_id == None or len(countries)==0:
self.fields['capital'] = forms.ChoiceField(label='Столица',choices=((None,'Нет городов в стране'),), required=False,
widget=forms.Select(attrs={'disabled' : True}))
self.fields['big_cities'] = forms.MultipleChoiceField(label='Большые города',choices=((None,'Нет городов в стране'),), required=False,
self.fields['big_cities'] = forms.MultipleChoiceField(label='Большие города',choices=((None,'Нет городов в стране'),), required=False,
widget=forms.Select(attrs={'disabled' : True}))
else:
self.fields['capital'] = forms.ChoiceField(label='Столица', choices=countries_list,
required=False)
self.fields['big_cities'] = forms.MultipleChoiceField(label='Большые города', choices=countries_list,
self.fields['big_cities'] = forms.MultipleChoiceField(label='Большие города', choices=countries_list,
required=False)
def save(self, id=None):
@ -126,8 +127,11 @@ class CountryForm(forms.Form):
country.language.clear()
country.currency.clear()
if data.get("name_en"):
country.url = translit_with_separator(data['name_en'].strip()).lower()
else:
country.url = translit_with_separator(data['name_ru'].strip()).lower()
country.url = translit_with_separator(data['name_ru'].strip()).lower()
country.population = data['population']
country.teritory = data['teritory']
country.timezone = data['timezone']

@ -1,19 +1,37 @@
# -*- coding: utf-8 -*-
from django.db import models
from hvad.models import TranslatableModel, TranslatedFields
from django.utils.translation import ugettext as _
from django.contrib.contenttypes import generic
from django.db.models.signals import post_save, pre_save
from hvad.models import TranslatableModel, TranslatedFields, TranslationManager
from bitfield import BitField
# models
from directories.models import Language, Currency
from city.models import City
from service.models import Service
# func
from functions.custom_fields import EnumField
from bitfield import BitField
from functions.db import db_table_exists
from functions.signal_handlers import post_save_handler, pre_save_handler
from django.utils.translation import get_language as lang
# check if table exist and create flags if true
flags = [str(item.id) for item in Service.objects.all()] if db_table_exists('service_service') else []
REGIONS =('europa', 'asia', 'america', 'africa')
class CountryManager(TranslationManager):
def all(self):
"""
hack
"""
return super(TranslationManager, self).all().filter(translations__language_code=lang()).order_by('translations__name')
def safe_get(self, **kwargs):
model = self.model
try:
return model.objects.get(**kwargs)
except:
return None
class Country(TranslatableModel):
"""
@ -23,11 +41,8 @@ class Country(TranslatableModel):
"""
objects = CountryManager()
services = BitField(flags=flags)
REGIONS =('europa', 'asia', 'america', 'africa')
url = models.SlugField(unique=True)
# relations
big_cities = models.ManyToManyField(City, blank=True, null=True, related_name='cities')
@ -50,7 +65,7 @@ class Country(TranslatableModel):
files = generic.GenericRelation('file.FileModel',content_type_field='content_type', object_id_field='object_id')
#translated fields
translations = TranslatedFields(
name = models.CharField(max_length=30),
name = models.CharField(max_length=255),
description = models.TextField(blank=True),
transport = models.TextField(blank=True),
#------visa inf
@ -64,5 +79,10 @@ class Country(TranslatableModel):
)
# class Meta:
# ordering = ['translations__name']
def __unicode__(self):
return self.lazy_translation_getter('name', unicode(self.pk))
return self.lazy_translation_getter('name', unicode(self.pk))
post_save.connect(post_save_handler, sender=Country)

@ -1,9 +1 @@
# -*- coding: utf-8 -*-
from django.db.models.signals import post_save
from functions.signal_handlers import post_save_handler
from models import Country
post_save.connect(post_save_handler, sender=Country)

@ -7,16 +7,16 @@ from django.forms.formsets import BaseFormSet, formset_factory
from django.forms.models import modelformset_factory
from django.contrib.contenttypes.models import ContentType
from django.contrib.auth.decorators import login_required
#models and forms
from models import Exposition, TimeTable
from forms import ExpositionChangeForm, ExpositionCreateForm, ExpositionDeleteForm, TimeTableForm
# models and forms
from models import Exposition, TimeTable, Statistic, TmpTimeTable
from forms import ExpositionCreateForm, ExpositionDeleteForm, TimeTableForm, StatisticForm
from theme.models import Tag
from city.models import City
from file.models import FileModel, TmpFile
from file.forms import FileModelForm
#python
# python
import random
#custom views
# custom views
from functions.custom_views import objects_list, delete_object
from functions.views_help import get_referer
@ -52,7 +52,6 @@ def exposition_switch(request, url, action):
return HttpResponse('error')
@login_required
def exposition_copy(request, url):
@ -63,6 +62,7 @@ def exposition_copy(request, url):
exposition.clone()
return HttpResponseRedirect(get_referer(request))
@login_required
def exposition_add(request):
"""
@ -70,25 +70,37 @@ def exposition_add(request):
If form is posted redirect on the page of all expositions.
"""
#if form would be not valid key must be same
# formset of StatisticForm
StatisticFormSet = formset_factory(StatisticForm)
# if form would be not valid key must be same
if request.POST.get('key'):
key = request.POST['key']
else:
key = random.getrandbits(128)
file_form = FileModelForm(initial={'key': key})
timetable_form = TimeTableForm(initial={'key': key})
if request.POST:
form = ExpositionCreateForm(request.POST)
#set choices filled by ajax
# set choices filled by ajax
form.fields['tag'].choices = [(item.id, item.name) for item in Tag.objects.all()]
form.fields['city'].choices = [(item.id, item.name) for item in City.objects.filter(country=request.POST['country'])]
if form.is_valid():
form.save()
formset_statistic = StatisticFormSet(request.POST)
if form.is_valid() and formset_statistic.is_valid():
exposition = form.save()
for item in formset_statistic.forms:
# saves forms if its valid and not empty
if item.is_valid() and item.has_changed():
statistic = item.save(commit=False)
statistic.exposition = exposition
statistic.save()
return HttpResponseRedirect('/admin/exposition/all/')
else:
form = ExpositionCreateForm(initial={'key': key})
formset_statistic = StatisticFormSet()
args = {}
args.update(csrf(request))
@ -96,7 +108,12 @@ def exposition_add(request):
args['form'] = form
args['file_form'] = file_form
args['files'] = TmpFile.objects.filter(key=key)
args['timetables'] = TmpTimeTable.objects.filter(key=key)
args['languages'] = settings.LANGUAGES
args['formset_statistic'] = formset_statistic
args['timetable_form'] = timetable_form
return render_to_response('exposition_add.html', args)
@ -113,31 +130,51 @@ def exposition_change(request, url):
"""
try:
#check if exposition_id exists else redirect to the list of expositions
# check if exposition_id exists else redirect to the list of expositions
exposition = Exposition.objects.get(url=url)
file_form = FileModelForm(initial={'model': 'exposition.Exposition'})
except:
return HttpResponseRedirect('/admin/exposition/all/')
if request.POST:
form = ExpositionChangeForm(request.POST)
#set choices filled by ajax
StatisticFormSet = formset_factory(StatisticForm)
form = ExpositionCreateForm(request.POST)
# set choices filled by ajax
form.fields['tag'].choices = [(item.id, item.name) for item in Tag.objects.all()]
form.fields['city'].choices = [(item.id, item.name) for item in City.objects.filter(country=request.POST['country'])]
formset_statistic = StatisticFormSet(request.POST)
if form.is_valid() and formset_statistic.is_valid():
exposition = form.save(getattr(exposition, 'id'))
# delete old halls
Statistic.objects.filter(exposition=getattr(exposition, 'id')).delete()
for item in formset_statistic.forms:
# saves new statistic if its valid and not empty
if item.is_valid() and item.has_changed():
statistic = item.save(commit=False)
statistic.exposition = exposition
statistic.save()
if form.is_valid():
form.save(getattr(exposition, 'id'))
return HttpResponseRedirect('/admin/exposition/all/')
else:
#fill form with data from database
# initial StatisticFormSet
StatisticFormSet = modelformset_factory(Statistic, form=StatisticForm, exclude=('exposition',))
# fill form with data from database
data = {'web_page':exposition.web_page, 'foundation_year': exposition.foundation_year,
'data_begin':exposition.data_begin, 'data_end':exposition.data_end, 'periodic':exposition.periodic,
'audience':exposition.audience, 'min_area':exposition.min_area, 'currency':exposition.currency,
'tax':exposition.tax, 'min_closed_area':exposition.min_closed_area,
'max_closed_area':exposition.max_closed_area, 'min_closed_equipped_area':exposition.min_closed_equipped_area,
'min_area':exposition.min_area, 'currency':exposition.currency, 'tax':exposition.tax,
'price_day':exposition.price_day, 'price_all':exposition.price_all, 'price_catalog':exposition.price_catalog,
'min_closed_area':exposition.min_closed_area, 'max_closed_area':exposition.max_closed_area,
'min_closed_equipped_area':exposition.min_closed_equipped_area,
'max_closed_equipped_area':exposition.max_closed_equipped_area,
'min_open_area':exposition.min_open_area, 'max_open_area':exposition.max_open_area,
'registration_payment':exposition.registration_payment, 'exposition_id':exposition.id}
'registration_payment':exposition.registration_payment, 'exposition_id':exposition.id,
'expohit': exposition.expohit, 'discount': exposition.discount,
'canceled': exposition.canceled, 'moved': exposition.moved,
'visitors': exposition.visitors, 'members': exposition.members,
'audience':[item for item, bool in exposition.audience if bool==True],
'quality_label': [item for item, bool in exposition.quality_label if bool==True]}
if exposition.country:
data['country'] = exposition.country.id
@ -150,7 +187,9 @@ def exposition_change(request, url):
data['theme'] = [item.id for item in exposition.theme.all()]
data['tag'] = [item.id for item in exposition.tag.all()]
#data from translated fields
data['organiser'] = [item.id for item in exposition.organiser.all()]
data['company'] = [item.id for item in exposition.company.all()]
# data from translated fields
for code, name in settings.LANGUAGES:
obj = Exposition._meta.translations_model.objects.get(language_code = code,master__id=getattr(exposition, 'id')) #access to translated fields
data['name_%s' % code] = obj.name
@ -158,14 +197,19 @@ def exposition_change(request, url):
data['main_title_%s' % code] = obj.main_title
data['time_%s' % code] = obj.time
data['products_%s' % code] = obj.products
data['discount_description_%s' % code] = obj.discount_description
data['title_%s' % code] = obj.title
data['keywords_%s' % code] = obj.keywords
data['descriptions_%s' % code] = obj.descriptions
#initial form
form = ExpositionChangeForm(initial=data)
#set choices filled by ajax
# initial form
form = ExpositionCreateForm(initial=data)
# set choices filled by ajax
form.fields['city'].choices = [(item.id, item.name) for item in City.objects.filter(country=data['country'])]
form.fields['tag'].choices = [(item.id, item.name) for item in Tag.objects.filter(theme__in=data['theme'])]
# get existing statistic
statistic = Statistic.objects.filter(exposition=getattr(exposition, 'id'))
# fill HallFormSet
formset_statistic = StatisticFormSet(queryset=statistic)
args = {}
args.update(csrf(request))
@ -173,10 +217,13 @@ def exposition_change(request, url):
args['form'] = form
args['languages'] = settings.LANGUAGES
args['file_form'] = file_form
args['formset_statistic'] = formset_statistic
args['timetable_form'] = TimeTableForm()
args['timetables'] = TimeTable.objects.filter(exposition=exposition)
#get list of files which connected with specific model object
# get list of files which connected with specific model object
args['files'] = FileModel.objects.filter(content_type=ContentType.objects.get_for_model(exposition),
object_id=getattr(exposition, 'id'))
args['obj_id'] = getattr(exposition, 'id')
return render_to_response('exposition_add.html', args)
return render_to_response('exposition_add.html', args)

@ -2,10 +2,12 @@
from django import forms
from django.conf import settings
from ckeditor.widgets import CKEditorWidget
from tinymce.widgets import TinyMCE
from django.core.exceptions import ValidationError
from django.forms.util import ErrorList
from django.core.validators import validate_email, URLValidator
#models
from models import Exposition, TimeTable, AUDIENCE1, CURRENCY
from models import Exposition, TimeTable, TmpTimeTable, AUDIENCE1, CURRENCY, Statistic, BIT_AUDIENCE
from country.models import Country
from theme.models import Theme
from organiser.models import Organiser
@ -19,6 +21,7 @@ from functions.translate import populate_all, fill_trans_fields_all, fill_with_s
from functions.form_check import is_positive_integer
from functions.files import check_tmp_files
from functions.form_check import translit_with_separator
from settings.settings import date_formats
class ExpositionCreateForm(forms.Form):
@ -29,39 +32,54 @@ class ExpositionCreateForm(forms.Form):
save function saves data in Exposition object. If it doesnt exist create new object
"""
PERIODIC = ((0, 'Не выбрано'),
(1.0, 'Ежегодно'), (2.0, '2 раза в год'), (3.0, '3 раза в год'),
(4.0, '4 раза в год'), (5.0, '5 раз в год'),
(0.5, 'Раз в 2 года'),(0.33, 'Раз в 3 года'),(0.25, 'Раз в 4 года'))
public = [(item1, item2) for item1, item2 in AUDIENCE1]
PERIODIC = ((0, u'Не выбрано'),
(1.0, u'Ежегодно'), (2.0, u'2 раза в год'), (3.0, u'3 раза в год'),
(4.0, u'4 раза в год'), (5.0, u'5 раз в год'),
(0.5, u'Раз в 2 года'),(0.33, u'Раз в 3 года'),(0.25, u'Раз в 4 года'))
public = [(item1, item2) for item1, item2 in BIT_AUDIENCE]
currencies = [(item, item) for item in CURRENCY]
data_begin = forms.DateField(label='Дата начала')
data_end = forms.DateField(label='Дата окночания')
data_begin = forms.DateField(label=u'Дата начала')
data_end = forms.DateField(label=u'Дата окночания')
country = forms.ModelChoiceField(label='Страна', queryset=Country.objects.all(), empty_label=None)
theme = forms.ModelMultipleChoiceField(label='Тематики', queryset=Theme.objects.all())
place = forms.ModelChoiceField(label='Место проведения', queryset=PlaceExposition.objects.all(),
organiser = forms.ModelMultipleChoiceField(label=u'Организаторы', queryset=Organiser.objects.all(), required=False)
company = forms.ModelMultipleChoiceField(label=u'Компании', queryset=Company.objects.all(), required=False)
country = forms.ModelChoiceField(label=u'Страна', queryset=Country.objects.all(), empty_label=None)
theme = forms.ModelMultipleChoiceField(label=u'Тематики', queryset=Theme.objects.all())
place = forms.ModelChoiceField(label=u'Место проведения', queryset=PlaceExposition.objects.all(),
empty_label='', required=False)
#creates select input with empty choices cause it will be filled with ajax
city = forms.ChoiceField(label='Город', choices=[('','')])
tag = forms.MultipleChoiceField(label='Теги', required=False)
periodic = forms.ChoiceField(label='Периодичность', choices=PERIODIC, required=False)
audience = forms.ChoiceField(label='Аудитория', choices=public, initial='', required=False)
web_page = forms.CharField(label='Веб страница', required=False)
foundation_year = forms.CharField(label='Год основания', required=False)
min_area = forms.CharField(label='Минимальная плошадь', required=False)
city = forms.ChoiceField(label=u'Город', choices=[('','')])
tag = forms.MultipleChoiceField(label=u'Теги', required=False)
periodic = forms.ChoiceField(label=u'Периодичность', choices=PERIODIC, required=False)
audience = forms.MultipleChoiceField(label=u'Аудитория', choices=public, initial='', required=False)
web_page = forms.CharField(label=u'Веб страница', required=False)
foundation_year = forms.CharField(label=u'Год основания', required=False)
members = forms.CharField(label=u'Участники', required=False)
visitors = forms.CharField(label=u'Посетители', required=False)
min_area = forms.CharField(label=u'Минимальная плошадь', required=False)
discount = forms.CharField(label=u'Cкидка(%)', required=False)
quality_label = forms.MultipleChoiceField(label=u'Метки', required=False,
choices=[('ufi', 'UFI'), ('rsva', 'РСВЯ'), ('exporating', 'ExpoRating')],
widget=forms.CheckboxSelectMultiple())
#
currency = forms.ChoiceField(label='Валюта', choices=currencies, required=False)
tax = forms.BooleanField(label='Налог включен', initial=True, required=False)
min_closed_area = forms.CharField(label='Минимальная цена закрытой НЕ оборудованной площади', required=False)
max_closed_area = forms.CharField(label='Максимальная цена закрытой НЕ оборудованной площади', required=False)
min_closed_equipped_area = forms.CharField(label='Минимальная цена закрытой оборудованной площади', required=False)
max_closed_equipped_area = forms.CharField(label='Максимальная цена закрытой оборудованной площади', required=False)
min_open_area = forms.CharField(label='Минимальная цена открытой площади', required=False)
max_open_area = forms.CharField(label='Максимальная цена открытой площади', required=False)
registration_payment = forms.CharField(label='Регистрационны взнос', required=False)
currency = forms.ChoiceField(label=u'Валюта', choices=currencies, required=False)
price_day = forms.CharField(label=u'Цена за 1 день', required=False)
price_all = forms.CharField(label=u'Цена за все дни', required=False)
price_catalog = forms.CharField(label=u'Цена за каталог', required=False)
tax = forms.BooleanField(label=u'Налог включен', initial=True, required=False)
min_closed_area = forms.CharField(label=u'Минимальная цена закрытой НЕ оборудованной площади', required=False)
max_closed_area = forms.CharField(label=u'Максимальная цена закрытой НЕ оборудованной площади', required=False)
min_closed_equipped_area = forms.CharField(label=u'Минимальная цена закрытой оборудованной площади', required=False)
max_closed_equipped_area = forms.CharField(label=u'Максимальная цена закрытой оборудованной площади', required=False)
min_open_area = forms.CharField(label=u'Минимальная цена открытой площади', required=False)
max_open_area = forms.CharField(label=u'Максимальная цена открытой площади', required=False)
registration_payment = forms.CharField(label=u'Регистрационны взнос', required=False)
expohit = forms.BooleanField(label=u'Expohit', required=False)
canceled = forms.BooleanField(label=u'Отменена', required=False)
moved = forms.BooleanField(label=u'Перенесена', required=False)
#field for comparing tmp files
key = forms.CharField(required=False, widget=forms.HiddenInput())
#
@ -80,21 +98,23 @@ class ExpositionCreateForm(forms.Form):
# uses enumerate for detect iteration number
# first iteration is a default lang so it required fields
required = True if lid == 0 else False
self.fields['name_%s' % code] = forms.CharField(label='Название', required=required)
self.fields['main_title_%s' % code] = forms.CharField(label='Краткое описание',
self.fields['name_%s' % code] = forms.CharField(label=u'Название', required=required)
self.fields['main_title_%s' % code] = forms.CharField(label=u'Краткое описание',
required=False, widget=CKEditorWidget)
self.fields['description_%s' % code] = forms.CharField(label='Описание',
self.fields['description_%s' % code] = forms.CharField(label=u'Описание',
required=False, widget=CKEditorWidget)
self.fields['time_%s' % code] = forms.CharField(label='Время работы',
self.fields['time_%s' % code] = forms.CharField(label=u'Время работы',
required=False, widget=CKEditorWidget)
self.fields['products_%s' % code] = forms.CharField(label='Экспонируемые продукты',
self.fields['products_%s' % code] = forms.CharField(label=u'Экспонируемые продукты',
required=False, widget=CKEditorWidget)
self.fields['discount_description_%s' % code] = forms.CharField(label=u'Описание скидки',
required=False, widget=CKEditorWidget)
#meta data
self.fields['title_%s' % code] = forms.CharField(label='Тайтл', required=required, max_length=255,
self.fields['title_%s' % code] = forms.CharField(label=u'Meta title', required=False, max_length=255,
widget=forms.TextInput(attrs={'style':'width: 550px'}))
self.fields['keywords_%s' % code] = forms.CharField(label='Дескрипшен', required=required, max_length=255,
self.fields['keywords_%s' % code] = forms.CharField(label=u'Meta keywords', required=False, max_length=255,
widget=forms.TextInput(attrs={'style':'width: 550px'}))
self.fields['descriptions_%s' % code] = forms.CharField(label='Кейвордс', required=required, max_length=255,
self.fields['descriptions_%s' % code] = forms.CharField(label=u'Meta description', required=False, max_length=255,
widget=forms.TextInput(attrs={'style':'width: 550px'}))
#creates select inputs ind fill it
#!service has bitfield. uncomment when country data will be filled
@ -116,18 +136,24 @@ class ExpositionCreateForm(forms.Form):
exposition = Exposition.objects.get(id=id)
exposition.theme.clear()
exposition.tag.clear()
exposition.organiser.clear()
exposition.company.clear()
#simple fields
exposition.url = translit_with_separator(data['name_ru'].strip()).lower()
exposition.data_begin = data['data_begin']
exposition.data_end = data['data_end']
exposition.periodic = data['periodic']
exposition.audience = data['audience']
exposition.web_page= data['web_page']
exposition.foundation_year = data['foundation_year']
exposition.members = data['members']
exposition.visitors = data['visitors']
exposition.min_area = data['min_area']
#
exposition.currency = data['currency']
exposition.price_day = data['price_day']
exposition.price_all = data['price_all']
exposition.price_catalog = data['price_catalog']
exposition.tax = data['tax']
exposition.min_closed_area = data['min_closed_area']
exposition.max_closed_area = data['max_closed_area']
@ -137,6 +163,23 @@ class ExpositionCreateForm(forms.Form):
exposition.max_open_area = data['max_open_area']
exposition.registration_payment = data['registration_payment']
exposition.discount = data['discount']
exposition.expohit = data['expohit']
exposition.canceled = data['canceled']
exposition.moved = data['moved']
# generates bitfield
quality = 0
if data['quality_label']:
quality = reduce(lambda x,y: x|y, (getattr(Exposition.quality_label, item) for item in data['quality_label']))
exposition.quality_label = quality
audience = 0
if data['audience']:
audience = reduce(lambda x,y: x|y, (getattr(Exposition.audience, item) for item in data['audience']))
exposition.audience = audience
if data.get('country'):
exposition.country = Country.objects.get(id=data['country'].id)#.id cause select uses queryset
@ -156,10 +199,18 @@ class ExpositionCreateForm(forms.Form):
for item in data['tag']:
exposition.tag.add(item)
# uses because in the next loop data will be overwritten
for item in data['organiser']:
exposition.organiser.add(item)
for item in data['company']:
exposition.company.add(item)
exposition.save()
#save files
check_tmp_files(exposition, data['key'])
# save files
check_tmp_files(exposition, data.get('key'))
check_tmp_timetables(exposition, data.get('key'))
return exposition
def clean(self):
id = self.cleaned_data.get('exposition_id')
@ -180,14 +231,14 @@ class ExpositionCreateForm(forms.Form):
cleaned_data = super(ExpositionCreateForm, self).clean()
web_page = cleaned_data.get('web_page')
if not web_page:
return web_page
return ''
import socket
validate = URLValidator()
try:
socket.getaddrinfo(web_page, 80)
return web_page
except:
raise forms.ValidationError('Введите правильный адрес страници')
validate(web_page)
except(forms.ValidationError),e:
raise forms.ValidationError(e.messages[0])
return web_page
def clean_foundation_year(self):
"""
@ -197,6 +248,47 @@ class ExpositionCreateForm(forms.Form):
foundation_year = cleaned_data.get('foundation_year').strip()
return is_positive_integer(foundation_year)
def clean_price_day(self):
"""
checking price_day
"""
cleaned_data = super(ExpositionCreateForm, self).clean()
price_day = cleaned_data.get('price_day').strip()
return is_positive_integer(price_day)
def clean_price_all(self):
"""
checking price_all
"""
cleaned_data = super(ExpositionCreateForm, self).clean()
price_all = cleaned_data.get('price_all').strip()
return is_positive_integer(price_all)
def clean_price_catalog(self):
"""
checking price_catalog
"""
cleaned_data = super(ExpositionCreateForm, self).clean()
price_catalog = cleaned_data.get('price_catalog').strip()
return is_positive_integer(price_catalog)
def clean_visitors(self):
"""
checking visitors
"""
cleaned_data = super(ExpositionCreateForm, self).clean()
visitors = cleaned_data.get('visitors').strip()
return is_positive_integer(visitors)
def clean_members(self):
"""
checking members
"""
cleaned_data = super(ExpositionCreateForm, self).clean()
members = cleaned_data.get('members').strip()
return is_positive_integer(members)
def clean_min_area(self):
"""
checking min_area
@ -262,17 +354,13 @@ class ExpositionCreateForm(forms.Form):
registration_payment = cleaned_data.get('registration_payment').strip()
return is_positive_integer(registration_payment)
class ExpositionChangeForm(ExpositionCreateForm):
"""
add some fields to ExpositionCreateForm
"""
organiser = forms.ModelMultipleChoiceField(label='Организаторы', queryset=Organiser.objects.all(), required=False)
company = forms.ModelMultipleChoiceField(label='Компании', queryset=Company.objects.all(), required=False)
users = forms.ModelMultipleChoiceField(label='Пользователи', queryset=User.objects.all(), required=False)
def clean_discount(self):
"""
checking discount
"""
cleaned_data = super(ExpositionCreateForm, self).clean()
discount = cleaned_data.get('discount').strip()
return is_positive_integer(discount)
class ExpositionDeleteForm(forms.ModelForm):
url = forms.CharField(widget=forms.HiddenInput())
@ -282,9 +370,39 @@ class ExpositionDeleteForm(forms.ModelForm):
fields = ('url',)
class StatisticForm(forms.ModelForm):
year = forms.CharField(widget=forms.TextInput(attrs={'style': 'width:70px'}))
visitors = forms.CharField(widget=forms.TextInput(attrs={'style': 'width:70px'}), required=False)
members = forms.CharField(widget=forms.TextInput(attrs={'style': 'width:70px'}), required=False)
class Meta:
model = Statistic
exclude = ('exposition')
def clean_year(self):
cleaned_data = super(StatisticForm, self).clean()
year = cleaned_data.get('year').strip()
return is_positive_integer(year)
def clean_members(self):
cleaned_data = super(StatisticForm, self).clean()
members = cleaned_data.get('members').strip()
return is_positive_integer(members)
def clean_visitors(self):
cleaned_data = super(StatisticForm, self).clean()
visitors = cleaned_data.get('visitors').strip()
return is_positive_integer(visitors)
from functions.files import check_tmp_timetables
class TimeTableForm(forms.Form):
begin = forms.DateTimeField(label='Время начала', widget=forms.TextInput(attrs={'style':'width: 150px'}))
end = forms.DateTimeField(label='Время окончания', widget=forms.TextInput(attrs={'style':'width: 150px'}))
begin = forms.DateTimeField(label='Время начала', input_formats=date_formats,
widget=forms.TextInput(attrs={'style':'width: 150px'}))
end = forms.DateTimeField(label='Время окончания', input_formats=date_formats,
widget=forms.TextInput(attrs={'style':'width: 150px'}))
timetable_organiser = forms.ModelChoiceField(label='Организатор', queryset=Organiser.objects.all(), empty_label='', required=False)
# uses for comparing with TmpTimetable key
key = forms.CharField(required=False, widget=forms.HiddenInput())
def __init__(self, *args, **kwargs):
"""
@ -299,7 +417,29 @@ class TimeTableForm(forms.Form):
# uses enumerate for detect iteration number
# first iteration is a default lang so it required fields
required = True if lid == 0 else False
self.fields['name_%s' % code] = forms.CharField(label='Название', required=required)
self.fields['programe_%s' % code] = forms.CharField(label='Программа', required=required,
widget=TinyMCE())
self.fields['speaker_%s' % code] = forms.CharField(label='Спикеры', required=False,
widget=forms.TextInput(attrs={'style':'width: 550px'}))
def save(self, id=None):
pass
def save(self,exposition=None):
data = self.cleaned_data
if not exposition:
timetable = TmpTimeTable()
timetable.key = data.get('key')
else:
timetable = TimeTable()
# simple fields
if data.get('timetable_organiser'):
timetable.timetable_organiser = data['timetable_organiser']
timetable.exposition = exposition
timetable.begin = data.get('begin')
timetable.end = data.get('end')
if not exposition:
fill_with_signal(TmpTimeTable, timetable, data)
else:
fill_with_signal(TimeTable, timetable, data)
return timetable

@ -1,39 +1,55 @@
# -*- coding: utf-8 -*-
from django.db import models
from django.db.models.signals import post_save, pre_save
from django.utils.translation import ugettext as _
from hvad.models import TranslatableModel, TranslatedFields, TranslationManager
import copy
import copy, datetime
from django.contrib.contenttypes import generic
from bitfield import BitField
from service.models import Service
from functions.db import db_table_exists
from organiser.models import Organiser
#
from functions.custom_fields import EnumField
from functions.signal_handlers import post_save_handler, pre_save_handler
from functions.models_methods import ExpoManager
from functions.model_mixin import EventMixin
AUDIENCE1 = ((None,'Не выбрано'),
('experts', 'Специалисты'),
('experts and consumers', 'Специалисты и потребители'),
('general public', 'Широкая публика'))
AUDIENCE1 = ((None,_(u'Не выбрано')),
('experts', _(u'Специалисты')),
('experts and consumers', _(u'Специалисты и потребители')),
('general public', _(u'Широкая публика'))
)
AUDIENCE = (None,'experts', 'experts and consumers', 'general public')
BIT_AUDIENCE = (('experts', _(u'Специалисты')), ('experts and consumers', _(u'Специалисты и потребители')),
('general public', _(u'Широкая публика')))
CURRENCY = ('RUB', 'USD', 'EUR')
# check if table exist and create flags if true
flags = [str(item.id) for item in Service.objects.all()] if db_table_exists('service_service') else []
class ExpositionManager(TranslationManager):
def safe_get(self, **kwargs):
model = self.model
try:
return model.objects.get(**kwargs)
except:
return None
class Exposition(TranslatableModel):
class Exposition(TranslatableModel, EventMixin):
"""
Create Exposition model
Uses hvad.TranslatableModel which is child of django.db.models class
"""
#set manager of this model
objects = ExpositionManager()
objects = ExpoManager()
url = models.SlugField(unique=True)
data_begin = models.DateField(verbose_name='Дата начала')
data_end = models.DateField(verbose_name='Дата окончания')
#relations
services = BitField(flags=flags)
quality_label = BitField(flags=['ufi', 'rsva', 'exporating'])
audience = BitField(flags=[k for k, v in BIT_AUDIENCE])
# relations
country = models.ForeignKey('country.Country', verbose_name='Страна', on_delete=models.PROTECT)
city = models.ForeignKey('city.City', verbose_name='Город', on_delete=models.PROTECT)
place = models.ForeignKey('place_exposition.PlaceExposition', verbose_name='Место проведения',
@ -45,18 +61,20 @@ class Exposition(TranslatableModel):
organiser = models.ManyToManyField('organiser.Organiser', verbose_name='Организатор',
blank=True, null=True, related_name='exposition_organisers')
company = models.ManyToManyField('company.Company', verbose_name='Компании',
blank=True, null=True, related_name='exposition_compamies')
blank=True, null=True, related_name='exposition_companies')
users = models.ManyToManyField('accounts.User', verbose_name='Посетители выставки',
blank=True, null=True, related_name='exposition_users')
#service = models.ManyToManyField('service.Service', verbose_name='Услуги',
# blank=True, null=True, related_name='exposition_services')
periodic = models.FloatField(verbose_name='Переодичность', blank=True, null=True)
audience = EnumField(values=AUDIENCE, blank=True)
#audience = EnumField(values=AUDIENCE, blank=True)
web_page = models.CharField(verbose_name='Вебсайт', max_length=255, blank=True)
foundation_year = models.PositiveIntegerField(verbose_name='Год основания', blank=True, null=True)
min_area = models.PositiveIntegerField(verbose_name='Минимальная площадь', blank=True, null=True)
#
currency = EnumField(values=CURRENCY, default='RUB')
price_day = models.PositiveIntegerField(verbose_name='Стоимость билета 1 день', blank=True, null=True)
price_all = models.PositiveIntegerField(verbose_name='Стоимость билета все дни', blank=True, null=True)
price_catalog = models.PositiveIntegerField(verbose_name='Стоимость каталога', blank=True, null=True)
tax = models.BooleanField(verbose_name='Налог', default=1)
min_closed_area = models.PositiveIntegerField(verbose_name='Минимальная цена закрытой НЕ оборудованной площади',
blank=True, null=True)
@ -72,44 +90,83 @@ class Exposition(TranslatableModel):
blank=True, null=True)
registration_payment = models.PositiveIntegerField(verbose_name='Регистрационный взнос', blank=True, null=True)
discount = models.PositiveIntegerField(verbose_name='Скидка', blank=True, null=True)
expohit = models.BooleanField(verbose_name='Expohit', default=0)
#administrator can cancel exposition
canceled_by_administrator = models.BooleanField(default=0)
#can publish not immediately
is_published = models.BooleanField(default=0)
canceled = models.BooleanField(default=0)
moved = models.BooleanField(default=0)
files = generic.GenericRelation('file.FileModel', content_type_field='content_type', object_id_field='object_id')
# statistic
foundation_year = models.PositiveIntegerField(verbose_name='Год основания', blank=True, null=True)
visitors = models.PositiveIntegerField(verbose_name='Посетители', blank=True, null=True)
members = models.PositiveIntegerField(verbose_name='Участники', blank=True, null=True)
translations = TranslatedFields(
name = models.CharField(verbose_name='Название', max_length=255),
main_title = models.TextField(verbose_name='Краткое описание', blank=True),
description = models.TextField(verbose_name='Описание', blank=True),
products = models.TextField(verbose_name='Экспонируемые продукты', blank=True),
discount_description = models.TextField(verbose_name='Описание скидки', blank=True),
time = models.TextField(verbose_name='Время работы', blank=True),
#-----meta data
title = models.CharField(max_length=250),
descriptions = models.CharField(max_length=250),
keywords = models.CharField(max_length=250),
)
#field saves information about creating and changing model
# field saves information about creating and changing model
created = models.DateTimeField(auto_now_add=True)
modified = models.DateTimeField(auto_now=True)
#mark
views = models.PositiveIntegerField(null=True, default=0)
def __unicode__(self):
return self.lazy_translation_getter('name', unicode(self.pk))
def cancel(self):
self.canceled_by_administrator = True
def get_audience(self):
checked = [item for item, bool in self.audience if bool==True]
audience = []
for k, v in BIT_AUDIENCE:
for item in checked:
if item == k:
audience.append(v)
return ', '.join(audience)
def get_periodic(self):
periodic = {0: '', 1.0: _(u'Ежегодно'), 2.0: _(u'2 раза в год'), 3.0: _(u'3 раза в год'),
4.0: _(u'4 раза в год'), 5.0: _(u'5 раз в год'), 0.5: _(u'Раз в 2 года'),
0.33: _(u'Раз в 3 года'), 0.25: _(u'Раз в 4 года')}
return periodic.get(self.periodic)
def get_nearest_events(self):
theme = self.theme.all()[0]
now = datetime.datetime.now()
now = now.replace(day=now.day-1)
expositions = Exposition.objects.filter(theme__in=[theme], data_begin__gt=now).exclude(id=self.id)
return expositions[3:]
def get_catalog_url(self):
return '/expositions/'
def get_event_type(self):
return _(u'Выставки')
def get_calendar_url(self):
return '/exposition-add-calendar/%s/'%self.id
def get_visit_url(self):
return '/exposition-visit/%s/'%self.id
def on(self):
self.is_published = True
self.canceled_by_administrator = False
self.save()
def off(self):
self.is_published = False
self.canceled_by_administrator = True
self.save()
def clone(self):
"""
@ -131,6 +188,16 @@ class Exposition(TranslatableModel):
duplicate.is_published = False
duplicate.cancel_by_administrator = False
ignore_fields = ['id', 'master', 'language_code']
duplicate.translate('ru')
tr = self._meta.translations_model.objects.get(language_code = 'ru',master__id=self.pk)
for field in duplicate._translated_field_names:
if field in ignore_fields:
continue
setattr(duplicate, field, getattr(tr, field))
duplicate.save()
# but lost all ManyToMany relations and Translations.
@ -141,24 +208,17 @@ class Exposition(TranslatableModel):
for item in source.all():
destination.add(item)
# copy translations
languages = self.get_available_languages()
ignore_fields = ['id', 'master', 'language_code']
for code in languages:
duplicate.translate(code)
tr = self._meta.translations_model.objects.get(language_code = code,master__id=self.pk)
for field in duplicate._translated_field_names:
if field in ignore_fields:
continue
setattr(duplicate, field, getattr(tr, field))
return duplicate
duplicate.save()
return duplicate
class Statistic(models.Model):
exposition = models.ForeignKey(Exposition, related_name='statistic')
year = models.PositiveIntegerField(verbose_name='Год')
members = models.PositiveIntegerField(verbose_name='Посетители')
visitors = models.PositiveIntegerField(verbose_name='Участники')
from django.core import serializers
from functions.models_methods import hvad_to_dict
class TimeTable(TranslatableModel):
"""
@ -168,7 +228,64 @@ class TimeTable(TranslatableModel):
exposition = models.ForeignKey(Exposition, related_name='business_program')
begin = models.DateTimeField(verbose_name='Начало')
end = models.DateTimeField(verbose_name='Конец')
timetable_organiser = models.ForeignKey(Organiser, null=True, blank=True)
#
created = models.DateTimeField(auto_now_add=True)
modified = models.DateTimeField(auto_now=True)
#translated fields
translations = TranslatedFields(
name = models.CharField(verbose_name='Название', max_length=255)
)
programe = models.TextField(verbose_name='Программа'),
speaker = models.CharField(verbose_name='Спикеры', max_length=255, blank=True)
)
def to_dict(self):
#obj = serializers.serialize('json', [self,])
return hvad_to_dict(self)
class TmpTimeTable(TranslatableModel):
exposition = models.ForeignKey(Exposition, null=True, blank=True)
begin = models.DateTimeField(verbose_name='Начало')
end = models.DateTimeField(verbose_name='Конец')
timetable_organiser = models.ForeignKey(Organiser, null=True, blank=True)
# key uses for checking keys from new objects.
key = models.CharField(max_length=255, blank=True)
#
created = models.DateTimeField(auto_now_add=True)
modified = models.DateTimeField(auto_now=True)
#translated fields
translations = TranslatedFields(
programe = models.TextField(verbose_name='Программа'),
speaker = models.CharField(verbose_name='Спикеры', max_length=255, blank=True)
)
def clone(self, exposition=None):
"""
Return an identical copy of the instance with a new ID.
"""
if not self.pk:
raise ValueError('Instance must be saved before it can be cloned.')
duplicate = copy.copy(self)
# Setting pk to None. Django thinking this is a new object.
duplicate.pk = None
duplicate.exposition = exposition
ignore_fields = ['id', 'master', 'language_code']
duplicate.translate('ru')
tr = self._meta.translations_model.objects.get(language_code = 'ru',master__id=self.pk)
for field in duplicate._translated_field_names:
if field in ignore_fields:
continue
setattr(duplicate, field, getattr(tr, field))
duplicate.save()
return duplicate
pre_save.connect(pre_save_handler, sender=Exposition)
post_save.connect(post_save_handler, sender=Exposition)
post_save.connect(post_save_handler, sender=TimeTable)
post_save.connect(post_save_handler, sender=TmpTimeTable)

@ -0,0 +1,15 @@
"""
from haystack import indexes
from models import Exposition
class ExpositionIndex(indexes.SearchIndex, indexes.Indexable):
text = indexes.CharField(document=True)
def get_model(self):
return Exposition
def index_queryset(self, using=None):
return self.get_model().objects.filter()
"""

@ -3,4 +3,4 @@ from django.db.models.signals import post_save
from models import Exposition
from functions.signal_handlers import post_save_handler
post_save.connect(post_save_handler, sender=Exposition)
#post_save.connect(post_save_handler, sender=Exposition)

@ -0,0 +1,18 @@
# -*- coding: utf-8 -*-
from django.conf.urls import patterns, include, url
from views import ExpositionView, ExpositionVisitors, ExpositionMembers
urlpatterns = patterns('',
url(r'expositions/(?P<params>.*)/(?P<page>\d+)/$', ExpositionView.as_view()),
url(r'expositions/(?P<page>\d+)/$', ExpositionView.as_view()),
url(r'expositions/(?P<params>.*)/visitors/$', ExpositionVisitors.as_view()),
url(r'expositions/(?P<params>.*)/members/$', ExpositionMembers.as_view()),
url(r'expositions/(?P<params>.*)/$', ExpositionView.as_view()),
url(r'expositions/$', ExpositionView.as_view()),
#
url(r'exposition-add-calendar/(?P<id>\d+)/$', 'exposition.views.exposition_add_calendar'),
url(r'exposition-remove-calendar/(?P<id>\d+)/$', 'exposition.views.exposition_remove_calendar'),
url(r'exposition-visit/(?P<id>\d+)/$', 'exposition.views.exposition_visit'),
url(r'exposition-unvisit/(?P<id>\d+)/$', 'exposition.views.exposition_unvisit'),
)

@ -0,0 +1,118 @@
# -*- coding: utf-8 -*-
from django.shortcuts import render_to_response
from django.http import HttpResponseRedirect, HttpResponse
from django.template import RequestContext
from django.shortcuts import get_object_or_404
from django.core.paginator import Paginator, PageNotAnInteger, EmptyPage
#models
from models import Exposition
from accounts.models import User
from functions.custom_views import ExpoListView, ExpoMixin
from django.views.generic import ListView
#
import json
from django.utils.translation import ugettext as _
class ExpositionView(ExpoListView):
model = Exposition
template_name = 'event_catalog.html'
class ExpositionVisitors(ExpositionView):
model = Exposition
template_name = 'event_visitors.html'
def get_queryset(self):
params = self.get_params()
for param in params:
if param.get('type') == 'event':
exp = Exposition.objects.safe_get(url=param.get('url'))
#query = exp.users
param['name'] = exp.name
params.append({'type':'visitors', 'name':_(u'Посетители')})
self.params = params
return exp.users.all()
class ExpositionMembers(ExpoListView):
model = Exposition
template_name = 'event_members.html'
def get_queryset(self):
params = self.get_params()
for param in params:
if param.get('type') == 'event':
exp = Exposition.objects.safe_get(url=param.get('url'))
param['name'] = exp.name
#query = exp.users
params.append({'type':'members', 'name':_(u'Участники')})
self.params = params
return exp.company.all()
def exposition_add_calendar(request, id):
args = {'success': False}
user = request.user
if user.is_authenticated():
exp = Exposition.objects.safe_get(id=id)
if exp:
user.calendar.expositions.add(exp)
args['success'] = True
else:
args['not_authorized'] = True
args['success'] = True
return HttpResponse(json.dumps(args), content_type='application/json')
def exposition_remove_calendar(request, id):
args = {'success': False}
user = request.user
if user.is_authenticated():
exp = Exposition.objects.safe_get(id=id)
if exp:
user.calendar.expositions.remove(exp)
args['success'] = True
else:
args['not_authorized'] = True
args['success'] = True
return HttpResponse(json.dumps(args), content_type='application/json')
def exposition_visit(request, id):
args = {'success': False}
user = request.user
if user.is_authenticated():
exp = Exposition.objects.safe_get(id=id)
if exp:
exp.users.add(user)
args['success'] = True
else:
args['not_authorized'] = True
args['success'] = True
return HttpResponse(json.dumps(args), content_type='application/json')
def exposition_unvisit(request, id):
args = {'success': False}
user = request.user
if user.is_authenticated():
exp = Exposition.objects.safe_get(id=id)
if exp:
exp.users.remove(user)
else:
args['not_authorized'] = True
args['success'] = True
return HttpResponse(json.dumps(args), content_type='application/json')

@ -40,7 +40,7 @@ class FileModelForm(forms.Form):
# using enumerate for detect iteration number
# first iteration is a default lang so it required fields
required = True if lid == 0 else False
self.fields['file_name_%s'%code] = forms.CharField(label='Имя файла',required=required, widget=forms.TextInput(attrs={'placeholder': 'Имя'}))
self.fields['file_name_%s'%code] = forms.CharField(label='Имя файла',required=False, widget=forms.TextInput(attrs={'placeholder': 'Имя'}))
self.fields['description_%s'%code] = forms.CharField(label='Описание', required=False, widget=CKEditorWidget())
def save(self, request, obj=None):

@ -95,7 +95,7 @@ class TmpFile(TranslatableModel):
img_width = models.PositiveIntegerField(blank=True, null=True)
img_height = models.PositiveIntegerField(blank=True, null=True)
#key uses for checking keys from new objects.
# key uses for checking keys from new objects.
# (if keys the same as in form move Tmpfile to FileModel)
key = models.CharField(max_length=255, blank=True)
created = models.DateTimeField(auto_now_add=True)

@ -1,3 +1,4 @@
import datetime
#https://djangosnippets.org/snippets/2607/
def required(wrapping_functions,patterns_rslt):
'''
@ -50,4 +51,5 @@ def _wrap_instance__resolve(wrapping_functions,instance):
return instance
#-----------------------------
#-----------------------------
datetime_handler = lambda obj: (obj.isoformat() if isinstance(obj, datetime.datetime) or isinstance(obj, datetime.date) else None)

@ -5,6 +5,7 @@ from django.core import exceptions
from django import forms
from django.utils.safestring import mark_safe
from django.conf import settings
from south.modelsinspector import add_introspection_rules
try:
import json
except:
@ -15,6 +16,8 @@ FILE_TYPES = ('PDF', 'DOC', 'TXT', 'OTHER')
IMG_TYPES = ('JPG', 'BMP', 'PNG', 'GIF',)
PURPOSES = ('photo', 'flat')
from south.modelsinspector import add_introspection_rules
add_introspection_rules([], ["^functions\.custom_fields\.EnumField", "^functions\.custom_fields\.LocationField"])
class EnumField(models.Field):

@ -1,30 +1,34 @@
# -*- coding: utf-8 -*-
from django.shortcuts import render_to_response
from django.http import HttpResponseRedirect
from django.http import HttpResponseRedirect, HttpResponse
from django.core.context_processors import csrf
from django.conf import settings
from django.contrib.auth.decorators import login_required
from django.contrib.admin.views.decorators import staff_member_required
from django.core.paginator import Paginator, PageNotAnInteger, EmptyPage
from django.core.paginator import Paginator, PageNotAnInteger, EmptyPage, InvalidPage
from django.db.models.deletion import ProtectedError
#forms and models
from file.forms import FileModelForm
from file.models import TmpFile
from theme.models import Tag
from accounts.models import User
from functions.forms import AdminSearchForm
from django.utils.translation import get_language as lang
from hvad.utils import get_translation_aware_manager
#python
import random
from country.models import Country
@staff_member_required
def objects_list(request, Model, template, item_per_page=10):
@login_required
def filtered_list(request, objects, template, item_per_page=20):
"""
Return template with all objects of model Model
Model - objects Model
Return template with objects in it with pagination
item_per_page - how many objects view in the one page
"""
list = Model.objects.all()
paginator = Paginator(list, item_per_page)
paginator = Paginator(objects, item_per_page)
page = request.GET.get('page')
try:
objects = paginator.page(page)
@ -34,16 +38,33 @@ def objects_list(request, Model, template, item_per_page=10):
except EmptyPage:
# If page is out of range (e.g. 9999), deliver last page of results.
objects = paginator.page(paginator._num_pages)
return render_to_response(template, {'objects': objects})
return render_to_response(template, {'objects': objects, 'search_form': AdminSearchForm()})
@login_required
def filtered_list(request, objects, template, item_per_page=10):
from django.db.models.loading import get_model
from theme.models import Theme
@staff_member_required
def objects_list(request, Model, template, item_per_page=20):
"""
Return template with objects in it with pagination
Return template with all objects of model Model
Model - objects Model
item_per_page - how many objects view in the one page
"""
paginator = Paginator(objects, item_per_page)
if request.GET:
form = AdminSearchForm(request.POST)
if form.is_valid():
s_name = request.GET.get('search_name')
if s_name:
objects = get_translation_aware_manager(Model).filter(name__contains=s_name).distinct()
return filtered_list(request, objects, template, 1000)
else:
list = Model.objects.all()
else:
list = Model.objects.all()
paginator = Paginator(list, item_per_page)
page = request.GET.get('page')
try:
objects = paginator.page(page)
@ -53,8 +74,7 @@ def filtered_list(request, objects, template, item_per_page=10):
except EmptyPage:
# If page is out of range (e.g. 9999), deliver last page of results.
objects = paginator.page(paginator._num_pages)
return render_to_response(template, {'objects': objects})
return render_to_response(template, {'objects': objects, 'search_form': AdminSearchForm()})
@login_required
def add_object(request, Form, template_string, redirect_string, #required values
@ -163,4 +183,108 @@ def delete_object(request, Model, Form, url, prev_page,):
args['object'] = object
args['prev_page'] = prev_page
return render_to_response('delete.html', args)
return render_to_response('delete.html', args)
#-----class------------------
from django.views.generic import ListView
from functions.views_help import split_params
from city.models import City
from exposition.models import Exposition
from conference.models import Conference
from seminar.models import Seminar
from webinar.models import Webinar
from company.models import Company
from django.utils.translation import ugettext as _
class ExpoMixin(object):
def get_params(self):
model_names = {Exposition: _(u'Выставки'), Conference: _(u'Конференции'),
Seminar: _(u'Семинары'),Webinar: _(u'Вебинары'), Company: _(u'Участники')}
model_alternative_name = {Exposition: 'exposition', Conference: 'conference'}
params = [{'type':'model', 'url':self.model, 'name': model_names.get(self.model),
'alternative_name': model_alternative_name.get(self.model)}]
st = self.kwargs.get('params')
if st:
params = params + split_params(st)
return params
single_page_filter = {Exposition:'event', Conference:'event', Seminar:'event', Webinar:'event', Company:'member',
User:'visitor'}
class ExpoListView(ExpoMixin, ListView):
"""
"""
paginate_by = 2
params = None
single_page = False
def get_queryset(self):
query = self.model.objects.all()
params = self.get_params()
for param in params:
if param.get('type') == 'country':
country = Country.objects.safe_get(url=param.get('url'))
if country:
param['name'] = country.name
query = query.filter(country=country)
if param.get('type') == 'city':
city = City.objects.safe_get(url=param.get('url'))
if city:
param['name'] = city.name
query = query.filter(city=city)
if param.get('type') == 'theme':
theme = Theme.objects.safe_get(url=param.get('url'))
if theme:
param['name'] = theme.name
query = query.filter(theme=theme)
if param.get('type') == 'tag':
tag = Tag.objects.safe_get(url=param.get('url'))
if tag:
param['name'] = tag.name
query = query.filter(tag=tag)
if param.get('type') == 'year':
param['name'] = param.get('url')
query = query.filter(data_begin__year=param.get('url'))
if param.get('type') == 'month':
monthes = {'jan': 1, 'feb': 2, 'mar': 3, 'apr': 4, 'may': 5, 'jun': 6,
'jul': 7, 'aug': 8, 'sep': 9, 'oct': 10, 'nov': 11, 'dec': 12}
param['name'] = param.get('url')
query = query.filter(data_begin__month=monthes.get(param.get('url')))
if param.get('type') == 'member' and self.model != Company:
param['name'] = param.get('url')
company = Company.objects.safe_get(url=param.get('url'))
if company:
param['name'] = company.name
query = query.filter(company__in=[company])
if param.get('type') == single_page_filter.get(self.model):
query = query.filter(url=param.get('url'))
if query:
self.single_page = True
param['name'] = query[0].name
#if self.request:
# views = query[0].views
# query.update(views=views+1)
self.params = params
return query
def get_context_data(self, **kwargs):
context = super(ExpoListView, self).get_context_data(**kwargs)
context['filter'] = self.params
context['single_page'] = self.single_page
return context

@ -91,4 +91,32 @@ def check_tmp_files(object, key=None):
file_obj.description = trans_object.description
file_obj.save()
list.delete()
list.delete()
from exposition.models import TmpTimeTable, TimeTable
from functions.translate import fill_with_signal
def check_tmp_timetables(object, key=None):
"""
object - exposition to which we saved timetable
"""
if key:
temp_objects = TmpTimeTable.objects.filter(key=key)
for obj in temp_objects:
timetable = TimeTable(begin=obj.begin, end=obj.end, exposition=object,
timetable_organiser=obj.timetable_organiser)
data = {}
for code, name in settings.LANGUAGES:
#timetable.translate(code)
trans_object = TmpTimeTable._meta.translations_model.objects.get(language_code = code,master__id=getattr(obj,'id'))
data['programe_%s'%code] = trans_object.programe
data['speaker_%s'%code] = trans_object.speaker
fill_with_signal(TimeTable, timetable, data)
temp_objects.delete()
else:
pass

@ -21,7 +21,9 @@ def translit_with_separator(string, separator='-'):
usage: translit_with_separator('введите, слово', '_') return 'vvedite_slovo'
"""
string = string.strip()
#make string unicode
string = u'%s'%string
#make string translit
st = pytils.translit.translify(string)

@ -0,0 +1,18 @@
# -*- coding: utf-8 -*-
from django import forms
from django.utils.translation import ugettext_lazy as _
from theme.models import Theme
class AdminSearchForm(forms.Form):
search_name = forms.CharField(required=False, max_length=50)
class ThemeSearch(forms.Form):
event = forms.MultipleChoiceField(required=False,widget=forms.CheckboxSelectMultiple, choices=[(0, _(u'выставки')),
(1, _(u'конференции')),
(2, _(u'семинары')),
(3, _(u'вебинары'))])
theme = forms.ModelMultipleChoiceField(required=False, queryset=Theme.objects.all(),
widget=forms.CheckboxSelectMultiple)

@ -0,0 +1,61 @@
from service.models import Service
class ExpoMixin(object):
def get_logo(self):
logo = self.files.filter(purpose='logo')
if logo:
return logo[0]
return logo
def get_preview(self):
preview = self.files.filter(purpose='preview')
if preview:
return preview[0]
return preview
def get_photos(self):
photos = self.files.filter(purpose='photo')
return photos
class EventMixin(object):
def get_permanent_url(self):
url = '%sevent-%s'%(self.get_catalog_url(), self.url)
return url
def get_logo(self):
logo = self.files.filter(purpose='logo')
if logo:
return logo[0]
return logo
def get_preview(self):
preview = self.files.filter(purpose='preview')
if preview:
return preview[0]
return preview
def get_photos(self):
photos = self.files.filter(purpose='photo')
return photos
def on(self):
self.is_published = True
self.canceled_by_administrator = False
self.save()
def off(self):
self.is_published = False
self.canceled_by_administrator = True
self.save()
def cancel(self):
self.canceled_by_administrator = True
def get_services(self):
ids = [item for item, bool in self.services if bool==True]
return [Service.objects.get(id=id) for id in ids]

@ -0,0 +1,27 @@
from django.utils.translation import get_language
from hvad.models import TranslationManager
class ExpoManager(TranslationManager):
def all(self, lang=None):
if lang:
return super(ExpoManager, self).language(lang).all().order_by('name')
else:
return super(ExpoManager, self).language(get_language()).all().order_by('name')
def safe_get(self, **kwargs):
model = self.model
try:
return model.objects.get(**kwargs)
except:
return None
def hvad_to_dict(object):
"""
"""
value = object.__dict__
lang = get_language()
bad_fields = ['master_id', 'id', 'language_code']
value.update({key:value for key, value in object.translations.filter(language_code=lang).values()[0].iteritems() if key not in bad_fields})
return value

@ -45,6 +45,7 @@ def fill_meta_information(obj):
# get Setting model object
setting = Setting.objects.get(key=s.get('key'))
field = s.get('field_name')
if setting.type != 'transl':
# simple field
if getattr(obj, field)=="":
@ -57,5 +58,11 @@ def fill_meta_information(obj):
tr = obj._meta.translations_model.objects.get(language_code=code, master__id=getattr(obj, 'id'))
if getattr(tr, field)=="":
setattr(tr, field, setting.get_value(code))
value = setting.get_value(code)
try:
value = value%tr.__dict__
except KeyError:
pass
# ! charfield -> textfield
setattr(tr, field, value[:250])
tr.save()

@ -1,7 +1,37 @@
from form_check import translit_with_separator
from signal_additional_func import fill_missing_languages, fill_meta_information
import random, string
from functions.form_check import translit_with_separator
def pre_save_handler(sender, **kwargs):
obj = kwargs['instance']
if obj.language_code =='en':
print('bla')
try:
name = getattr(obj, 'name')
obj.url = translit_with_separator(name)
except AttributeError:
pass
if not obj.url:
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
@ -14,7 +44,7 @@ def post_save_handler(sender, **kwargs):
fill_missing_languages(obj)
fill_meta_information(obj)
from country.models import Country
'''
def post_save_translation_handler(sender, **kwargs):
"""
receiver function
@ -22,8 +52,6 @@ def post_save_translation_handler(sender, **kwargs):
"""
obj = kwargs['instance']
if obj.language_code == 'ru':
c = Country.objects.all()[0]
c.url = 'tttt'
c.save()
#obj.master.url = translit_with_separator(obj.name)
#obj.master.save()
obj.master.url = translit_with_separator(obj.name)
obj.master.save()
'''

@ -9,4 +9,15 @@ def get_referer(request, default=None):
referer = re.sub('^https?:\/\/', '', referer).split('/')
# add the slash at the relative path's view and finished
referer = u'/' + u'/'.join(referer[1:])
return referer
return referer
def split_params(st):
st = st.split('/')
params = []
for item in st:
n = item.find('-')
if n != -1:
params.append({'type': item[:n], 'url':item[n+1:]})
return params

@ -0,0 +1,111 @@
# -*- 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
from django.views.generic import FormView
from django.contrib import messages
def xls_to_response(xls, fname):
response = HttpResponse(mimetype="application/ms-excel")
response['Content-Disposition'] = 'attachment; filename=%s' % fname
xls.save(response)
return response
class ImportView(FormView):
"""
abstract class
"""
template_name = 'import.html'
def form_valid(self, form):
form.save_file()
messages.success(self.request, 'Success')
return super(ImportView, self).form_valid(form)
class ExportView(FormView):
"""
abstract class
"""
template_name = 'export.html'
def form_valid(self, form):
workbook = form.export()
if workbook:
f_name = form.get_fname()
else:
messages.error(self.request, 'No objects found')
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 ImportEvent(ImportView):
form_class = ImportEventForm
success_url = '/admin/import-event'
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
template_name = 'export_event.html'
success_url = '/admin/export-event'

@ -0,0 +1,25 @@
# -*- 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
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()),
url(r'^export-company/$', ExportCompany.as_view()),
)

@ -1,4 +1,5 @@
# -*- coding: utf-8 -*-
from accounts.models import User
from country.models import Country
from city.models import City
from theme.models import Theme, Tag
@ -14,21 +15,24 @@ def get_int(value):
return ''
return value
from bitfield import BitHandler
from exposition.models import BIT_AUDIENCE
def get_audience(value):
if not value:
return 'Не выбрано'
elif value == 'experts':
return 'Специалисты'
elif value == 'experts and consumers':
return 'Специалисты и потребители'
elif value == 'general public':
return 'Широкая публика'
else:
return ''
if isinstance(value, BitHandler):
l = [k for k, v in value.iteritems() if v]
if l:
new_list = []
for value in l:
for item1, item2 in BIT_AUDIENCE:
if value == item1:
new_list.append(item2)
return ', '.join(new_list)
return
def get_theme(value):
objects = value.all()
return ', '.join(str(obj) for obj in objects)
return ','.join(str(obj.id) for obj in objects)
def get_tag(tag, theme):
@ -37,47 +41,58 @@ def get_tag(tag, theme):
result = ''
for theme in themes:
# list of tags with current theme
tag_list = [str(tag) for tag in tags if tag.theme == theme]
tag_list = [str(tag.id) for tag in tags if tag.theme == theme]
result += '['+', '.join(tag_list)+']'
result += '['+','.join(tag_list)+']'
return result
def get_place_type():
pass
field_settings = [
{'name': 'id', 'verbose_name': 'id', 'type': get_int, 'width':1500},
{'name': 'url', 'verbose_name': 'url', 'type': str},
{'name': 'name', 'verbose_name': 'Имя', 'type': str, 'width':8000},
{'name': 'data_begin', 'verbose_name': 'Дата начала', 'type': str},
{'name': 'data_end', 'verbose_name': 'Дата окончания', 'type': str},
{'name': 'audience', 'verbose_name': 'Аудитория', 'type': get_audience},
{'name': 'main_title', 'verbose_name': 'Краткое описание', 'type': str},
{'name': 'description', 'verbose_name': 'Описание', 'type': str},
{'name': 'country', 'verbose_name': 'Страна', 'type': str},
{'name': 'city', 'verbose_name': 'Город', 'type': str},
{'name': 'theme', 'verbose_name': 'Тематика', 'type': get_theme, 'width':8000},
{'name': 'tag', 'verbose_name': 'Теги', 'type': get_tag, 'width':8000},
{'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, 'width':8000},
{'name': 'data_begin', 'verbose_name': u'Дата начала', 'type': unicode},
{'name': 'data_end', 'verbose_name': u'Дата окончания', 'type': unicode},
{'name': 'audience', 'verbose_name': u'Аудитория', 'type': get_audience},
{'name': 'main_title', 'verbose_name': u'Краткое описание', 'type': unicode},
{'name': 'description', 'verbose_name': u'Описание', 'type': unicode},
{'name': 'country', 'verbose_name': u'Страна', 'type': unicode},
{'name': 'city', 'verbose_name': u'Город', 'type': unicode},
{'name': 'theme', 'verbose_name': u'Тематика', 'type': get_theme, 'width':8000},
{'name': 'tag', 'verbose_name': u'Теги', 'type': get_tag, 'width':8000},
{'name': 'address', 'verbose_name': u'Адрес', 'type': unicode},
#{'name': 'periodic', 'verbose_name': 'Периодичность', 'type': str},
{'name': 'web_page', 'verbose_name': 'Веб страница', 'type': str},
{'name': 'time', 'verbose_name': 'Время проведения', 'type': str},
{'name': 'products', 'verbose_name': 'Экспонируемые продукты', 'type': str},
{'name': 'foundation_year', 'verbose_name': 'Год основания', 'type': get_int},
{'name': 'tax', 'verbose_name': 'Налог включен', 'type': get_bool, 'width':1000},
{'name': 'currency', 'verbose_name': 'Валюта', 'type': str},
{'name': 'max_price', 'verbose_name': 'Максимальная цена', 'type': get_int},
{'name': 'min_price', 'verbose_name': 'Минимальная цена', 'type': get_int},
{'name': 'registration_payment', 'verbose_name': 'Регистрационный взнос', 'type': get_int},
{'name': 'min_closed_area', 'verbose_name': 'Минимальная цена закрытой НЕ оборудованной площади', 'type': get_int},
{'name': 'max_closed_area', 'verbose_name': 'Максимальная цена закрытой НЕ оборудованной площади', 'type': get_int},
{'name': 'min_closed_equipped_area', 'verbose_name': 'Минимальная цена закрытой оборудованной площади ', 'type': get_int},
{'name': 'max_closed_equipped_area', 'verbose_name': 'Максимальная цена закрытой оборудованной площади', 'type': get_int},
{'name': 'min_open_area', 'verbose_name': 'Минимальная цена закрытой площади', 'type': get_int},
{'name': 'max_open_area', 'verbose_name': 'Максимальная цена открытой площади', 'type': get_int},
{'name': 'min_area', 'verbose_name': 'Минимальная площадь', 'type': get_int},
{'name': 'max_area', 'verbose_name': 'Максимальная площадь', 'type': get_int},
{'name': 'is_published', 'verbose_name': 'Опубликована', 'type': get_bool},
{'name': 'canceled_by_administrator', 'verbose_name': 'Отменена администратором', 'type': get_bool}
{'name': 'web_page', 'verbose_name': u'Веб страница', 'type': unicode},
{'name': 'email', 'verbose_name': u'Email', 'type': unicode},
{'name': 'phone', 'verbose_name': u'Телефон', 'type': get_int},
{'name': 'time', 'verbose_name': u'Время проведения', 'type': unicode},
{'name': 'products', 'verbose_name': u'Экспонируемые продукты', 'type': unicode},
{'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': 'foundation_year', 'verbose_name': u'Год основания', 'type': get_int},
{'name': 'tax', 'verbose_name': u'Налог включен', 'type': get_bool, 'width':1000},
{'name': 'currency', '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},
{'name': 'min_closed_area', 'verbose_name': u'Минимальная цена закрытой НЕ оборудованной площади', 'type': get_int},
{'name': 'max_closed_area', 'verbose_name': u'Максимальная цена закрытой НЕ оборудованной площади', 'type': get_int},
{'name': 'min_closed_equipped_area', 'verbose_name': u'Минимальная цена закрытой оборудованной площади ', 'type': get_int},
{'name': 'max_closed_equipped_area', 'verbose_name': u'Максимальная цена закрытой оборудованной площади', 'type': get_int},
{'name': 'min_open_area', 'verbose_name': u'Минимальная цена закрытой площади', 'type': get_int},
{'name': 'max_open_area', 'verbose_name': u'Максимальная цена открытой площади', 'type': get_int},
{'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},
{'name': 'canceled_by_administrator', 'verbose_name': u'Отменена администратором', 'type': get_bool}
]
@ -122,85 +137,102 @@ def to_city(value, lang, country):
return city
def to_audience(value):
try:
if value == 'Специалисты':
return 'experts'
elif value == 'Специалисты и потребители':
return 'experts and consumers'
elif value == 'Широкая публика':
return 'general public'
else:
return 'None'
except:
return 'None'
from exposition.models import Exposition
def to_audience(value, model=Exposition):
if value:
l = value.split(', ')
if l:
new_list = []
for value in l:
for item1, item2 in BIT_AUDIENCE:
if value == item2:
new_list.append(item1)
if new_list:
return reduce(lambda x,y: x|y, (getattr(model.audience, item) for item in new_list))
return 0
def to_theme(value, lang='ru'):
theme_names = value.split(', ')
def to_theme(value):
if isinstance(value, float):
if (value - int(value) > 0):
value = str(value)
else:
value = str(int(value))
theme_ids = value.split('.')
else:
theme_ids = value.split(',')
theme_objects = []
for name in theme_names:
for id in theme_ids:
try:
objects = get_translation_aware_manager(Theme)
theme = objects.filter(name=name)[0]
except:
theme = Theme()
theme.translate(lang)
theme.name = name
theme.save()
theme = Theme.objects.language().get(id=int(id))
theme_objects.append(theme)
except Theme.DoesNotExist, ValueError:
pass
theme_objects.append(theme)
return theme_objects
def to_tag(value, lang, themes):
if value == [""]:
return None
value = value.replace('[', '')
themes = themes.all()
# list tags by themes
value = value.split(']')
arr = []
bla = value[0].split(', ')
for theme_number, theme in enumerate(themes):
for val in value[theme_number].split(', '):
for val in value[theme_number].split(','):
if val:
try:
objects = get_translation_aware_manager(Tag)
tag = objects.language(lang).filter(name=val, theme=theme)
tag = tag[0]
except:
tag = Tag()
tag.theme = theme
tag.translate(lang)
tag.name = val
tag.save()
arr.append(tag)
tag = Tag.objects.language(lang).get(id=int(val), theme=theme)
arr.append(tag)
except Tag.DoesNotExist, ValueError:
pass
return arr
def to_theme_type(st):
if not st:
return 15
types = st.split(',')
flag = 0
flag = reduce(lambda x,y: x|y, (getattr(Theme.types, item) for item in types))
return flag
import time, xlrd
def to_date(value):
if isinstance(value, unicode):
t = time.strptime(value, "%d.%m.%Y")
if isinstance(value, float):
t = xlrd.xldate_as_tuple(value, 0)+(0,0,0)
return time.strftime("%Y-%m-%d", t)
import_settings={
'name': {'func': str, },
'url': {'func': str},
'data_begin': {'func': str},
'data_end': {'func': str},
'main_title': {'func': str},
'description': {'func': str},
'name': {'func': unicode, },
'url': {'func': unicode},
'data_begin': {'func': to_date},
'data_end': {'func': to_date},
'main_title': {'func': unicode},
'description': {'func': unicode},
'audience': {'func': to_audience},
'country': {'func': to_country},
'city': {'func': to_city, 'extra_values': 'country'},
'theme': {'func': to_theme},
'tag': {'func': to_tag, 'extra_values': 'theme'},
'periodic': {'func': str},
'web_page': {'func': str},
'time': {'func': str},
'products': {'func': str},
'periodic': {'func': unicode},
'web_page': {'func': unicode},
'time': {'func': unicode},
'products': {'func': unicode},
'foundation_year': {'func': to_int},
'tax': {'func': bool},
'currency': {'func': str},
'currency': {'func': unicode},
'max_price': {'func': to_int},
'min_price': {'func': to_int},
'registration_payment': {'func': to_int},
@ -213,5 +245,6 @@ import_settings={
'min_area': {'func': to_int},
'max_area': {'func': to_int},
'is_published': {'func': bool},
'canceled_by_administrator': {'func': bool}
}
'canceled_by_administrator': {'func': bool},
'types': {'func': to_theme_type}
}

@ -1,82 +1,123 @@
# -*- coding: utf-8 -*-
from django import forms
from django.conf import settings
from theme.models import Theme
from theme.models import Theme, Tag
from country.models import Country
from organiser.models import Organiser
from accounts.models import User
from company.models import Company
from place_exposition.models import PlaceExposition
from place_conference.models import PlaceConference
from django.db.models.loading import get_model
import xlrd, xlwt
import xlwt
from excel_settings import import_settings, field_settings
languages = [code for code in settings.LANGUAGES]
class ExportForm(forms.Form):
def __init__(self, *args, **kwargs):
super(ExportForm, self).__init__(*args, **kwargs)
self.workbook = xlwt.Workbook(encoding = 'utf8')
self.worksheet = self.workbook.add_sheet('My Worksheet')
class ImportEventForm(forms.Form):
excel_file = forms.FileField(label='Выберите файл')
event = forms.ChoiceField(label='Выберите тип события', choices=[('exposition.Exposition', 'Выставка'),
('conference.Conference', 'Конференция'),
('seminar.Seminar', 'Семинар'),
('webinar.Webinar', 'Вебинар')])
self.font = xlwt.Font()
self.font.name = 'Times New Roman'
self.font.bold = True
self.style = xlwt.XFStyle()
# Create the Style
self.style.font = self.font
model = None
language = forms.ChoiceField(label='Выберите язык', choices=languages)
def save_events(self):
"""
save events from excel file
in language from form
"""
def get_objects(self, data):
return self.model.objects.language(data['language']).all()
def get_fname(self):
return 'export list.xls'
def export(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[1]]
# model
model = get_model(data['event'].split('.')[0], data['event'].split('.')[1])
objects = self.get_objects(data)
if not objects:
# not found any objects
return None
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
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])
if row == 0:
# first iteration. set names. set columns width
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+2, col, field.get('type')(value, object.theme))
else:
# if id blank - its a new event
object = model()
object.translate(lang)
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)
# условие заглушка для мени ту мени
if object.id == None and (field_name=='theme' or field_name=='tag'):
pass
else:
value = func(cell, lang, getattr(object, extra_value))
else:
value = func(cell)
# условие заглушка для мени ту мени
if object.id == None and (field_name=='theme' or field_name=='tag'):
pass
else:
setattr(object, field_name, value)
object.save()
self.worksheet.write(row+2, col, field.get('type')(value))
col += 1
return self.workbook
class ExportOrganiserForm(ExportForm):
model = Organiser
def get_fname(self):
return 'organisers.xls'
class ExportUserForm(ExportForm):
model = User
def get_objects(self, data):
return self.model.objects.all()
def get_fname(self):
return 'users.xls'
class ExportThemeForm(ExportForm):
model = Theme
def get_fname(self):
return 'themes.xls'
class ExportTagForm(ExportForm):
model = Tag
def get_fname(self):
return 'tags.xls'
class ExportPlaceExpositionForm(ExportForm):
model = PlaceExposition
def get_fname(self):
return 'places.xls'
class ExportPlaceConferenceForm(ExportForm):
model = PlaceConference
def get_fname(self):
return 'places.xls'
class ExportCompanyForm(ExportForm):
model = Company
def get_fname(self):
return 'companies.xls'
class ExportEventForm(forms.Form):
@ -90,7 +131,7 @@ 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):
def export(self):
data = self.cleaned_data
# get model
model = get_model(data['event'].split('.')[0], data['event'].split('.')[1])
@ -119,6 +160,7 @@ class ExportEventForm(forms.Form):
for row, object in enumerate(objects):
# column number
col = 0
for field in field_settings:
try:

@ -0,0 +1,237 @@
# -*- coding: utf-8 -*-
from django import forms
from django.conf import settings
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 excel_settings import import_settings
languages = [code for code in settings.LANGUAGES]
class ImportForm(forms.Form):
"""
abstract form for importing models from excel file to database
"""
model = None
excel_file = forms.FileField(label='Выберите файл')
language = forms.ChoiceField(label='Выберите язык', choices=languages)
def save_file(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[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
try:
object = self.model.objects.language(lang).get(id=int(row[0]))
except ValueError:
object = self.model()
object.translate(lang)
except self.model.DoesNotExist:
object = self.model(id= int(row[0]))
object.translate(lang)
else:
# if id blank - its a new event
object = self.model()
object.translate(lang)
for col_number, cell in enumerate(row):
# go through row cells
# field name current cell
field_name = field_names[col_number]
if field_name =='theme':
# need save object before saving manytomany field
object.save()
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 ImportOrganiserForm(ImportForm):
model = Organiser
class ImportThemeForm(ImportForm):
model = Theme
class ImportPlaceExpositionForm(ImportForm):
model = PlaceExposition
class ImportPlaceConferenceForm(ImportForm):
model = PlaceConference
class ImportEventForm(ImportForm):
"""
extended form for importing one type of event
"""
event = forms.ChoiceField(label='Выберите тип события', choices=[('exposition.Exposition', 'Выставка'),
('conference.Conference', 'Конференция'),
('seminar.Seminar', 'Семинар'),
('webinar.Webinar', 'Вебинар')])
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[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
try:
object = self.model.objects.language(lang).get(id=int(row[0]))
except ValueError:
object = self.model()
object.translate(lang)
except self.model.DoesNotExist:
object = self.model(id= int(row[0]))
object.translate(lang)
else:
# if id blank - its a new event
object = model()
object.translate(lang)
for col_number, cell in enumerate(row):
# go through row cells
# field name current cell
field_name = field_names[col_number]
if field_name =='theme':
# need save object before saving manytomany field
object.save()
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)
if cell:
value = func(cell, lang, getattr(object, extra_value))
else:
value = None
else:
value = func(cell)
if value:
setattr(object, field_name, value)
object.save()
class ImportTagForm(ImportForm):
"""
hacked problem with importing theme field in save_file method
"""
model = Tag
def save_file(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[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
try:
object = self.model.objects.language(lang).get(id=int(row[0]))
except ValueError:
object = self.model()
object.translate(lang)
except self.model.DoesNotExist:
object = self.model(id= int(row[0]))
object.translate(lang)
else:
# if id blank - its a new event
object = self.model()
object.translate(lang)
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)
if field_name != 'theme':
setattr(object, field_name, value)
else:
setattr(object, field_name, value[0])
object.save()

@ -1,64 +0,0 @@
# -*- 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 custom_forms import ImportEventForm, ExportEventForm
from excel_settings import field_settings, import_settings
relation_fields = ['city']
@login_required
def import_event(request):
args = {}
form = ImportEventForm()
args.update(csrf(request))
args['form'] = form
if request.POST:
form = ImportEventForm(request.POST, request.FILES)
if form.is_valid():
form.save_events()
args['message'] = 'Success'
return render_to_response('import_event.html', args)
return render_to_response('import_event.html', args)
def xls_to_response(xls, fname):
response = HttpResponse(mimetype="application/ms-excel")
response['Content-Disposition'] = 'attachment; filename=%s' % fname
xls.save(response)
return response
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:
f_name = form.get_fname()
return xls_to_response(workbook, f_name)
#return xls_to_response(workbook, 'My Worksheet.xls')
else:
form = ExportEventForm()
args = {}
args.update(csrf(request))
args['form'] = form
return render_to_response('export_event.html', args)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 448 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 354 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 329 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 331 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 342 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 340 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 336 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 338 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 343 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 321 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 323 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 344 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 338 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 328 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 337 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 350 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 336 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 53 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 152 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 43 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 46 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save