diff --git a/accounts/edit_forms.py b/accounts/edit_forms.py index 14f2860e..cb687a90 100644 --- a/accounts/edit_forms.py +++ b/accounts/edit_forms.py @@ -1,4 +1,5 @@ # -*- coding: utf-8 -*- +# forms for editing user data from django import forms from django.utils.translation import ugettext as _ from models import User, Profile @@ -6,13 +7,16 @@ from country.models import Country from city.models import City from company.models import Company + class AvatarForm(forms.ModelForm): avatar = forms.ImageField(label=_(u'Выберите файл (GIF, JPG, PNG. Размер 100 × 100 пикселей)'), required=False, widget=forms.FileInput(attrs={'class': 'input'})) + class Meta: model = Profile fields = ('avatar',) + class NameForm(forms.ModelForm): first_name = forms.CharField(label=_(u'Введите ваше имя')) last_name = forms.CharField(label=_(u'Введите вашу фамилию')) @@ -22,17 +26,19 @@ class NameForm(forms.ModelForm): fields = ('first_name', 'last_name') def get_full_name(self): - return u'%s %s'%(self.instance.first_name, self.instance.last_name,) + return u'%s %s' % (self.instance.first_name, self.instance.last_name,) class HomeForm(forms.ModelForm): city = forms.CharField(label='Город', required=False, widget=forms.HiddenInput(attrs={'class': 'select2'})) - country = forms.ChoiceField(label=_(u'Страна'), choices=[(c.id, c.name) for c in Country.objects.all()], required=False, - widget=forms.Select(attrs={'class': 'select2'})) + country = forms.ChoiceField(label=_(u'Страна'), choices=[(c.id, c.name) for c in Country.objects.all()], + required=False, widget=forms.Select(attrs={'class': 'select2'})) + def __init__(self, *args, **kwargs): super(HomeForm, self).__init__(*args, **kwargs) if self.instance.city: + # city uses ajax select2 widget self.fields['city'].widget = forms.HiddenInput(attrs={'class': 'select2', 'data-init-text': self.instance.city.name}) class Meta: @@ -48,7 +54,6 @@ class HomeForm(forms.ModelForm): except City.DoesNotExist: return None - def clean_country(self): try: return Country.objects.get(id=self.cleaned_data['country']) @@ -56,19 +61,18 @@ class HomeForm(forms.ModelForm): return None - class WorkForm(forms.ModelForm): position = forms.CharField(label=_(u'Укажите вашу должность'), required=False, widget=forms.TextInput()) company = forms.CharField(label=_(u'Укажите вашу компанию'), required=False, - widget=forms.HiddenInput(attrs={'class': 'select2'})) + widget=forms.HiddenInput(attrs={'class': 'select2'})) def __init__(self, *args, **kwargs): super(WorkForm, self).__init__(*args, **kwargs) if self.instance.company: + # for ajax select2 widget self.fields['company'].widget = forms.HiddenInput(attrs={'class': 'select2', 'data-init-text': self.instance.company.name}) - class Meta: model = User fields = ('position', 'company') @@ -84,7 +88,8 @@ class WorkForm(forms.ModelForm): class AboutCompanyForm(forms.ModelForm): about_company = forms.CharField(label=_(u'Описание компании'), required=False, - widget=forms.Textarea(attrs={'cols':'30'})) + widget=forms.Textarea(attrs={'cols': '30'})) + class Meta: model = Profile fields = ('about_company',) @@ -99,11 +104,11 @@ class PhoneForm(forms.ModelForm): fields = ('phone', 'show_phone') def clean_phone(self): - phone = self.cleaned_data['phone'] - if not phone: + phone = self.cleaned_data['phone'] + if not phone: return - deduct = ('-','(',')','.',' ', '+') + deduct = ('-', '(', ')', '.', ' ', '+') for elem in deduct: phone = phone.replace(elem, '') if phone.isdigit(): @@ -112,7 +117,6 @@ class PhoneForm(forms.ModelForm): raise forms.ValidationError(_(u'Введите правильный телефон')) - class EmailForm(forms.ModelForm): email = forms.EmailField(label=_(u'Ваш e-mail'), required=False) @@ -120,6 +124,7 @@ class EmailForm(forms.ModelForm): model = User fields = ('email',) + class WebPageForm(forms.ModelForm): web_page = forms.URLField(label=_(u'Адрес вашего сайта'), required=False) @@ -127,17 +132,18 @@ class WebPageForm(forms.ModelForm): model = User fields = ('web_page',) + class SocialForm(forms.ModelForm): facebook = forms.CharField(label=_(u'Facebook'), required=False) twitter = forms.CharField(label=_(u'Twitter'), required=False) vk = forms.CharField(label=_(u'В контакте'), required=False) linkedin = forms.CharField(label=_(u'LinkedIn'), required=False) - class Meta: model = Profile fields = ('facebook', 'twitter', 'vk', 'linkedin') + class AboutForm(forms.ModelForm): about = forms.CharField(label=_(u'Немного о себе'), required=False, widget=forms.Textarea(attrs={'cols':'30'})) diff --git a/accounts/forms.py b/accounts/forms.py index 2e9bc922..8ab13b3e 100644 --- a/accounts/forms.py +++ b/accounts/forms.py @@ -6,16 +6,14 @@ from django.contrib.auth.forms import ReadOnlyPasswordHashField from django.forms.util import ErrorList from django.utils.translation import ugettext as _ from django.conf import settings -from models import User, Profile +from models import User +from django.db.models import Q from theme.models import Theme, Tag from country.models import Area -from django.utils import translation from country.models import Country from city.models import City from company.models import Company -from organiser.models import Organiser -# functions -from functions.form_check import translit_with_separator, is_latin +from functions.form_check import is_latin def clean_relation_field(inst, field_name, model): @@ -137,17 +135,6 @@ class UserForm(forms.ModelForm): profile.save() return user - #def clean_url(self): - # url = self.cleaned_data.get('url') - # if url: - # if User.objects.get(url=translit_with_separator(url)): - # raise forms.ValidationError('Такой урл уже занят') - # else: - # return url - - #def clean_organiser(self): - # return clean_relation_field(self, 'organiser', Organiser) - def clean_company(self): return clean_relation_field(self, 'company', Company) @@ -174,21 +161,6 @@ class UserForm(forms.ModelForm): else: raise forms.ValidationError('Введите правильный код страны') - """ - def clean_web_page(self): - cleaned_data = super(UserForm, self).clean() - web_page = cleaned_data.get('web_page') - if not web_page: - return web_page - - import socket - try: - socket.getaddrinfo(web_page, 80) - return web_page - except: - return forms.ValidationError('Введите правильный адрес страници') - """ - class ChangePasswordForm(forms.Form): """ @@ -319,24 +291,6 @@ class SocialRegistrationCompleteForm(RegistrationCompleteForm): return user -class RecoveryForm(forms.Form): - email = forms.EmailField(widget=forms.TextInput(attrs={'placeholder': _(u'Email')})) - - def get_user(self): - email = self.cleaned_data['email'] - return User.objects.get(email=email) - - def clean_email(self): - email = self.cleaned_data['email'] - try: - return User.objects.get(email=email) - except User.DoesNotExist: - raise forms.ValidationError(_(u'Пользователь с таким емейлом не зарегестрирован')) - - -from django.db.models import Q - - class UserFilterForm(forms.Form): model = User search_req = forms.CharField(label=_(u'Введите e-mail, имя или фамилию для запроса'), required=False) @@ -450,21 +404,21 @@ class FeedFilterForm(forms.Form): area = self.cleaned_data['area'] country = self.cleaned_data['co'] city = self.cleaned_data['ci'] - filter = self.filter + filter_obj = self.filter - filter.theme.clear() - filter.theme.add(*Theme.objects.filter(id__in=theme)) + filter_obj.theme.clear() + filter_obj.theme.add(*Theme.objects.filter(id__in=theme)) - filter.tag.clear() - filter.tag.add(*Tag.objects.filter(id__in=tag)) + filter_obj.tag.clear() + filter_obj.tag.add(*Tag.objects.filter(id__in=tag)) - filter.area.clear() - filter.area.add(*Area.objects.filter(id__in=area)) - filter.country.clear() - filter.country.add(*Country.objects.filter(id__in=country)) + filter_obj.area.clear() + filter_obj.area.add(*Area.objects.filter(id__in=area)) + filter_obj.country.clear() + filter_obj.country.add(*Country.objects.filter(id__in=country)) - filter.city.clear() - filter.city.add(*City.objects.filter(id__in=city)) + filter_obj.city.clear() + filter_obj.city.add(*City.objects.filter(id__in=city)) def clean_tg(self): diff --git a/accounts/management/__init__.py b/accounts/management/__init__.py deleted file mode 100644 index 3ed9fd0f..00000000 --- a/accounts/management/__init__.py +++ /dev/null @@ -1 +0,0 @@ -__author__ = 'root' diff --git a/accounts/management/commands/__init__.py b/accounts/management/commands/__init__.py deleted file mode 100644 index 3ed9fd0f..00000000 --- a/accounts/management/commands/__init__.py +++ /dev/null @@ -1 +0,0 @@ -__author__ = 'root' diff --git a/accounts/management/commands/load_accounts.py b/accounts/management/commands/load_accounts.py deleted file mode 100644 index 6d2147fb..00000000 --- a/accounts/management/commands/load_accounts.py +++ /dev/null @@ -1,82 +0,0 @@ -import os -import MySQLdb -from MySQLdb.cursors import DictCursor -from django.core.management.base import BaseCommand -from accounts.models import User - -def create_new_user(data): - email = data['email'] - firstname = data['firstname'] - lastname = data['lastname'] - position = data['position'] - web_page = data['web_page'] - fb = data['fb'] - li = data['li'] - sk = data['sk'] - about = data['about'] - password = data['password'] - url = data['url'] - if not url: - url = str(data['id']) - - user = User(username=email, first_name=firstname, last_name=lastname, email=email, - is_staff=False, is_active=True, is_superuser=False, password=password, position=position, url=url) - - try: - user.save() - except: - return - profile = user.profile - - profile.web_page = web_page - profile.facebook = fb - profile.linkedin = li - profile.skype = sk - profile.about = about - try: - profile.save() - except: - pass - - return - - -class Command(BaseCommand): - def handle(self, *args, **options): - db = MySQLdb.connect(host="localhost", - user="expomap", - passwd="7FbLtAGjse", - db="old_db", - charset='utf8', - cursorclass=DictCursor) - cursor = db.cursor() - sql = """ - SELECT customers_id as id, customers_email_address as email, customers_password as password, customers_firstname as firstname , - customers_lastname as lastname , customers_telephone as phone, customers_job as `position`, customers_web as web_page, - customers_facebook as fb, customers_linkedin as li, customers_skype as sk, customers_about as about, - url - FROM `customers` - where customers_email_address!='' - - """ - - - - - cursor.execute(sql) - result = cursor.fetchall() - - #user.password = result[0]['customers_password'] - - for res in result: - email = res['email'] - print(email) - try: - user = User.objects.get(username=email) - except User.DoesNotExist: - user = None - create_new_user(res) - if user: - password = res['password'] - user.password = password - user.save() diff --git a/accounts/models.py b/accounts/models.py index 2c83a17b..f2dbdc87 100644 --- a/accounts/models.py +++ b/accounts/models.py @@ -1,7 +1,5 @@ # -*- coding: utf-8 -*- -import random, string from django.db import models -from django.core.validators import email_re from django.db.models import Q from django.contrib.auth.models import BaseUserManager, AbstractBaseUser, PermissionsMixin from django.core.mail import send_mail @@ -9,19 +7,9 @@ from django.utils import timezone from django.utils.translation import ugettext as _ from django.db.models.signals import post_save from django.db.models.loading import get_model -#custom functions from functions.form_check import translit_with_separator - -""" -from django.contrib.auth.hashers import check_password -from hashlib import md5 -from django.contrib.auth import get_user_model - -from django.db.models import get_model -""" - class UserManager(BaseUserManager): """ Creates and saves a User with the given email, first_name, last_name and password. @@ -31,10 +19,10 @@ class UserManager(BaseUserManager): if not email: raise ValueError('Вы должни ввести электронную почту') - user= self.model( - email = UserManager.normalize_email(email), - first_name = first_name,last_name = last_name, - username = UserManager.normalize_email(email), + user = self.model( + email=UserManager.normalize_email(email), + first_name=first_name,last_name = last_name, + username=UserManager.normalize_email(email), is_staff=False, is_active=False, is_superuser=False, last_login=now, date_joined=now, **extra_fields ) @@ -43,29 +31,6 @@ class UserManager(BaseUserManager): user.save(using=self._db) return user - def create_social_user(self, username, first_name, last_name, password=None, **extra_fields): - now = timezone.now() - # generate random password - digits = random.sample(('0', '1', '2', '3', '4', '5', '6', '7', '8', '9'), 4) - chars = random.sample(string.lowercase[:], 4) - password = chars + digits - random.shuffle(password) - password = ''.join(password) - - - user= self.model(first_name=first_name, last_name=last_name, username=username, - is_staff=False, is_active=True, is_superuser=False, - last_login=now, date_joined=now, **extra_fields) - - check = True if email_re.match(username) else False - if check: - user.email = UserManager.normalize_email(username) - - user.set_password(password) - user.save(using=self._db) - return user - - def create_superuser(self, username, first_name, last_name, password, **extra_fields): if not username: raise ValueError('Вы должни ввести электронную почту') @@ -73,9 +38,9 @@ class UserManager(BaseUserManager): username = UserManager.normalize_email(username) user = self.create_user( - email = username, - first_name = first_name,last_name = last_name, - password = password, **extra_fields + email=username, + first_name=first_name, last_name=last_name, + password=password, **extra_fields ) user.is_staff = True @@ -85,7 +50,6 @@ class UserManager(BaseUserManager): user.save(using=self._db) return user - def safe_get(self, **kwargs): model = self.model try: @@ -108,24 +72,22 @@ class User(AbstractBaseUser, PermissionsMixin): catalog = '/user/' email = models.EmailField( - verbose_name = u'Email', - max_length = 255, + verbose_name=u'Email', + max_length=255, #unique = True, - db_index = True, + db_index=True, ) username = models.CharField(verbose_name='Email', max_length=255, unique=True, db_index=True) - first_name = models.CharField(verbose_name='First name', max_length=255) - last_name = models.CharField(verbose_name='Last name', max_length=255) - rating = models.IntegerField(default=100)# добавить индекс в базе - url = models.SlugField(blank=True)#, unique=True, null=True) - # - is_active = models.BooleanField(default=0) # СДЕЛАТЬ проверку на емейле - is_staff = models.BooleanField(default=0) - is_admin = models.BooleanField(default=0) - - date_joined = models.DateTimeField(auto_now_add=True) - date_registered = models.DateTimeField(blank=True, null=True)# - date_modified = models.DateTimeField(auto_now=True) + first_name = models.CharField(verbose_name=_(u'First name'), max_length=255) + last_name = models.CharField(verbose_name=_(u'Last name'), max_length=255) + rating = models.IntegerField(verbose_name=_(u'Рейтинг'), default=100)# добавить индекс в базе + url = models.SlugField(verbose_name=_(u'Url'), blank=True) + is_active = models.BooleanField(verbose_name=_(u'Активный'), default=0) + is_staff = models.BooleanField(verbose_name=_(u'Сотрудник?'), default=0) + is_admin = models.BooleanField(verbose_name=_(u'Админ?'), default=0) + date_joined = models.DateTimeField(verbose_name=_(u'Дата создания'), auto_now_add=True) + date_registered = models.DateTimeField(verbose_name=_(u'Дата регистрации'), blank=True, null=True) + date_modified = models.DateTimeField(verbose_name=_(u'Изменен'), auto_now=True) #relations organiser = models.ForeignKey('organiser.Organiser', verbose_name='Организатор', blank=True, null=True, unique=True, @@ -133,7 +95,8 @@ class User(AbstractBaseUser, PermissionsMixin): translator = models.ForeignKey('translator.Translator', verbose_name='Переводчик', blank=True, null=True, unique=True, on_delete=models.PROTECT, related_name='user') - company = models.ForeignKey('company.Company', blank=True, null=True, related_name='users') + company = models.ForeignKey('company.Company', verbose_name=_(u'Компания'), blank=True, null=True, + related_name='users') position = models.CharField(verbose_name='Должность', max_length=255, blank=True) objects = UserManager() @@ -142,10 +105,7 @@ class User(AbstractBaseUser, PermissionsMixin): REQUIRED_FIELDS = ['first_name', 'last_name'] class Meta: - ordering=['-rating'] - - def is_organiser(self): - return bool(self.organiser) + ordering = ['-rating'] def get_full_name(self): """ @@ -154,16 +114,13 @@ class User(AbstractBaseUser, PermissionsMixin): return u'%s %s'%(self.first_name, self.last_name) def set_url(self, st): - """ - - """ self.url = translit_with_separator(u'%s'%st) def __unicode__(self): return self.email def get_short_name(self): - "Returns the short name for the user." + """Returns the short name for the user.""" return self.first_name def email_user(self, subject, message, from_email=None): @@ -172,7 +129,6 @@ class User(AbstractBaseUser, PermissionsMixin): """ send_mail(subject, message, from_email, [self.email]) - def has_perm(self, perm, obj=None): return True @@ -201,81 +157,54 @@ class User(AbstractBaseUser, PermissionsMixin): return n def get_permanent_url(self): - - if self.url: - return '/%s/'%self.url - #return self.catalog+self.url+'/' - return '/%d/'%self.id - #return self.catalog+str(self.id)+'/' - - def get_translator_url(self): if self.url: - return '/translators/%s/'%self.url - return '/translators/%d/'%self.id + return '/%s/' % self.url + return '/%d/' % self.id def get_expos(self): """ - return information about expos and them related data by 1 query + return information about expos and them related data by 1 query(reverse connection) """ return self.exposition_users.language().select_related('country', 'city', 'place').all() def get_confs(self): """ - return information about confs and them related data by 1 query + return information about confs and them related data by 1 query(reverse connection) """ return self.conference_users.language().select_related('country', 'city', 'place').all() - def get_seminars(self): - """ - return information about seminars and them related data by 1 query - - """ - return self.seminar_users.language().select_related('country', 'city').all() - def remove_from_calendar(self, data): expo = data['expo'] conf = data['conf'] - seminar = data['seminar'] - webinar = data['webinar'] calendar = self.calendar if expo: calendar.expositions.remove(*expo) if conf: calendar.conferences.remove(*conf) - if seminar: - calendar.seminars.remove(*seminar) - if webinar: - calendar.webinars.remove(*webinar) - - - class Profile(models.Model): """ stores additional information about users - """ user = models.OneToOneField(User) - country = models.ForeignKey('country.Country', verbose_name='Страна', blank=True, null=True, + country = models.ForeignKey('country.Country', verbose_name=_(u'Страна'), blank=True, null=True, on_delete=models.PROTECT, related_name='users') - city = models.ForeignKey('city.City', verbose_name='Город', blank=True, null=True, + city = models.ForeignKey('city.City', verbose_name=_(u'Город'), blank=True, null=True, on_delete=models.PROTECT) about_company = models.TextField(verbose_name=_(u'Описание компании'), blank=True) - phone = models.BigIntegerField(verbose_name=_(u'Телефон'), blank=True, null=True) show_phone = models.NullBooleanField(verbose_name=_(u'Показывать телефон'), blank=True, null=True, default=1) - web_page = models.URLField(verbose_name='Вебсайт',blank=True) - about = models.TextField(verbose_name='О себе', blank=True) - avatar = models.ImageField(verbose_name='Фото', upload_to='accounts/avatar/', blank=True) - skype = models.CharField(blank=True, max_length=255) + web_page = models.URLField(verbose_name=_(u'Вебсайт'),blank=True) + about = models.TextField(verbose_name=_(u'О себе'), blank=True) + avatar = models.ImageField(verbose_name=_(u'Фото'), upload_to='accounts/avatar/', blank=True) + skype = models.CharField(verbose_name=_(u'Skype'), blank=True, max_length=255) facebook = models.URLField(verbose_name=_(u'Facebook'), blank=True, max_length=255) twitter = models.URLField(verbose_name=_(u'Twitter'), blank=True,max_length=255) linkedin = models.URLField(verbose_name=_(u'LinkedIn'), blank=True, max_length=255) vk = models.URLField(verbose_name=_(u'В контакте'), blank=True, max_length=255) - # meta title = models.CharField(max_length=255, blank=True) descriptions = models.CharField(max_length=255, blank=True) @@ -288,10 +217,10 @@ class Calendar(models.Model): every user has one calendar """ 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) + expositions = models.ManyToManyField('exposition.Exposition', verbose_name=_(u'Выставки'), null=True) + conferences = models.ManyToManyField('conference.Conference', verbose_name=_(u'Конфеернции'), null=True) + seminars = models.ManyToManyField('seminar.Seminar', verbose_name=_(u'Семинары'), null=True) + webinars = models.ManyToManyField('webinar.Webinar', verbose_name=_(u'Вебинары'), null=True) def get_expos(self): # 1 query @@ -345,15 +274,18 @@ class Calendar(models.Model): class EventFilter(models.Model): user = models.OneToOneField(User) - theme = models.ManyToManyField('theme.Theme', null=True) - tag = models.ManyToManyField('theme.Tag', null=True) - area = models.ManyToManyField('country.Area', null=True) - country = models.ManyToManyField('country.Country', null=True) - city = models.ManyToManyField('city.City', null=True) - fr = models.DateField(blank=True, null=True) - to = models.DateField(blank=True, null=True) + theme = models.ManyToManyField('theme.Theme', verbose_name=_(u'Тематики'), null=True) + tag = models.ManyToManyField('theme.Tag', verbose_name=_(u'Теги'), null=True) + area = models.ManyToManyField('country.Area', verbose_name=_(u'Геограифческие зоны'), null=True) + country = models.ManyToManyField('country.Country', verbose_name=_(u'Страны'), null=True) + city = models.ManyToManyField('city.City', verbose_name=_(u'Города'), null=True) + fr = models.DateField(blank=True, verbose_name=_(u'с'), null=True) + to = models.DateField(blank=True, verbose_name=_(u'до'), null=True) def get_queryset(self): + """ + get filtered queryset + """ Exposition = get_model('exposition', 'Exposition') qs = Exposition.enable.upcoming() themes = self.theme.all() @@ -380,9 +312,11 @@ class EventFilter(models.Model): return qs.order_by('data_begin') - - def calculate_rating(user): + """ + calculates user rating depending og user filled information + calls in post save signal of profile model + """ user_rating_fields = {'position': 5, 'company': 5, 'url': 10} profile_rating_fields = {'country': 5, 'city': 5, 'phone': 10, 'facebook': 5, 'twitter': 5, 'linkedin': 5, 'vk': 5, 'web_page': 10, 'avatar': 20, 'about': 15} @@ -396,7 +330,6 @@ def calculate_rating(user): if getattr(user, key): rating += value - for key, value in profile_rating_fields.iteritems(): if getattr(user.profile, key): rating += value @@ -409,6 +342,9 @@ def calculate_rating(user): def create_user_inf(sender, instance, created, **kwargs): + """ + create default models that is required for users + """ if created: Calendar.objects.create(user=instance) Profile.objects.create(user=instance) @@ -416,10 +352,10 @@ def create_user_inf(sender, instance, created, **kwargs): calculate_rating(instance) + def post_profile(sender, instance, created, **kwargs): user = instance.user calculate_rating(user) post_save.connect(create_user_inf, sender=User) -post_save.connect(post_profile, sender=Profile) - +post_save.connect(post_profile, sender=Profile) \ No newline at end of file diff --git a/accounts/search_indexes.py b/accounts/search_indexes.py deleted file mode 100644 index 0b9b391d..00000000 --- a/accounts/search_indexes.py +++ /dev/null @@ -1,21 +0,0 @@ -from haystack import indexes -from models import User - -""" -class UserIndex(indexes.SearchIndex, indexes.Indexable): - text = indexes.CharField(document=True, use_template=True) -# first_name = indexes.CharField(model_attr='first_name') -# last_name = indexes.CharField(model_attr='last_name') - email = indexes.NgramField(model_attr='email') - #email = indexes.CharField(model_attr='email') - - - - def get_model(self): - return User - - - def index_queryset(self, using=None): - - return self.get_model().objects.filter(is_active=True) -""" \ No newline at end of file diff --git a/accounts/tests.py b/accounts/tests.py deleted file mode 100644 index 501deb77..00000000 --- a/accounts/tests.py +++ /dev/null @@ -1,16 +0,0 @@ -""" -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) diff --git a/accounts/urls.py b/accounts/urls.py index f3250df3..4c0f3c0d 100644 --- a/accounts/urls.py +++ b/accounts/urls.py @@ -1,18 +1,12 @@ # -*- coding: utf-8 -*- from django.conf.urls import patterns, url from django.contrib.auth.decorators import login_required -from views import SettingsView, ProfileView, CalendarView, UserView, UserExpositionsView, UserConferenceView, UserSeminarView +from views import SettingsView, CalendarView from views import NameView, HomeView, AvatarView, WorkView, AboutCompanyView, PhoneView, WebPageView,\ SocialView, AboutView, ProfileCompanyView, Feed -# -from django.http import HttpResponse -def test(request): - return HttpResponse('123') - urlpatterns = patterns('', - url(r'^profile/$', login_required(ProfileView.as_view())), url(r'^profile/company/$', login_required(ProfileCompanyView.as_view())), url(r'^profile/settings/$', login_required(SettingsView.as_view()), name='accounts_settings'), url(r'^profile/calendar/remove/$', 'accounts.views.remove_from_calendar'), @@ -20,20 +14,8 @@ urlpatterns = patterns('', url(r'^profile/calendar/$', login_required(CalendarView.as_view())), url(r'^profile/feed/page/(?P\d+)/$', Feed.as_view()), url(r'^profile/feed/$', login_required(Feed.as_view())), - url(r'^user/(?P.*)/expositions/(?P\d+)/$', UserExpositionsView.as_view()), - url(r'^user/(?P.*)/expositions/$', UserExpositionsView.as_view()), - url(r'^user/(?P.*)/seminars/(?P\d+)/$', UserSeminarView.as_view()), - url(r'^user/(?P.*)/seminars/$', UserSeminarView.as_view()), - url(r'^user/(?P.*)/conferences/(?P\d+)/$', UserConferenceView.as_view()), - url(r'^user/(?P.*)/conferences/$', UserConferenceView.as_view()), - url(r'^user/(?P.*)/events/(?P\d+)/$', UserView.as_view()), - url(r'^user/(?P.*)/events/$', UserView.as_view()), - url(r'^user/(?P.*)/$', UserView.as_view()), url(r'^inactive-user/$', 'registration.backends.default.views.inactive_user_message'), - #url(r'^profile/messages/(?P.*)/$', login_required(MessagesView.as_view())), - #url(r'^profile/messages/$', login_required(MessagesView.as_view())), - # ajax url(r'^profile/update/announce-settings/$', 'accounts.views.save_announce_settings', name='account_save_announce_settings'), url(r'^profile/update/name/$', login_required(NameView.as_view())), diff --git a/accounts/user_catalog_urls.py b/accounts/user_catalog_urls.py index 60fdaf9d..1f8c302f 100644 --- a/accounts/user_catalog_urls.py +++ b/accounts/user_catalog_urls.py @@ -1,16 +1,11 @@ from django.conf.urls import patterns, url -from django.contrib.auth.decorators import login_required -from views import SettingsView, ProfileView, CalendarView, UserView, UserExpositionsView, UserConferenceView, UserSeminarView +from views import UserView, UserExpositionsView, UserConferenceView urlpatterns = patterns('', url(r'^(?P.*)/expositions/(?P\d+)/$', UserExpositionsView.as_view(), {'meta_id': 72}), url(r'^(?P.*)/expositions/$', UserExpositionsView.as_view(), {'meta_id': 72}), - url(r'^(?P.*)/seminars/(?P\d+)/$', UserSeminarView.as_view()), - url(r'^(?P.*)/seminars/$', UserSeminarView.as_view()), url(r'^(?P.*)/conferences/(?P\d+)/$', UserConferenceView.as_view(), {'meta_id': 73}), url(r'^(?P.*)/conferences/$', UserConferenceView.as_view(), {'meta_id': 73}), - url(r'^(?P.*)/events/(?P\d+)/$', UserView.as_view()), - url(r'^(?P.*)/events/$', UserView.as_view()), url(r'^(?P.*)/$', UserView.as_view(), {'meta_id': 71}), ) diff --git a/accounts/views.py b/accounts/views.py index 95bf56bc..8b3b149b 100644 --- a/accounts/views.py +++ b/accounts/views.py @@ -1,24 +1,31 @@ # -*- coding: utf-8 -*- import dateutil.relativedelta as rdelta -import json, datetime +import json +import datetime import calendar as python_calendar from django.shortcuts import get_object_or_404 -from django.core.urlresolvers import reverse -from django.http import HttpResponseRedirect, HttpResponse, Http404, HttpResponseForbidden +from django.http import HttpResponseRedirect, HttpResponse, Http404 from django.contrib.auth.decorators import login_required from django.utils.translation import ugettext as _, get_language from django_messages.forms import SendForm from django.views.generic import TemplateView, FormView +from django.conf import settings from functions.custom_views import ListView +from functions.views_help import dates_range, get_user from sorl.thumbnail import get_thumbnail -from .forms import ChangePasswordForm, FeedFilterForm +from exposition.models import Exposition +from .forms import ChangePasswordForm, EmailAnnouncementForm, FeedFilterForm from company.forms import CreateCompanyForm from .models import User from .edit_forms import AvatarForm, NameForm, HomeForm, WorkForm, AboutCompanyForm, PhoneForm, EmailForm,\ WebPageForm, SocialForm, AboutForm +from company.edit_forms import NameForm as CompNameForm, HomeForm as CompHomeForm, PhoneForm as CompPhoneForm,\ + EmailForm as CompEmailForm, WebPageForm as CompWebPageForm, SocialForm as CompSocialForm,\ + TagForm as CompTagForm, DescriptionForm as CompDescr, StaffForm as CompStaff, \ + FoundationForm as CompFound, SpecializationForm as CompSpec, AddressForm as CompAddress +from meta.views import MetadataMixin from emencia.django.newsletter.forms import SubscribeSettingsForm from emencia.django.newsletter.models import Contact -from meta.views import MetadataMixin class SettingsView(TemplateView): @@ -56,8 +63,6 @@ class SettingsView(TemplateView): form = SubscribeSettingsForm(instance=setting, initial=initial) return form - - def get_context_data(self, **kwargs): context = super(SettingsView, self).get_context_data(**kwargs) context['change_password_form'] = ChangePasswordForm() @@ -66,13 +71,10 @@ class SettingsView(TemplateView): return context - def save_announce_settings(request): - if request.POST: user = request.user email = request.POST.get('email') or user.username - # check if setting subscription already exist try: contact, created = user.contact_set.get(email=email), False @@ -94,16 +96,6 @@ def save_announce_settings(request): return HttpResponseRedirect(reverse('accounts_settings')) - - - -def dates_range(date1, date2): - delta = date2 - date1 - dates = [] - for i in range(delta.days + 1): - dates.append(date1 + datetime.timedelta(days=i)) - return dates - class CalendarView(TemplateView): """ display template with user calendar(one month) @@ -119,7 +111,6 @@ class CalendarView(TemplateView): - events - events in current months - days - days in current month - current_day - """ context = super(CalendarView, self).get_context_data(**kwargs) now = datetime.datetime.now().replace(microsecond=0, second=0, minute=0, hour=0) @@ -137,32 +128,27 @@ class CalendarView(TemplateView): number_of_days = python_calendar.monthrange(now.year, now.month)[1] # number of days in current month days = [datetime.datetime(now.year, now.month, i+1) for i in range(number_of_days)] - #context['days'] = days calendar = self.request.user.calendar # events in current month context['events'] = calendar.events_by_month(now) else: - number_of_days = python_calendar.monthrange(year, month)[1] + # days in current month days = [datetime.datetime(year, month, i+1) for i in range(number_of_days)] - # number of days in current month - #context['days'] = days + calendar = self.request.user.calendar now = now.replace(year=year, month=month, day=1) # events in current month context['events'] = calendar.events_by_month(now) - - # add days from previous mondey to next sunday - + # add days from previous monday to next sunday first_day = days[0] if first_day.weekday() != 0: past_monday = first_day + rdelta.relativedelta(days=-1, weekday=rdelta.MO(-1)) a = [past_monday + datetime.timedelta(days=x) for x in range((first_day - past_monday).days)] days = a + days - last_day = days[-1] if last_day != 6: @@ -171,9 +157,6 @@ class CalendarView(TemplateView): days += b events = context['events'] context['days'] = days - #days = context['days'] - event_in_day = False - counter = 0 dates_with_events = [] for event in events: dates_with_events += dates_range(event.data_begin, event.data_end) @@ -203,39 +186,6 @@ class CalendarView(TemplateView): return context - -class ProfileView(TemplateView): - """ - display template with user information forms - - in template forms handles dynamically by ajax - """ - template_name = 'client/accounts/new_profile.html' - - def get_context_data(self, **kwargs): - context = super(ProfileView, self).get_context_data(**kwargs) - user = self.request.user - profile = user.profile - - profile_forms = { - 'avatar_form': AvatarForm(instance=profile), 'name_form': NameForm(instance=user), - 'home_form': HomeForm(instance=profile), 'work_form': WorkForm(instance=user), - 'about_company_form': AboutCompanyForm(instance=profile), 'phone_form': PhoneForm(instance=profile), - 'email_form': EmailForm(instance=user), 'web_page_form': WebPageForm(instance=profile), - 'social_form': SocialForm(instance=profile), 'about_form': AboutForm(instance=profile) - } - if not user.company: - company_form = {'company_form': CreateCompanyForm()} - context.update(company_form) - - context.update(profile_forms) - return context - -from company.edit_forms import NameForm as CompNameForm, HomeForm as CompHomeForm, PhoneForm as CompPhoneForm,\ - EmailForm as CompEmailForm, WebPageForm as CompWebPageForm, SocialForm as CompSocialForm,\ - TagForm as CompTagForm, DescriptionForm as CompDescr, StaffForm as CompStaff, \ - FoundationForm as CompFound, SpecializationForm as CompSpec, AddressForm as CompAddress - class ProfileCompanyView(TemplateView): """ display template with user company information forms @@ -270,8 +220,6 @@ class ProfileCompanyView(TemplateView): return context - - class UserView(MetadataMixin, TemplateView): """ display user information for another users @@ -306,8 +254,6 @@ class UserView(MetadataMixin, TemplateView): context.update(profile_forms) - - context['message_form'] = SendForm() context['member'] = user return context @@ -335,6 +281,7 @@ class BaseProfileView(ProfileInvalidView): response = {'success': True, 'rating': profile.user.rating} return HttpResponse(json.dumps(response), content_type='application/json') + class WorkView(ProfileInvalidView): """ instance user @@ -345,13 +292,11 @@ class WorkView(ProfileInvalidView): user = self.request.user form = self.form_class(self.request.POST, instance=user) user = form.save() - #company = user.company - - #response = {'success': True, 'url':company.get_permanent_url()} response = {'success': True, 'rating': user.rating} return HttpResponse(json.dumps(response), content_type='application/json') + class AvatarView(BaseProfileView): """ instance profile. save user avatar. @@ -413,6 +358,7 @@ class AboutView(BaseProfileView): """ form_class = AboutForm + class NameView(ProfileInvalidView): """ instance user @@ -427,25 +373,14 @@ class NameView(ProfileInvalidView): return HttpResponse(json.dumps(response), content_type='application/json') -from exposition.models import Exposition - - -def get_user(url): - try: - url = int(url) - user = get_object_or_404(User, id=url) - except ValueError: - user = get_object_or_404(User, url=url) - return user class UserEventView(ListView): model = Exposition - template_name = 'accounts/user_events.html' + template_name = 'client/accounts/user_events.html' paginate_by = 10 obj = None event_type = None - def get_queryset(self): url = self.kwargs.get('url') user = get_user(url) @@ -458,6 +393,7 @@ class UserEventView(ListView): context['event_type'] = self.event_type return context + class UserExpositionsView(MetadataMixin, UserEventView): """ return template with list of expos that user joined @@ -485,17 +421,6 @@ class UserConferenceView(MetadataMixin, UserEventView): self.kwargs['user_full_name'] = user.get_full_name() return user.get_confs() -class UserSeminarView(UserEventView): - """ - return template with list of seminars that user joined - """ - event_type = _(u'Семинары') - - def get_queryset(self): - url = self.kwargs.get('url') - user = get_user(url) - self.obj = user - return user.get_seminars() @login_required def change_password(request): @@ -525,10 +450,10 @@ def change_password(request): else: return HttpResponse(json.dumps(success), content_type='application/json') -from django.views.generic.edit import FormMixin + class Feed(ListView): template_name = 'client/accounts/feed.html' - paginate_by = 10 + paginate_by = settings.CLIENT_PAGINATION model = Exposition filter_form = FeedFilterForm success_url = '/profile/feed/' @@ -540,11 +465,9 @@ class Feed(ListView): form.filter_save() return HttpResponseRedirect(self.success_url) - def get_queryset(self): - filter = self.request.user.eventfilter - qs = filter.get_queryset() - + filter_obj = self.request.user.eventfilter + qs = filter_obj.get_queryset() return qs def get_context_data(self, **kwargs): diff --git a/article/admin.py b/article/admin.py index a2f12539..0ee17583 100644 --- a/article/admin.py +++ b/article/admin.py @@ -171,7 +171,10 @@ class BlogView(FormView): article = self.obj data = {} data['slug'] = article.slug - data['theme'] = [item.id for item in article.blog_theme.all()] + if self.obj.type == Article.blog: + data['theme'] = [item.id for item in article.blog_theme.all()] + else: + data['theme'] = [item.id for item in article.theme.all()] if article.exposition: data['exposition'] = article.exposition.id if article.conference: @@ -200,13 +203,10 @@ class BlogView(FormView): else: return form_class() - - def get_context_data(self, **kwargs): context = super(BlogView, self).get_context_data(**kwargs) self.set_obj() - context['article'] = self.obj if context['article']: context['file_form'] = FileForm(initial={'model': 'article.Article'}) @@ -229,6 +229,7 @@ class NewsList(ListView): context['news_flag'] = True return context + class NewsView(BlogView): form_class = NewsForm template_name = 'admin/article/blog_form.html' diff --git a/article/forms.py b/article/forms.py index c5d1508d..e476d26b 100644 --- a/article/forms.py +++ b/article/forms.py @@ -1,15 +1,12 @@ # -*- coding: utf-8 -*- from django import forms 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 ugettext as _ -#functions +from ckeditor.widgets import CKEditorWidget from functions.translate import fill_with_signal from functions.files import check_tmp_files from functions.form_check import translit_with_separator -#models from models import Article from accounts.models import User from theme.models import Theme, Tag, ThemeBlog @@ -57,7 +54,9 @@ class BlogForm(forms.Form): article.author = author article.type = self.type - article.slug = data.get('slug') + if not getattr(article, 'slug', None): + article.slug = data['slug'] + if data['logo']: article.logo = data['logo'] article.publish_date = data['publish_date'] @@ -95,21 +94,22 @@ class BlogForm(forms.Form): else: return [] + class NewsForm(BlogForm): type = Article.news exposition = forms.CharField(label=u'Выставка', widget=forms.HiddenInput(), required=False) conference = forms.CharField(label=u'Конференция', widget=forms.HiddenInput(), required=False) theme = forms.ModelMultipleChoiceField(label='Тематики', queryset=Theme.objects.all(), required=False, widget=forms.SelectMultiple(attrs={'style':'width: 550px'})) - #exposition = forms.ModelChoiceField(label = u'Выставка', required=False, queryset=Exposition.objects.all()) - #conference = forms.ModelChoiceField(label = u'Конференция', required=False, queryset=Conference.objects.all()) def save(self, author, article=None): article = super(NewsForm, self).save(author, article) exposition = self.cleaned_data.get('exposition') conference = self.cleaned_data.get('conference') + theme = self.cleaned_data.get('theme') article.exposition = exposition article.conference = conference + article.theme = theme article.save() return article @@ -267,7 +267,7 @@ class BlogForm(forms.ModelForm): class ArticleFilterForm(forms.Form): theme = forms.MultipleChoiceField(label=_(u'Тематика:'), required=False, - choices=[(item.id, item.name) for item in ThemeBlog.objects.language().distinct()]) + choices=[(item.id, item.name) for item in Theme.objects.language().distinct()]) tag = forms.CharField(label=_(u'Теги:'), widget=forms.HiddenInput(), required=False) ''' @@ -291,7 +291,7 @@ class BlogFilterForm(forms.Form): create dynamical translated fields fields """ super(BlogFilterForm, self).__init__(*args, **kwargs) - ids = [item['theme'] for item in list(Article.objects.blogs().values('theme').distinct())] + ids = set([item['blog_theme'] for item in list(Article.objects.blogs().filter(blog_theme__isnull=False).values('blog_theme'))]) self.fields['theme'] = forms.MultipleChoiceField(label=_(u'Тематика:'), required=False, choices=[(item.id, item.name) for item in ThemeBlog.objects.language().filter(id__in=ids)]) @@ -304,6 +304,6 @@ class NewsFilterForm(forms.Form): create dynamical translated fields fields """ super(NewsFilterForm, self).__init__(*args, **kwargs) - ids = [item['theme'] for item in list(Article.objects.news().values('theme').distinct())] + ids = set([item['theme'] for item in list(Article.objects.news().values('theme'))]) self.fields['theme'] = forms.MultipleChoiceField(label=_(u'Тематика:'), required=False, - choices=[(item.id, item.name) for item in Theme.objects.language().exclude(article__id=None).filter(id__in=ids)]) \ No newline at end of file + choices=[(item.id, item.name) for item in Theme.objects.language().filter(id__in=ids)]) diff --git a/article/management/__init__.py b/article/management/__init__.py deleted file mode 100644 index 3ed9fd0f..00000000 --- a/article/management/__init__.py +++ /dev/null @@ -1 +0,0 @@ -__author__ = 'root' diff --git a/article/management/commands/__init__.py b/article/management/commands/__init__.py deleted file mode 100644 index 3ed9fd0f..00000000 --- a/article/management/commands/__init__.py +++ /dev/null @@ -1 +0,0 @@ -__author__ = 'root' diff --git a/article/management/commands/article_load.py b/article/management/commands/article_load.py deleted file mode 100644 index 70130815..00000000 --- a/article/management/commands/article_load.py +++ /dev/null @@ -1,62 +0,0 @@ -# -*- coding: utf-8 -*- -import xlrd -from django.core.management.base import BaseCommand -from django.conf import settings -from article.models import Article -from import_xls.excel_settings import article_sett -from django.db import IntegrityError - - -NEWS_FILE = settings.MEDIA_ROOT+'/import/news.xls' - - -class Command(BaseCommand): - def handle(self, *args, **options): - - f = open(NEWS_FILE, 'r') - 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)] - labels = [label for label in row_list[0]] - existing = 0 - for row_number, row in enumerate(row_list[2:]): - - published = row[4] - if row[0] != '': - # in first column ids - try: - object = Article.objects.language('ru').get(id=int(row[0])) - object.type = Article.news - object.save() - print(object.type) - continue - except ValueError: - - object = Article(type=Article.news) - object.translate('ru') - except Article.DoesNotExist: - object = Article(id= int(row[0])) - object.translate('ru') - existing += 1 - else: - # if id blank - its a new place - object = Article(type=Article.news) - object.translate('ru') - - for col_number, cell in enumerate(row): - - label = labels[col_number] - setting = article_sett.get(label) - if setting is None: - continue - - field_name = setting['field'] - func = setting.get('func') - value = func(cell) - setattr(object, field_name, value) - object.publish_date = published - try: - object.save() - except Exception, e: - print(e) - diff --git a/article/management/commands/articles_from_blog.py b/article/management/commands/articles_from_blog.py deleted file mode 100644 index 7380727d..00000000 --- a/article/management/commands/articles_from_blog.py +++ /dev/null @@ -1,77 +0,0 @@ -# -*- coding: utf-8 -*- -import MySQLdb -from MySQLdb.cursors import DictCursor -from django.core.management.base import BaseCommand, CommandError -from functions.translate import fill_with_signal -from article.models import Article -from accounts.models import User -from theme.models import Theme,Tag - - -class Command(BaseCommand): - def handle(self, *args, **options): - db = MySQLdb.connect(host="localhost", - user="kotzilla", - passwd="qazedc", - db="expomap_old_blog", - charset='utf8', - cursorclass=DictCursor) - - cursor = db.cursor() - - sql = """SELECT post.post_date as publish_date, - post.post_content as description, - post.post_modified as modified, - post.post_title as main_title, - post.post_name as slug, - tag.name as tag_name - FROM wp_posts post - INNER JOIN wp_term_relationships rel ON rel.object_id = post.ID - INNER JOIN wp_terms tag ON tag.term_id=rel.term_taxonomy_id - WHERE post_status = "publish";""" - - cursor.execute(sql) - result = cursor.fetchall() - user = User.objects.get(id=1) - - tags = {x.name: x.id for x in Tag.objects.language('ru')} - - clear_result = {} - - errors = [] - for a in result: - if a.get('tag_name') in tags.keys(): - tag_id = tags[a['tag_name']] - a['tag_id'] = [tag_id] - print a - else: - tag_id = None - - if not clear_result.get(a['main_title']): - clear_result[a['main_title']] = a - else: - if clear_result[a['main_title']].get('paid_id') and tag_id: - clear_result[a['main_title']]['tag_id'].append(tag_id) - - - for a in clear_result.values(): - article = Article(type=1, - created = a['publish_date'], - publish_date= a['publish_date'], - modified = a['modified'], - ) - article.author = user - article.translate('ru') - article.main_title = a['main_title'] - article.description = a['description'] - article.slug = a['slug'] - if a.get('tag_id'): - article.tag = [Tag.objects.language('ru').get(id=id) for id in a['tag_id']] - try: - article.save() - except Exception as e: - errors.append(e) - - print errors - - diff --git a/article/management/commands/articles_from_old.py b/article/management/commands/articles_from_old.py deleted file mode 100644 index f2034aa2..00000000 --- a/article/management/commands/articles_from_old.py +++ /dev/null @@ -1,63 +0,0 @@ -# -*- coding: utf-8 -*- -import MySQLdb -from MySQLdb.cursors import DictCursor -from django.core.management.base import BaseCommand, CommandError -from functions.translate import fill_with_signal -from article.models import Article -from accounts.models import User - - -class Command(BaseCommand): - def handle(self, *args, **options): - db = MySQLdb.connect(host="localhost", - user="kotzilla", - passwd="qazedc", - db="old_expomap", - charset='utf8', - cursorclass=DictCursor) - cursor = db.cursor() - - sql = """SELECT articles_description.articles_id as id , - articles_description.articles_name as main_title, - articles_description.articles_description as description, - articles.authors_id as author, - articles_description.articles_intro as preview, - articles.articles_date_added as created, - articles.articles_last_modified as modified, - articles.articles_date_available as publish_date, - articles_description.articles_head_title_tag as title, - articles_description.articles_head_desc_tag as descriptions, - articles_description.articles_head_keywords_tag as keywords - - FROM `articles_description` - JOIN articles - ON articles_description.articles_id=articles.articles_id""" - - cursor.execute(sql) - - result = cursor.fetchall() - user = User.objects.get(id=1) - Article.objects.blogs().delete() - for a in result: - article = Article(type=Article.blog, - id=a['id'], - created=a['created'], - modified=a['modified'], - publish_date=a['publish_date']) - - article.author = user - - article.translate('ru') - article.main_title = a['main_title'] - article.preview = a['preview'] - article.description = a['description'] - article.title = a['title'] - article.keywords = a['keywords'] - if len(a['descriptions'])<255: - article.descriptions = a['descriptions'] - article.save() - print(article) - - #print(a['main_title']) - - diff --git a/article/management/commands/news_from_old.py b/article/management/commands/news_from_old.py deleted file mode 100644 index aac5f958..00000000 --- a/article/management/commands/news_from_old.py +++ /dev/null @@ -1,77 +0,0 @@ -# -*- coding: utf-8 -*- -import datetime -import MySQLdb -from MySQLdb.cursors import DictCursor -from django.core.management.base import BaseCommand, CommandError -from functions.translate import fill_with_signal -from article.models import Article -from accounts.models import User -from django.db import IntegrityError - -class Command(BaseCommand): - def handle(self, *args, **options): - db = MySQLdb.connect(host="localhost", - user="expomap", - passwd="7FbLtAGjse", - db="old_db", - charset='utf8', - cursorclass=DictCursor) - cursor = db.cursor() - sql = """SELECT news_id as id , - headline as main_title, - content as description, - cid as author, - date_added as created - - FROM `payed_news` - WHERE status = 1 - order by created DESC""" - - cursor.execute(sql) - - result = cursor.fetchall() - user = User.objects.get(id=1) - now = datetime.datetime.now() - #Article.objects.news().delete() - - for a in result: - title = a['main_title'] - id = a['id'] - published = a['created'] - #try: - # news = Article.objects.get(id=id) - #except Article.DoesNotExist: - # continue - - #news.publish_date = published - #news.save() - - if len(a['main_title'])>255 or not a['main_title']: - continue - - - article = Article(type=Article.news, - old_id=a['id'], - publish_date=a['created'], - created=now) - if a['author']: - try: - author = User.objects.get(id=a['author']) - except User.DoesNotExist: - author = user - else: - author = user - - article.author = author - - article.translate('ru') - article.main_title = a['main_title'] - article.description = a['description'] - try: - article.save() - print(article) - except : - print ('error. id:%d'%a['id']) - - #print(a['main_title']) - diff --git a/article/management/commands/news_generate_file.py b/article/management/commands/news_generate_file.py deleted file mode 100644 index 57af5a16..00000000 --- a/article/management/commands/news_generate_file.py +++ /dev/null @@ -1,45 +0,0 @@ -# -*- coding: utf-8 -*- -import MySQLdb -from MySQLdb.cursors import DictCursor -from django.core.management.base import BaseCommand, CommandError -from functions.translate import fill_with_signal -from article.models import Article -from accounts.models import User -from django.db import IntegrityError -import xlwt -from django.utils import translation -from django.conf import settings - -class Command(BaseCommand): - def handle(self, *args, **options): - translation.activate('en') - - workbook = xlwt.Workbook(encoding = 'utf8') - worksheet = workbook.add_sheet('My Worksheet') - - font = xlwt.Font() - font.name = 'Times New Roman' - font.bold = True - - style = xlwt.XFStyle() - # Create the Style - style.font = font - - qs = Article.objects.news() - worksheet.write(0, 0, 'id') - worksheet.write(0, 1, 'url') - worksheet.write(0, 2, 'title') - - row = 1 - for a in qs: - print a.id - url = a.slug - id = a.id - name = a.main_title - - worksheet.write(row, 0, id) - worksheet.write(row, 1, url) - worksheet.write(row, 2, name) - - row += 1 - workbook.save(settings.MEDIA_ROOT+'/import/exported_news.xls') \ No newline at end of file diff --git a/article/management/commands/update_news.py b/article/management/commands/update_news.py deleted file mode 100644 index 50329f04..00000000 --- a/article/management/commands/update_news.py +++ /dev/null @@ -1,69 +0,0 @@ -# -*- coding: utf-8 -*- -import MySQLdb -import datetime -from django.utils.translation import activate -from MySQLdb.cursors import DictCursor -from django.core.management.base import BaseCommand, CommandError -from django.conf import settings -import xlrd -from import_xls.utils import to_theme, to_tag -from functions.translate import fill_with_signal -from article.models import Article -from accounts.models import User -from django.db import IntegrityError -from exposition.models import Exposition - -NEWS_FILE = settings.MEDIA_ROOT+'/import/exported_news.xls' -BLOGS_FILE = settings.MEDIA_ROOT+'/import/blogs.xls' - - - -class Command(BaseCommand): - def handle(self, *args, **options): - activate('ru') - f = open(BLOGS_FILE, 'r') - 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)] - - - - - print(len(row_list)) - - - existing = 0 - - - for row_number, row in enumerate(row_list[2:]): - - id = int(row[0]) - if id == 49: - continue - - main_title = row[1] - theme = row[2] - tag = row[3] - description = row[4] - article = Article.objects.language('ru').get(id=id) - #article.main_title = main_title - #article.description = description - #article.save() - - - to_theme(article, theme) - to_tag(article, tag) - print(id) - """ - try: - expo = Exposition.objects.filter(translations__name=event)[0] - except IndexError: - expo = None - - if expo: - article.exposition = expo - article.save() - print(id) - """ - - diff --git a/article/managers.py b/article/managers.py new file mode 100644 index 00000000..17026786 --- /dev/null +++ b/article/managers.py @@ -0,0 +1,49 @@ +from django.utils import translation +from django.core.cache import cache +from hvad.models import TranslatableModel, TranslatedFields, TranslationManager + + +class ArticleManager(TranslationManager): + cache_time = 60 + def safe_get(self, **kwargs): + model = self.model + try: + return model.objects.get(**kwargs) + except: + return None + + def news(self): + """ + return queryset of news + """ + model = self.model + return self.language().filter(type=model.news) + + def blogs(self): + """ + return queryset of blogs + """ + model = self.model + return self.language().filter(type=model.blog) + + def main_page_news(self): + lang = translation.get_language() + key = 'main_page_news_%s'%lang + cached_news = cache.get(key) + if cached_news: + return cached_news + else: + news = list(self.news().filter(publish_date__isnull=False).order_by('-main_page', '-publish_date', '-modified')[:3]) + cache.set(key, news, self.cache_time) + return news + + def main_page_blogs(self): + lang = translation.get_language() + key = 'main_page_blogs_%s'%lang + cached_blogs = cache.get(key) + if cached_blogs: + return cached_blogs + else: + blogs = list(self.blogs().filter(publish_date__isnull=False).order_by('-main_page', '-publish_date')[:3]) + cache.set(key, blogs, self.cache_time) + return blogs diff --git a/article/models.py b/article/models.py index f2cf06dc..352d2f08 100644 --- a/article/models.py +++ b/article/models.py @@ -1,63 +1,16 @@ # -*- coding: utf-8 -*- -import copy from django.db import models from django.contrib.contenttypes import generic from django.utils.translation import ugettext_lazy as _ -from django.utils import translation from django.utils.timezone import now +from django.db.models.signals import post_save +from functions.signal_handlers import post_save_handler from hvad.models import TranslatableModel, TranslatedFields, TranslationManager -from django.utils.html import strip_tags from sorl.thumbnail import ImageField from functions.url_utils import slugify, unique_slug from functions.model_utils import base_concrete_model from functions.form_check import translit_with_separator -from django.core.cache import cache - - -class ArticleManager(TranslationManager): - cache_time = 60 - def safe_get(self, **kwargs): - model = self.model - try: - return model.objects.get(**kwargs) - except: - return None - - def news(self): - """ - return queryset of news - """ - model = self.model - return self.language().filter(type=model.news) - - def blogs(self): - """ - return queryset of blogs - """ - model = self.model - return self.language().filter(type=model.blog) - - def main_page_news(self): - lang = translation.get_language() - key = 'main_page_news_%s'%lang - cached_news = cache.get(key) - if cached_news: - return cached_news - else: - news = list(self.news().filter(publish_date__isnull=False).order_by('-main_page', '-publish_date', '-modified')[:3]) - cache.set(key, news, self.cache_time) - return news - - def main_page_blogs(self): - lang = translation.get_language() - key = 'main_page_blogs_%s'%lang - cached_blogs = cache.get(key) - if cached_blogs: - return cached_blogs - else: - blogs = list(self.blogs().filter(publish_date__isnull=False).order_by('-main_page', '-publish_date')[:3]) - cache.set(key, blogs, self.cache_time) - return blogs +from article.managers import ArticleManager class Article(TranslatableModel): @@ -67,36 +20,36 @@ class Article(TranslatableModel): Uses hvad.TranslatableModel which is child of django.db.models class """ - MAX_ON_MAIN_PAGE = 3 # types of article blog = 1 news = 2 - #set manager of this model objects = ArticleManager() - slug = models.SlugField(unique=True, max_length=255) - old_id = models.IntegerField(blank=True, null=True) - logo = ImageField(upload_to='articles_preview', blank=True) - theme = models.ManyToManyField('theme.Theme') - blog_theme = models.ManyToManyField('theme.ThemeBlog') - tag = models.ManyToManyField('theme.Tag', blank=True, null=True) - author = models.ForeignKey('accounts.User', verbose_name='Автор', + slug = models.SlugField(verbose_name=_(u'Url'), unique=True, max_length=255) + # fields provides importing and reindexing new articles from previous site + old_id = models.IntegerField(verbose_name=_(u'Id из старой базы'), blank=True, null=True) + logo = ImageField(verbose_name=_(u'Логотип'), upload_to='articles_preview', blank=True) + theme = models.ManyToManyField('theme.Theme', verbose_name=_(u'Тематики')) + blog_theme = models.ManyToManyField('theme.ThemeBlog', verbose_name=_(u'Тематики для блогов'), ) + tag = models.ManyToManyField('theme.Tag', blank=True, null=True, verbose_name=_(u'Теги'), ) + author = models.ForeignKey('accounts.User', verbose_name=_(u'Автор'), on_delete=models.PROTECT, related_name='articles') - exposition = models.ForeignKey('exposition.Exposition', blank=True, null=True) - conference = models.ForeignKey('conference.Conference', blank=True, null=True) - type = models.PositiveSmallIntegerField(default=1) - allow_comments = models.BooleanField(default=True) - + exposition = models.ForeignKey('exposition.Exposition', blank=True, null=True, verbose_name=_(u'Выставка')) + conference = models.ForeignKey('conference.Conference', blank=True, null=True, verbose_name=_(u'Конференция')) + # type can be blog or news + type = models.PositiveSmallIntegerField(verbose_name=_(u'Тип'), default=1, db_index=True) + # do not use anywhere now + allow_comments = models.BooleanField(verbose_name=_(u'Позволить коментарии'), default=True) # fields that provides features of a visible page on the website - publish_date = models.DateTimeField(blank=True, null=True) + publish_date = models.DateTimeField(verbose_name=_(u'Дата публикации'), blank=True, null=True, db_index=True) expiry_date = models.DateTimeField(_("Expires on"), help_text=_("With Published chosen, won't be shown after this time"), blank=True, null=True) in_sitemap = models.BooleanField(_("Show in sitemap"), default=False) # fields that provides features of a visible on main page - main_page = models.BooleanField(default=False) + main_page = models.BooleanField(verbose_name=_(u'Показывать на главной'), default=False, db_index=True) main_page_time = models.DateTimeField(blank=True, null=True) # field that check if need generate description @@ -104,23 +57,22 @@ class Article(TranslatableModel): help_text=_("If checked, the description will be automatically " "generated from content. Uncheck if you want to manually " "set a custom description."), default=False) - -# published = models. created = models.DateTimeField(auto_now_add=True) modified = models.DateTimeField(auto_now=True) #translated fields translations = TranslatedFields( - main_title = models.CharField(max_length=255), - preview = models.TextField(), - description = models.TextField(blank=False), + main_title=models.CharField(verbose_name=_(u'Заголовок'), max_length=255), + preview=models.TextField(verbose_name=_(u'Превью'), ), + description=models.TextField(verbose_name=_(u'Основной текст'), blank=False), #-----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), + title=models.CharField(max_length=255, blank=True), + descriptions=models.CharField(max_length=255, blank=True), + keywords=models.CharField(max_length=255, blank=True), ) files = generic.GenericRelation('file.FileModel', content_type_field='content_type', object_id_field='object_id') + class Meta: ordering = ['-publish_date'] @@ -130,8 +82,10 @@ class Article(TranslatableModel): def translation_model(self): return self._meta.translations_model - def publish(self): + """ + set publish date. uses when publish date is none + """ self.in_sitemap = True if not self.publish_date: # save time only first time @@ -141,6 +95,10 @@ class Article(TranslatableModel): return self def get_event(self): + """ + get event connected to article + exposition has priority + """ if self.exposition: return self.exposition elif self.conference: @@ -182,8 +140,10 @@ class Article(TranslatableModel): return slugify(self.get_available_title()) def get_available_title(self): - #print self.lazy_translation_getter('main_title', self.pk) - return u'%s'%self.lazy_translation_getter('main_title', self.pk) + """ + get title from current language + """ + return u'%s' % self.lazy_translation_getter('main_title', self.pk) def _get_next_or_previous_by_publish_date(self, is_next, **kwargs): """ @@ -216,21 +176,28 @@ class Article(TranslatableModel): """ return self._get_next_or_previous_by_publish_date(False, **kwargs) - def admin_url(self): + """ + returns url for admin pages + """ if self.type == 1: - return '/admin/article/blog/%s'%self.slug + return '/admin/article/blog/%s' % self.slug elif self.type == 2: - return '/admin/article/news/%s'%self.slug + return '/admin/article/news/%s' % self.slug def get_permanent_url(self): + """ + returns object url on site(get_absolute_url analog) + """ if self.type == 1: - return '/blogs/%s/'%self.slug + return '/blogs/%s/' % self.slug elif self.type == 2: - return '/news/%s/'%self.slug + return '/news/%s/' % self.slug def get_blog_preview(self): - + """ + returns preview(fildemodel) if it exist gor current object + """ preview = self.files.filter(purpose='preview') if preview: return preview[0] @@ -238,7 +205,6 @@ class Article(TranslatableModel): return None def get_blog_preview2(self): - preview = self.files.filter(purpose='preview2') if preview: return preview[0] @@ -246,18 +212,26 @@ class Article(TranslatableModel): return None def get_catalog(self): + """ + get catalog for current objects + catalogs different for news and blogs + """ if self.type == 1: return '/blogs/' elif self.type == 2: return '/news/' def similar(self): - themes = [item ['id'] for item in self.theme.all().values('id')] - return list(Article.objects.language().exclude(id=self.id).filter(type=self.type, publish_date__isnull=False, theme__in=themes).distinct().order_by('-publish_date')[:3]) - - -from django.db.models.signals import post_save -from functions.signal_handlers import post_save_handler + """ + returns list of articles with same type and themes + :return: + """ + themes = [item['id'] for item in self.theme.all().values('id')] + return list(Article.objects.language() + .exclude(id=self.id) + .filter(type=self.type, publish_date__isnull=False, theme__in=themes) + .distinct() + .order_by('-publish_date')[:3]) post_save.connect(post_save_handler, sender=Article) \ No newline at end of file diff --git a/article/signals.py b/article/signals.py deleted file mode 100644 index df3d2d3b..00000000 --- a/article/signals.py +++ /dev/null @@ -1,6 +0,0 @@ -# -*- coding: utf-8 -*- -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) diff --git a/article/tests.py b/article/tests.py deleted file mode 100644 index 501deb77..00000000 --- a/article/tests.py +++ /dev/null @@ -1,16 +0,0 @@ -""" -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) diff --git a/article/urls.py b/article/urls.py index 482a9e76..9488f8e5 100644 --- a/article/urls.py +++ b/article/urls.py @@ -3,22 +3,38 @@ from django.conf.urls import patterns, url from views import BlogList, NewsList, BlogDetail, NewsDetail, NewsTagCatalog, BlogsFilterCatalog urlpatterns = patterns('', - url(r'^blogs/tag/(?P.*)/page/(?P\d+)/$', BlogsFilterCatalog.as_view(), {'meta_id':75, 'filter':'tag'}), - url(r'^blogs/theme/(?P.*)/page/(?P\d+)/$', BlogsFilterCatalog.as_view(), {'filter':'theme'}), - url(r'^blogs/page/(?P\d+)/$', BlogList.as_view(), {'meta_id':79}), - url(r'^blogs/tag/(?P.*)/$', BlogsFilterCatalog.as_view(), {'meta_id':75, 'filter':'tag'}), - url(r'^blogs/theme/(?P.*)/$', BlogsFilterCatalog.as_view(), {'filter':'theme'}), - url(r'^blogs/$', BlogList.as_view(), {'meta_id':79}), + url(r'^blogs/tag/(?P.*)/page/(?P\d+)/$', BlogsFilterCatalog.as_view(), + {'meta_id': 75, 'filter': 'tag'}), + url(r'^blogs/theme/(?P.*)/page/(?P\d+)/$', BlogsFilterCatalog.as_view(), + {'filter': 'theme'}), + url(r'^blogs/page/(?P\d+)/$', BlogList.as_view(), + {'meta_id': 79}), + url(r'^blogs/tag/(?P.*)/$', BlogsFilterCatalog.as_view(), + {'meta_id': 75, 'filter': 'tag'}), + url(r'^blogs/theme/(?P.*)/$', BlogsFilterCatalog.as_view(), + {'filter': 'theme'}), + url(r'^blogs/$', BlogList.as_view(), + {'meta_id': 79}), - url(r'^news/tag/(?P.*)/(?P\d+)/(?P.*)/page/(?P\d+)/$', NewsTagCatalog.as_view(), {'meta_id':77}), - url(r'^news/tag/(?P.*)/(?P\d+)/page/(?P\d+)/$', NewsTagCatalog.as_view(), {'meta_id':76}), - url(r'^news/tag/(?P.*)/page/(?P\d+)/$', NewsTagCatalog.as_view(), {'meta_id':74}), - url(r'^news/tag/(?P.*)/(?P\d+)/(?P.*)/$', NewsTagCatalog.as_view(), {'meta_id':77}), - url(r'^news/tag/(?P.*)/(?P\d+)/$', NewsTagCatalog.as_view(), {'meta_id':76}), - url(r'^news/tag/(?P.*)/$', NewsTagCatalog.as_view(), {'meta_id':74}), - url(r'^news/page/(?P\d+)/$', NewsList.as_view(), {'meta_id':78}), - url(r'^news/$', NewsList.as_view(), {'meta_id':78}), - url(r'^blogs/(?P.*)/$', BlogDetail.as_view(), {'meta_id':19}), - url(r'^news/(?P.*)/$', NewsDetail.as_view(), {'meta_id':19}), + url(r'^news/tag/(?P.*)/(?P\d+)/(?P.*)/page/(?P\d+)/$', NewsTagCatalog.as_view(), + {'meta_id': 77}), + url(r'^news/tag/(?P.*)/(?P\d+)/page/(?P\d+)/$', NewsTagCatalog.as_view(), + {'meta_id': 76}), + url(r'^news/tag/(?P.*)/page/(?P\d+)/$', NewsTagCatalog.as_view(), + {'meta_id': 74}), + url(r'^news/tag/(?P.*)/(?P\d+)/(?P.*)/$', NewsTagCatalog.as_view(), + {'meta_id': 77}), + url(r'^news/tag/(?P.*)/(?P\d+)/$', NewsTagCatalog.as_view(), + {'meta_id': 76}), + url(r'^news/tag/(?P.*)/$', NewsTagCatalog.as_view(), + {'meta_id': 74}), + url(r'^news/page/(?P\d+)/$', NewsList.as_view(), + {'meta_id': 78}), + url(r'^news/$', NewsList.as_view(), + {'meta_id':78}), + url(r'^blogs/(?P.*)/$', BlogDetail.as_view(), + {'meta_id': 19}), + url(r'^news/(?P.*)/$', NewsDetail.as_view(), + {'meta_id': 19}), ) diff --git a/article/views.py b/article/views.py index 06932d0b..5cc1fe6d 100644 --- a/article/views.py +++ b/article/views.py @@ -1,22 +1,25 @@ # -*- coding: utf-8 -*- import json from django.views.generic import DetailView +from django.conf import settings +from django.shortcuts import get_object_or_404 +from django.utils.translation import ugettext as _ from functions.custom_views import ListView -from django.http import HttpResponse from models import Article -from forms import ArticleFilterForm -from theme.models import Tag, Theme, ThemeBlog +from forms import BlogFilterForm, NewsFilterForm +from theme.models import Tag, ThemeBlog from meta.views import MetadataMixin - - class NewsList(MetadataMixin, ListView): model = Article - template_name = 'article/news_list.html' - paginate_by = 10 + template_name = 'client/article/news_list.html' + paginate_by = settings.CLIENT_PAGINATION def get_queryset(self): + """ + filters queryset by get params if they exists + """ if self.request.GET: qs = self.model.objects.news() themes = self.request.GET.getlist('theme') @@ -32,12 +35,15 @@ class NewsList(MetadataMixin, ListView): return qs else: - return self.model.objects.news().filter(publish_date__isnull=False).order_by('-publish_date') + return self.model.objects.news().filter(publish_date__isnull=False) def get_context_data(self, **kwargs): + """ + add filter form to context + """ context = super(NewsList, self).get_context_data(object_list=self.object_list) if self.request.GET: - filter_form = ArticleFilterForm(self.request.GET) + filter_form = NewsFilterForm(self.request.GET) tags = self.request.GET.getlist('tag') if u'' in tags: tags.remove(u'') @@ -48,7 +54,7 @@ class NewsList(MetadataMixin, ListView): filter_form.fields['tag'].widget.attrs['data-predifined'] = json.dumps(tags) filter_form.fields['tag'].widget.attrs['value'] = '' else: - filter_form = ArticleFilterForm() + filter_form = NewsFilterForm() context['article_filter_form'] = filter_form return context @@ -57,15 +63,18 @@ class NewsList(MetadataMixin, ListView): class NewsDetail(MetadataMixin, DetailView): model = Article slug_field = 'slug' - template_name = 'article/news.html' + template_name = 'client/article/news.html' class BlogList(MetadataMixin, ListView): model = Article - template_name = 'article/blog_list.html' - paginate_by = 10 + template_name = 'client/article/blog_list.html' + paginate_by = settings.CLIENT_PAGINATION def get_queryset(self): + """ + filters queryset by get params if they exists + """ if self.request.GET: qs = self.model.objects.blogs() @@ -85,9 +94,12 @@ class BlogList(MetadataMixin, ListView): return self.model.objects.blogs() def get_context_data(self, **kwargs): + """ + add filter form to context + """ context = super(BlogList, self).get_context_data(object_list=self.object_list) if self.request.GET: - filter_form = ArticleFilterForm(self.request.GET) + filter_form = BlogFilterForm(self.request.GET) tags = self.request.GET.getlist('tag') if u'' in tags: tags.remove(u'') @@ -98,25 +110,23 @@ class BlogList(MetadataMixin, ListView): filter_form.fields['tag'].widget.attrs['data-predifined'] = json.dumps(tags) filter_form.fields['tag'].widget.attrs['value'] = '' else: - filter_form = ArticleFilterForm() + filter_form = BlogFilterForm() context['article_filter_form'] = filter_form return context - class BlogDetail(MetadataMixin, DetailView): model = Article slug_field = 'slug' - template_name = 'article/article.html' + template_name = 'client/article/article.html' -from exposition.views import ExpoCatalog -from django.conf import settings -from django.shortcuts import get_object_or_404 -from django.utils.translation import ugettext as _ - class NewsTagCatalog(MetadataMixin, ListView): + """ + returns queryset filtered by filtered_object and dates + filtered_object can be theme or tag + """ model = Article template_name = 'client/article/catalog.html' catalog_url = '/news/tag/' @@ -152,7 +162,6 @@ class NewsTagCatalog(MetadataMixin, ListView): self.month = {'text': monthes[month]['name'], 'link': '%s%s/%s/%s/'%(self.catalog_url, self.filter_object.url, year, month)} return qs - def get_context_data(self, **kwargs): context = super(NewsTagCatalog, self).get_context_data(**kwargs) context['filter_object'] = self.filter_object @@ -162,7 +171,6 @@ class NewsTagCatalog(MetadataMixin, ListView): return context - class BlogsFilterCatalog(MetadataMixin, ListView): model = Article template_name = 'client/article/catalog.html' @@ -206,7 +214,6 @@ class BlogsFilterCatalog(MetadataMixin, ListView): self.month = {'text': monthes[month]['name'], 'link': '%s%s/%s/%s/'%(self.catalog_url, self.filter_object.url, year, month)} return qs - def get_context_data(self, **kwargs): context = super(BlogsFilterCatalog, self).get_context_data(**kwargs) context['filter_object'] = self.filter_object diff --git a/banners/__init__.py b/banners/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/banners/models.py b/banners/models.py deleted file mode 100644 index 8cd34977..00000000 --- a/banners/models.py +++ /dev/null @@ -1,15 +0,0 @@ -from django.db import models - -# Create your models here. - -class Redirect(models.Model): - redirect = models.URLField() - count = models.PositiveIntegerField(default=0) - views = models.PositiveIntegerField(default=0) - - - def __unicode__(self): - return self.redirect - - def get_object_url(self): - return '/redirect/redirect/%d/'%self.id diff --git a/banners/tests.py b/banners/tests.py deleted file mode 100644 index 501deb77..00000000 --- a/banners/tests.py +++ /dev/null @@ -1,16 +0,0 @@ -""" -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) diff --git a/banners/urls.py b/banners/urls.py deleted file mode 100644 index a0ce0988..00000000 --- a/banners/urls.py +++ /dev/null @@ -1,7 +0,0 @@ -# -*- coding: utf-8 -*- -from django.conf.urls import patterns, url - -urlpatterns = patterns('', - url(r'redirect/(?P.*)/$', 'banners.views.redirect'), -) - diff --git a/banners/views.py b/banners/views.py deleted file mode 100644 index 22eb6ca5..00000000 --- a/banners/views.py +++ /dev/null @@ -1,10 +0,0 @@ -from django.http import HttpResponseRedirect -from django.shortcuts import get_object_or_404 -from banners.models import Redirect -from django.db.models import F - -def redirect(request, id): - redirect = get_object_or_404(Redirect, id=id) - Redirect.objects.filter(id=id).update(count=F('count')+1) - return HttpResponseRedirect(redirect.redirect) - diff --git a/city/management/commands/city_lost_create.py b/city/management/commands/city_lost_create.py deleted file mode 100644 index 033de6f3..00000000 --- a/city/management/commands/city_lost_create.py +++ /dev/null @@ -1,78 +0,0 @@ -# -*- coding: utf-8 -*- -from django.core.management.base import BaseCommand, CommandError -from city.models import City -from country.models import Country - -cities = [ - {'id':'-1563952', 'country':'11', 'url':'canberra-australia', 'ru':u'Канберра', 'en':'Canberra'}, -] -""" -cities = [ - {'id':'-1563952', 'country':'11', 'url':'canberra-australia', 'ru':u'Канберра', 'en':'Canberra'}, - {'id':'-1586844', 'country':'11', 'url':'melbourne-australia', 'ru':u'Мельбурн', 'en':'Melbourne'}, - {'id':'-1594675', 'country':'11', 'url':'perth-australia', 'ru':u'Перт', 'en':'Perth'}, - {'id':'-1555188', 'country':'11', 'url':'adelaide-australia', 'ru':u'Аделаида', 'en':'Adelaide'}, - {'id':'-1561728', 'country':'11', 'url':'brisbane-australia', 'ru':u'Брисбен', 'en':'Brisbane'}, - {'id':'-1569058', 'country':'11', 'url':'darwin-australia', 'ru':u'Дарвин', 'en':'Darwin'}, - - {'id':'-1989985', 'country':'10', 'url':'salzburg-austria', 'ru':u'Зальцбург', 'en':'Salzburg'}, - {'id':'-1981445', 'country':'10', 'url':'innsbruck-austria', 'ru':u'Инсбрук', 'en':'Innsbruck'}, - {'id':'-1982354', 'country':'10', 'url':'klagenfurt-austria', 'ru':u'Клагенфурте', 'en':'Klagenfurt'}, - - {'id':'-979186', 'country':'8', 'url':'buenos-aires-argentina', 'ru':u'Буэнос-Айрес', 'en':'Buenos Aires'}, - - {'id':'-1955925', 'country':'17', 'url':'charleroi-belgium', 'ru':u'Шарлеруа', 'en':'Charleroi'}, - {'id':'-1953257', 'country':'17', 'url':'antwerp-belgium', 'ru':u'Антверпен', 'en':'Antwerp'}, - {'id':'-1955538', 'country':'17', 'url':'brussels-belgium', 'ru':u'Брюссель', 'en':'Brussels'}, - {'id':'-1958757', 'country':'17', 'url':'ghent-belgium', 'ru':u'Гент', 'en':'Ghent'}, - {'id':'-1963947', 'country':'17', 'url':'leuven-belgium', 'ru':u'Левен', 'en':'Leuven'}, - {'id':'-1964016', 'country':'17', 'url':'liege-belgium', 'ru':u'Льеж', 'en':'Liège'}, - {'id':'-1965564', 'country':'17', 'url':'mons-belgium', 'ru':u'Монс', 'en':'Mons'}, - {'id':'-1956109', 'country':'17', 'url':'ciney-belgium', 'ru':u'Сине', 'en':'Ciney'}, - {'id':'-1959925', 'country':'17', 'url':'hasselt-belgium', 'ru':u'Хасселт', 'en':'Hasselt'}, - - {'id':'-629138', 'country':'27', 'url':'belo-horizonte-brazil', 'ru':u'Белу-Оризонти', 'en':'Belo Horizonte'}, - {'id':'-663509', 'country':'27', 'url':'porto-alegre-brazil', 'ru':u'Порту-Алегри', 'en':'Porto Alegre'}, - {'id':'-629039', 'country':'27', 'url':'Belem-brazil', 'ru':u'Белем', 'en':'Belém'}, - {'id':'-644901', 'country':'27', 'url':'goiania-brazil', 'ru':u'Гояния', 'en':'Goiânia'}, - {'id':'-653186', 'country':'27', 'url':'manaus-brazil', 'ru':u'Манаус', 'en':'Manaus'}, - {'id':'-657942', 'country':'27', 'url':'olinda-brazil', 'ru':u'Olinda', 'en':'Olinda'}, - {'id':'-657510', 'country':'27', 'url':'novo-hamburgo-brazil', 'ru':u'Novo Hamburgo', 'en':'Novo Hamburgo'}, - - {'id':'-2112243', 'country':'84', 'url':'surat-india', 'ru':u'Сурат', 'en':'Sūrat'}, - {'id':'-3102179', 'country':'85', 'url':'basrah-iraq', 'ru':u'Басра', 'en':'Basrah'}, - {'id':'-559845', 'country':'33', 'url':'abbotsford-canada', 'ru':u'Abbotsford', 'en':'Abbotsford'}, - {'id':'-561990', 'country':'33', 'url':'calgary-canada', 'ru':u'Калгари', 'en':'Calgary'}, - {'id':'-571851', 'country':'33', 'url':'quebec-canada', 'ru':u'Квебек', 'en':'Quebec'}, - {'id':'-569541', 'country':'33', 'url':'montreal-canada', 'ru':u'Монреаль', 'en':'Montreal'}, - {'id':'-570760', 'country':'33', 'url':'ottawa-canada', 'ru':u'Оттава', 'en':'Ottawa'}, - {'id':'-567785', 'country':'33', 'url':'laval-canada', 'ru':u'Лаваль', 'en':'Laval'}, - {'id':'-564968', 'country':'33', 'url':'fredericton-canada', 'ru':u'Фредериктон', 'en':'Fredericton'}, - {'id':'-564064', 'country':'33', 'url':'edmonton-canada', 'ru':u'Эдмонтон', 'en':'Edmonton'}, - {'id':'-569498', 'country':'33', 'url':'moncton-canada', 'ru':u'Монктон', 'en':'Moncton'}, - {'id':'-562447', 'country':'33', 'url':'charlottetown-canada', 'ru':u'Шарлоттаун', 'en':'Charlottetown'}, - - - {'id':'-2764584', 'country':'147', 'url':'karachi-pakistan', 'ru':u'Карачи', 'en':'Karachi'}, - {'id':'-2767043', 'country':'147', 'url':'lahore-pakistan', 'ru':u'Лахор', 'en':'Lahore'}, - - ] -""" - -class Command(BaseCommand): - def handle(self, *args, **options): - for city in cities: - #City.objects.get(id=city['id']).delete() - - country = Country.objects.get(id=city['country']) - c = City(id=city['id'], country=country, url=city['url']) - c.translate('ru') - c.name = city['ru'] - print('pre save %s'%str(c)) - c.save() - print('post save %s'%str(c)) - - - - - diff --git a/city/management/commands/city_slug.py b/city/management/commands/city_slug.py deleted file mode 100644 index d60006a9..00000000 --- a/city/management/commands/city_slug.py +++ /dev/null @@ -1,22 +0,0 @@ -# -*- coding: utf-8 -*- -from django.core.management.base import BaseCommand, CommandError -from city.models import City -from country.models import Country -from functions.form_check import translit_with_separator -from django.db import IntegrityError - - -class Command(BaseCommand): - def handle(self, *args, **options): - - qs = City.objects.language('en').filter() - for c in qs: - url = translit_with_separator(c.name.encode('utf8')) - c.url = url - try: - c.save() - except IntegrityError: - continue - - print(c.url) - #print(qs.count()) \ No newline at end of file diff --git a/city/management/commands/city_update_from_old.py b/city/management/commands/city_update_from_old.py deleted file mode 100644 index 465d0930..00000000 --- a/city/management/commands/city_update_from_old.py +++ /dev/null @@ -1,30 +0,0 @@ -# -*- coding: utf-8 -*- -import MySQLdb -from MySQLdb.cursors import DictCursor -from django.core.management.base import BaseCommand, CommandError -from django.utils import translation -from country.models import City - - -class Command(BaseCommand): - def handle(self, *args, **options): - db = MySQLdb.connect(host="localhost", - user="kotzilla", - passwd="qazedc", - db="test2", - charset='utf8', - cursorclass=DictCursor) - cursor = db.cursor() - sql = """SELECT title, url, inflect - FROM old_expomap.products_places - WHERE parent_id > 0 """ - - - cursor.execute(sql) - result = cursor.fetchall() - for res in result: - name = res['title'] - url = res['url'] - inflect = res['inflect'] - City.objects.filter(translations__name=name).update(inflect=inflect, old_url=url) - print(name.encode('utf-8')) \ No newline at end of file diff --git a/city/management/commands/create_hotels.py b/city/management/commands/create_hotels.py index 11d04f8b..1f6dc2b2 100644 --- a/city/management/commands/create_hotels.py +++ b/city/management/commands/create_hotels.py @@ -12,8 +12,8 @@ HOTEL_URL = 'https://distribution-xml.booking.com/json/bookings.getHotels?' HOTEL_PHOTO_URL = 'https://distribution-xml.booking.com/json/bookings.getHotelPhotos?' -username = 'expomap' -password = '33xp00m33p' +username = settings.BOOKING_USERNAME +password = settings.BOOKING_PASSWORD langs = [code for code, name in settings.LANGUAGES] def create_hotels(hotels, city): @@ -34,8 +34,8 @@ def create_hotels(hotels, city): tr_model.objects.bulk_create(dj_hotels_translation) print('city: %s'%str(city)) -def main(): +def main(): cities = City.objects.select_related('place_expositions', 'place_conferences').\ filter(Q(place_expositions__city__isnull=False) | Q(place_conferences__city__isnull=False)).distinct() for city in cities: @@ -67,22 +67,4 @@ def main(): class Command(BaseCommand): def handle(self, *args, **options): - main() - """ - request = urllib2.Request(URL) - base64string = base64.encodestring('%s:%s' % (username, password)).replace('\n', '') - request.add_header("Authorization", "Basic %s" % base64string) - - try: - response = urllib2.urlopen(request) - code = response.getcode() - except urllib2.HTTPError, e: - code = e.code - except urllib2.URLError, e: - code = e.code - - json_hotels = response.read() - hotels = json.loads(json_hotels) - - print(hotels) - """ \ No newline at end of file + main() \ No newline at end of file diff --git a/city/management/commands/hotel_photos.py b/city/management/commands/hotel_photos.py index b34486b5..3ebb4f35 100644 --- a/city/management/commands/hotel_photos.py +++ b/city/management/commands/hotel_photos.py @@ -4,13 +4,14 @@ from django.conf import settings from django.core.management.base import BaseCommand, CommandError from city.models import Hotel, City from functions.files import get_alternative_filename +from concurrent.futures import ThreadPoolExecutor -username = 'expomap' -password = '33xp00m33p' +username = settings.BOOKING_USERNAME +password = settings.BOOKING_PASSWORD HOTEL_URL = 'https://distribution-xml.booking.com/json/bookings.getHotels?' HOTEL_PHOTO_URL = 'https://distribution-xml.booking.com/json/bookings.getHotelPhotos?' -from concurrent.futures import ThreadPoolExecutor + def upload(photo): @@ -37,15 +38,6 @@ def download_photos(photos): result[i[0]] = i[1] return result - """ - result = {} - for photo in photos: - res = upload(photo) - result[res[0]] = res[1] - return result - """ - - def run(hotels): ids = [str(hotel.id) for hotel in hotels]# comment after testing url = HOTEL_PHOTO_URL+'hotel_ids=%s'%','.join(ids) diff --git a/city/management/commands/update_hotels_currency.py b/city/management/commands/update_hotels_currency.py index f28365d4..1ddd322a 100644 --- a/city/management/commands/update_hotels_currency.py +++ b/city/management/commands/update_hotels_currency.py @@ -1,11 +1,13 @@ -import urllib2, base64 +import urllib2 +import base64 import json from django.core.management.base import BaseCommand, CommandError +from django.conf import settings from city.models import Hotel HOTEL_URL = 'https://distribution-xml.booking.com/json/bookings.getHotels?' -username = 'expomap' -password = '33xp00m33p' +username = settings.BOOKING_USERNAME +password = settings.BOOKING_PASSWORD def handle_hotels(hotel_ids): @@ -41,11 +43,10 @@ def main(): while hotels_todo > 0: hotel_ids = [str(item.id) for item in list(Hotel.objects.filter(currency__isnull=True)[:100])] handle_hotels(hotel_ids) - hotels_todo =Hotel.objects.filter(currency__isnull=True)[:100].count() - - + hotels_todo = Hotel.objects.filter(currency__isnull=True)[:100].count() class Command(BaseCommand): def handle(self, *args, **options): - main() + # fill hotel currencies + main() \ No newline at end of file diff --git a/city/management/commands/update_hotels_price.py b/city/management/commands/update_hotels_price.py index 38243658..7db61986 100644 --- a/city/management/commands/update_hotels_price.py +++ b/city/management/commands/update_hotels_price.py @@ -1,12 +1,14 @@ -import urllib2, base64 +import urllib2 +import base64 import json -from django.core.management.base import BaseCommand, CommandError +from django.core.management.base import BaseCommand +from django.conf import settings from city.models import Hotel URL = 'https://distribution-xml.booking.com/json/bookings.getRooms?' -username = 'expomap' -password = '33xp00m33p' -test_id = '298239' +username = settings.BOOKING_USERNAME +password = settings.BOOKING_PASSWORD + def get_prices(rooms): min_price = None @@ -28,6 +30,7 @@ def get_prices(rooms): return min_price, max_price + def handle_hotels(hotel_id): hotel_ids_str = hotel_id new_url = URL + 'hotel_ids=%s'%hotel_ids_str @@ -48,21 +51,17 @@ def handle_hotels(hotel_id): Hotel.objects.filter(id=hotel_id).update(min_price=min_price, max_price=max_price) print('success') + def main(): - hotel_id = test_id for hotel in Hotel.objects.all(): try: handle_hotels(str(hotel.id)) except: continue - #hotels_todo = Hotel.objects.filter(currency__isnull=True)[:100].count() - #while hotels_todo > 0: - #hotel_ids = [str(item.id) for item in list(Hotel.objects.filter(currency__isnull=True)[:100])] - #handle_hotels(hotel_ids) - #hotels_todo = Hotel.objects.filter(currency__isnull=True)[:100].count() - class Command(BaseCommand): def handle(self, *args, **options): + # update hotels prices + # runs one time in a week main() \ No newline at end of file diff --git a/city/models.py b/city/models.py index 8ec29ea9..cb0bdeca 100644 --- a/city/models.py +++ b/city/models.py @@ -3,147 +3,149 @@ from datetime import date from django.db import models from django.db.models.signals import post_save, pre_save from django.utils import translation +from django.utils.translation import ugettext_lazy as _ from hvad.models import TranslatableModel, TranslatedFields, TranslationManager from bitfield import BitField from sorl.thumbnail import ImageField -# models from directories.models import Iata -from service.models import Service from exposition.models import Exposition from place_exposition.models import PlaceExposition -from organiser.models import Organiser from conference.models import Conference from seminar.models import Seminar from webinar.models import Webinar -# custom functions from functions.db import db_table_exists from functions.signal_handlers import post_save_handler, pre_save_handler from functions.models_methods import ExpoManager, CityManager +from service.models import Service #check if table exist and create flags if true -flags = [str(item.url) for item in Service.objects.all()] if db_table_exists('service_service') else [] +#flags = [str(item.url) for item in Service.objects.all()] if db_table_exists('service_service') else [] +flags = ['catalog', 'translator', 'participation', 'remote', 'tickets', 'visit', 'buildstand'] class City(TranslatableModel): """ - Create City model - - Uses hvad.TranslatableModel which is child of django.db.models class - + City describes cities with translations in the project + all cities with id from booking.com -> id city on booking equal this city objects """ objects = ExpoManager() used = CityManager() catalog = '/city/' - services = BitField(flags=flags) - - url = models.SlugField(unique=True) - # - old_url = models.CharField(max_length=55) - inflect = models.CharField(max_length=255, blank=True) - #relations - country = models.ForeignKey('country.Country', null=True, on_delete=models.PROTECT, related_name='cities') - code_IATA = models.ForeignKey(Iata, blank=True, null=True) - - population = models.PositiveIntegerField(blank=True, null=True) - phone_code = models.PositiveIntegerField(blank=True, null=True) + url = models.SlugField(verbose_name=_(u'Url'), unique=True) + logo = models.ImageField(verbose_name='Logo', upload_to='city/logo/', blank=True, max_length=255) + old_url = models.CharField(verbose_name=_(u'Url старой бд'), max_length=55) + # inflect name for russian language. example- в Москве + inflect = models.CharField(verbose_name=_(u'Склонение'), max_length=255, blank=True) + country = models.ForeignKey('country.Country', verbose_name=_(u'Страна'), null=True, on_delete=models.PROTECT, + related_name='cities') + code_IATA = models.ForeignKey(Iata, verbose_name=_(u'IATA'), blank=True, null=True) + + population = models.PositiveIntegerField(verbose_name=_(u'Население'), blank=True, null=True) + phone_code = models.PositiveIntegerField(verbose_name=_(u'Тел. код '), blank=True, null=True) #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), - shoping = models.TextField(blank=True), + name = models.CharField(verbose_name=_(u'Название'), max_length=50), + region = models.CharField(verbose_name=_(u'Регион'), max_length=255), + transport = models.TextField(verbose_name=_(u'Транспорт'), blank=True), + description = models.TextField(verbose_name=_(u'Описание'), blank=True), + famous_places = models.TextField(verbose_name=_(u'Знаменитые места'), blank=True), + shoping = models.TextField(verbose_name=_(u'Магазины'), blank=True), #-----meta title = models.CharField(max_length=255), descriptions = models.CharField(max_length=255), keywords = models.CharField(max_length=255), ) - # fields saves information about creating and changing model + created = models.DateTimeField(auto_now_add=True) modified = models.DateTimeField(auto_now=True) - logo = models.ImageField(verbose_name='Logo', upload_to='city/logo/', blank=True, max_length=255) - class Meta: - ordering = ['translations__name'] + #class Meta: + #ordering = ['translations__name'] def __unicode__(self): return self.lazy_translation_getter('name', self.pk) def get_hotels(self): + """ + returns list of 4 hotels in current city + """ return list(self.hotels.all()[:4]) def get_events(self): + """ + returns nearest expos in this city + """ now = date.today() return Exposition.objects.filter(data_begin__gte=now, city=self).order_by('data_begin')[:3] def get_places(self): return PlaceExposition.objects.filter(city=self)[:3] - def get_organisers(self): - return Organiser.objects.filter(city=self) - def get_permanent_url(self): return self.catalog+self.url - def events_catalog(self): - return Exposition.catalog+'city-%s'%self.url - - def places_catalog(self): - return PlaceExposition.catalog+'city-%s'%self.url - def expositions_number(self): - - return Exposition.objects.filter(city=self.id).count() + return Exposition.objects.filter(city=self).count() def conferences_number(self): - - return Conference.objects.filter(city=self.id).count() + return Conference.objects.filter(city=self).count() def seminars_number(self): - - return Seminar.objects.filter(city=self.id).count() + return Seminar.objects.filter(city=self).count() def webinars_number(self): - - return Webinar.objects.filter(city=self.id).count() + return Webinar.objects.filter(city=self).count() def get_parent(self): - parent = {'text' : self.country.name, 'id': self.country.id, 'name': 'co', - 'parent':{'text' : self.country.area.name, 'id': self.country.area.id, 'name': 'area'}} + """ + returns dictionary of parents + uses in search in ajax requests + """ + parent = {'text': self.country.name, 'id': self.country.id, 'name': 'co', + 'parent': { + 'text': self.country.area.name, + 'id': self.country.area.id, + 'name': 'area'} + } return parent def get_sub_categories(self): + """ + uses in search + city has no children objects, so returns empty list + """ return [] def get_index_text(self): + """ + returns string of names in all languages for indexing it in search engine + """ translation.activate('ru') translations = self.translations.all() names = ' '.join([tr.name for tr in translations]) return names - - - class Hotel(TranslatableModel): - url = models.URLField(max_length=255) - city = models.ForeignKey(City, related_name='hotels') - - ranking = models.FloatField(blank=True, null=True) - hotel_class = models.CharField(max_length=10, blank=True) - latitude = models.FloatField(blank=True, null=True) - longitude = models.FloatField(blank=True, null=True) - photo = ImageField(upload_to='hotels') - currency = models.CharField(max_length=10) - min_price = models.FloatField(blank=True, null=True) - max_price = models.FloatField(blank=True, null=True) - checked = models.NullBooleanField(blank=True, null=True) + """ + Hotels downloaded from booking.com with booking api + """ + url = models.URLField(verbose_name=_(u'Url'), max_length=255) + city = models.ForeignKey(City, verbose_name=_(u'Город'), related_name='hotels') + ranking = models.FloatField(verbose_name=_(u'Рейтинг'), blank=True, null=True) + hotel_class = models.CharField(verbose_name=_(u'Клас отеля'), max_length=10, blank=True) + latitude = models.FloatField(verbose_name=_(u'Широта'), blank=True, null=True) + longitude = models.FloatField(verbose_name=_(u'Долгота'), blank=True, null=True) + photo = ImageField(verbose_name=_(u'Фото'), upload_to='hotels') + currency = models.CharField(verbose_name=_(u'Валюта'), max_length=10) + min_price = models.FloatField(verbose_name=_(u'Мин. цена'), blank=True, null=True) + max_price = models.FloatField(verbose_name=_(u'Макс. цена'), blank=True, null=True) + checked = models.NullBooleanField(verbose_name=_(u'Проверено'), blank=True, null=True) translations = TranslatedFields( - name = models.CharField(max_length=255, blank=True), - address = models.CharField(max_length=255, blank=True) + name=models.CharField(verbose_name=_(u'Название'), max_length=255, blank=True), + address=models.CharField(verbose_name=_(u'Адрес'), max_length=255, blank=True) ) diff --git a/city/signals.py b/city/signals.py deleted file mode 100644 index faaaf799..00000000 --- a/city/signals.py +++ /dev/null @@ -1,3 +0,0 @@ -# -*- coding: utf-8 -*- - - diff --git a/city/tests.py b/city/tests.py deleted file mode 100644 index 501deb77..00000000 --- a/city/tests.py +++ /dev/null @@ -1,16 +0,0 @@ -""" -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) diff --git a/city/urls.py b/city/urls.py index 4d3a78cd..2496e422 100644 --- a/city/urls.py +++ b/city/urls.py @@ -4,6 +4,6 @@ from views import CityView urlpatterns = patterns('', url(r'get-city/', 'city.views.get_city'), - url(r'(?P.*)', CityView.as_view()), - + # commented for good times + #url(r'(?P.*)', CityView.as_view()), ) diff --git a/city/views.py b/city/views.py index 13fcc6f4..0cf49417 100644 --- a/city/views.py +++ b/city/views.py @@ -8,12 +8,18 @@ from settings.views import get_by_lang class CityView(DetailView): + """ + this view is not used yet + """ model = City slug_field = 'url' - template_name = 'city/city.html' + template_name = 'client/city/city.html' def get_city(request): + """ + returns filtered cities in current language in json format + """ if request.is_ajax(): country = request.GET.get('country') term = request.GET.get('term', '').capitalize() diff --git a/company/management/__init__.py b/company/management/__init__.py deleted file mode 100644 index 8b137891..00000000 --- a/company/management/__init__.py +++ /dev/null @@ -1 +0,0 @@ - diff --git a/company/management/commands/__init__.py b/company/management/commands/__init__.py deleted file mode 100644 index 8b137891..00000000 --- a/company/management/commands/__init__.py +++ /dev/null @@ -1 +0,0 @@ - diff --git a/company/management/commands/company_from_old_db.py b/company/management/commands/company_from_old_db.py deleted file mode 100644 index 15d6e68a..00000000 --- a/company/management/commands/company_from_old_db.py +++ /dev/null @@ -1,97 +0,0 @@ -from django.core.management.base import BaseCommand, CommandError -from company.models import Company -from theme.models import Theme, Tag -from accounts.models import User -from functions.form_check import translit_with_separator -import datetime - -import MySQLdb -from MySQLdb.cursors import DictCursor - -def convert_to_int(st): - if not st: - return None - deduct = ('-','(',')','.',' ') - for elem in deduct: - st = st.replace(elem, '') - if st.isdigit(): - return int(st) - else: - return None - -class Command(BaseCommand): - def handle(self, *args, **options): - db = MySQLdb.connect(host="localhost", - user="root", - passwd="qazedc", - db="expomap_ru", - charset='utf8', - cursorclass=DictCursor) - - cursor = db.cursor() - sql = "select * from customers_company" - cursor.execute(sql) - - res = cursor.fetchall() - - - for c in res: - - phone = convert_to_int(c.get('phone')) - fax = convert_to_int(c.get('fax')) - url = c['url'] - if not url: - url = translit_with_separator(c.get('title')) - - - company = Company(id=c['company_id'], url=url, phone=phone, fax=fax, - email=c.get('email'), web_page=c.get('website'), twitter=c.get('twitter', '')) - - company.translate('ru') - company.name = c.get('title') - company.specialization = c.get('specialize') - company.description = c.get('about') - company.address_inf = c.get('adress') - user = User.objects.safe_get(id=user_id) - company.creator = user - print('not_saved: %s'%c['title']) - company.save() - user_id = c['customers_id'] - print('saved: %s'%str(company)) - - if user: - user.company = company - if not user.last_login: - now = datetime.datetime.now() - user.last_login = now - - user.save() - - theme = None - theme_id = c.get('otrasly') - if theme_id: - try: - theme = Theme.objects.get(id=theme_id) - except Theme.DoesNotExist: - continue - company.theme.add(theme) - - if not theme: - continue - - tags = c.get('tags') - if tags: - tags = tags.split(',') - if tags: - for tag_id in tags: - try: - tag = Tag.objects.get(id=tag_id) - except Tag.DoesNotExist: - continue - if tag.theme == theme: - company.tag.add(tag) - else: - continue - - #print(str(type(res[0]['phone']))) - print('success') \ No newline at end of file diff --git a/company/management/commands/company_test.py b/company/management/commands/company_test.py deleted file mode 100644 index a8060e93..00000000 --- a/company/management/commands/company_test.py +++ /dev/null @@ -1,77 +0,0 @@ -from django.core.management.base import BaseCommand, CommandError -from company.models import Company -from theme.models import Theme, Tag -from accounts.models import User -from functions.form_check import translit_with_separator -import datetime - -import MySQLdb -from MySQLdb.cursors import DictCursor - -def convert_to_int(st): - if not st: - return None - deduct = ('-','(',')','.',' ') - for elem in deduct: - st = st.replace(elem, '') - if st.isdigit(): - return int(st) - else: - return None - -class Command(BaseCommand): - def handle(self, *args, **options): - db = MySQLdb.connect(host="localhost", - user="root", - passwd="qazedc", - db="expomap_ru", - charset='utf8', - cursorclass=DictCursor) - - cursor = db.cursor() - sql = "select * from customers_company WHere otrasly>0" - cursor.execute(sql) - - res = cursor.fetchall() - print(len(res)) - - for c in res: - id = c['company_id'] - company = Company.objects.safe_get(id=id) - if not company: - continue - - theme_id = c.get('otrasly') - tags = c.get('tags') - - - if theme_id: - try: - theme = Theme.objects.get(id=theme_id) - except Theme.DoesNotExist: - continue - print(theme) - print(company) - company.theme.add(theme) - print('add %s theme to %s company'%(str(theme), str(company))) - print('123') - if not theme: - continue - - - tags = c.get('tags') - if tags: - tags = tags.split(',') - if tags: - for tag_id in tags: - try: - tag = Tag.objects.get(id=tag_id) - except Tag.DoesNotExist: - continue - if tag.theme == theme: - company.tag.add(tag) - print('add %s tag to %s company'%(str(tag), str(company))) - else: - continue - - diff --git a/conference/admin.py b/conference/admin.py index 7e22fc61..01a24f89 100644 --- a/conference/admin.py +++ b/conference/admin.py @@ -272,7 +272,6 @@ class ConferenceView(AdminView): else: return form_class() - def get_context_data(self, **kwargs): context = super(ConferenceView, self).get_context_data(**kwargs) obj = self.set_obj() @@ -294,6 +293,7 @@ class ConferenceListView(AdminListView): form_class = ConferenceFilterForm model = Conference + def upload_conference_photo(request, conf_id): return upload_photo(request, conf_id, Conference) diff --git a/conference/forms.py b/conference/forms.py index 4cba3c0b..49a48de8 100644 --- a/conference/forms.py +++ b/conference/forms.py @@ -34,10 +34,9 @@ class ConferenceCreateForm(forms.Form): save function saves data in Conference object. If it doesnt exist create new object """ - 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 года')) + 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 года'), (0.2, u'Раз в 5 лет')) public = [(item1, item2) for item1, item2 in BIT_AUDIENCE] @@ -68,8 +67,8 @@ 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) + 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) diff --git a/conference/models.py b/conference/models.py index 8f067230..02d25008 100644 --- a/conference/models.py +++ b/conference/models.py @@ -2,6 +2,7 @@ import datetime from django.utils.translation import ugettext as _ from django.db import models +from django.conf import settings from django.db.models import Q from django.db.models.signals import post_save, pre_save from django.contrib.contenttypes import generic @@ -22,8 +23,9 @@ from functions.model_mixin import EventMixin, ExpoMixin from functions.models_methods import hvad_to_dict # check if table exist and create flags if true -flags = [item.url for item in Service.objects.all()] if db_table_exists('service_service') else [] -from django.conf import settings +#flags = [item.url for item in Service.objects.all()] if db_table_exists('service_service') else [] +flags = ['catalog', 'translator', 'participation', 'remote', 'tickets', 'visit', 'buildstand'] + CURRENCY = settings.CURRENCY BIT_AUDIENCE = settings.BIT_AUDIENCE @@ -66,7 +68,7 @@ class Conference(TranslatableModel, EventMixin, ExpoMixin): blank=True, null=True, related_name='conference_companies') users = models.ManyToManyField('accounts.User', verbose_name='Посетители выставки', blank=True, null=True, related_name='conference_users') - photogallery = models.ForeignKey('photologue.Gallery', blank=True, null=True) + photogallery = models.ForeignKey('photologue.Gallery', blank=True, null=True, on_delete=models.SET_NULL) logo = models.ImageField(verbose_name='Logo', upload_to='conference/logo/', blank=True) rating = models.IntegerField(default=0, db_index=True) # добавить индекс в базе @@ -150,7 +152,6 @@ class Conference(TranslatableModel, EventMixin, ExpoMixin): else: return [] - def get_catalog_url(self): return '/conference/' @@ -193,25 +194,8 @@ class Conference(TranslatableModel, EventMixin, ExpoMixin): tags = ' '.join([' '.join(tag.get_all_names()) for tag in self.tag.all()]) return names + ' ' + titles + ' ' + themes + ' ' + tags - def get_gallery(self): - if self.photogallery: - return self.photogallery - - data = {} - model = type(self) - for code, name in settings.LANGUAGES: - obj = model._meta.translations_model.objects.get(language_code = code,master__id=self.id) #access to translated fields - data['title_%s'%code] = obj.name - data['description_%s'%code] = obj.description - - gallery = Gallery() - - fill_with_signal(Gallery, gallery, data) - self.photogallery = gallery - self.save() - - - return gallery + def upload_photo_url(self): + return '/admin/conference/upload-photo/%s/' % self.id class Statistic(TranslatableModel): diff --git a/conference/urls.py b/conference/urls.py index 77279394..9e24ad9a 100644 --- a/conference/urls.py +++ b/conference/urls.py @@ -2,7 +2,7 @@ from django.conf.urls import patterns, include, url from views import ConferenceDetail, ConferenceList, ConferenceByCity, ConferenceByCountry, ConferenceByTheme,\ ConferenceCountryCatalog, ConferenceCityCatalog, ConferenceTagCatalog, ConferenceThemeCatalog, ConferenceMembers,\ - ConferenceVisitors, ConferenceServiceView, ConferenceThankView, ConferenceByTag + ConferenceVisitors, ConferenceServiceView, ConferenceThankView, ConferenceByTag, ConferencePhotoView from exposition.views import ExpositionSearchView urlpatterns = patterns('', @@ -61,6 +61,8 @@ urlpatterns = patterns('', url(r'conference/tag/(?P.*)/(?P\d+)/$', ConferenceTagCatalog.as_view(), {'meta_id':33}), url(r'conference/tag/(?P.*)/$', ConferenceTagCatalog.as_view(), {'meta_id':32}), # conf additional pages + url(r'^conference/(?P.*)/photo/page/(?P\d+)/$', ConferencePhotoView.as_view()), + url(r'^conference/(?P.*)/photo/$', ConferencePhotoView.as_view()), url(r'conference/(?P.*)/visitors/page/(?P\d+)/$', ConferenceVisitors.as_view()), url(r'conference/(?P.*)/visitors/$', ConferenceVisitors.as_view()), url(r'conference/(?P.*)/members/page/(?P\d+)/$', ConferenceMembers.as_view()), diff --git a/conference/views.py b/conference/views.py index c5a854e8..abcbd2ce 100644 --- a/conference/views.py +++ b/conference/views.py @@ -28,7 +28,7 @@ MONTHES = settings.MONTHES class ConferenceBy(JitterCacheMixin, MetadataMixin, ListView): cache_range = settings.CACHE_RANGE - template_name = 'conference/conference_by.html' + template_name = 'client/conference/conference_by.html' title1 = '' title2 = '' @@ -437,6 +437,30 @@ class ConferenceList(MetadataMixin, JitterCacheMixin, ListView): return context +class ConferencePhotoView(MetadataMixin, ListView): + template_name = 'client/conference/photo.html' + obj = None + paginate_by = settings.CLIENT_PAGINATION + + def get_queryset(self): + slug = self.kwargs.get('slug') + conf = get_object_or_404(Conference, url=slug) + self.obj = conf + if conf.photogallery: + return conf.photogallery.photos.all() + else: + raise Http404() + + def get_context_data(self, **kwargs): + context = super(ConferencePhotoView, self).get_context_data(**kwargs) + obj = self.obj + context['object'] = obj + context['city'] = str(obj.city_id) + context['country'] = str(obj.country_id) + context['themes'] = [str(item.id) for item in obj.theme.all()] + return context + + def conference_add_calendar(request, id): args = {'success': False} user = request.user diff --git a/core/utils.py b/core/utils.py index b3f04ee6..7dd2b4af 100644 --- a/core/utils.py +++ b/core/utils.py @@ -100,7 +100,6 @@ def queryset_to_workbook(queryset, columns, report_date = None): sheet_name = u'My calendar {0}'.format(report_date.strftime('%Y-%B')) sheet = workbook.add_sheet(sheet_name) - # drawing head part with image sheet.write_merge(0, 6, 0, 6, main_header.format( month = month_name,year = report_date.strftime("%Y")), main_style) diff --git a/country/management/__init__.py b/country/management/__init__.py deleted file mode 100644 index 13ef41a7..00000000 --- a/country/management/__init__.py +++ /dev/null @@ -1 +0,0 @@ -__author__ = 'kotzilla' diff --git a/country/management/commands/__init__.py b/country/management/commands/__init__.py deleted file mode 100644 index 13ef41a7..00000000 --- a/country/management/commands/__init__.py +++ /dev/null @@ -1 +0,0 @@ -__author__ = 'kotzilla' diff --git a/country/management/commands/country_coordinates.py b/country/management/commands/country_coordinates.py deleted file mode 100644 index abe3a38d..00000000 --- a/country/management/commands/country_coordinates.py +++ /dev/null @@ -1,25 +0,0 @@ -# -*- coding: utf-8 -*- -import MySQLdb -from MySQLdb.cursors import DictCursor -from django.core.management.base import BaseCommand, CommandError -from country.models import Country - - -class Command(BaseCommand): - def handle(self, *args, **options): - # local database(will not work on production) - db = MySQLdb.connect(host="localhost", - user="root", - passwd="qazedc", - db="test", - charset='utf8', - cursorclass=DictCursor) - cursor = db.cursor() - # !!!database can change - sql = "SELECT country_code as code, geo_lat as latitude, geo_lng as longitude FROM test.country_country LEFT JOIN localization.meta_location ON test.country_country.country_code=localization.meta_location.iso COLLATE utf8_unicode_ci WHERE localization.meta_location.type='CO' AND geo_lat IS NOT NULL;" - cursor.execute(sql) - result = cursor.fetchall() - for item in result: - updates = Country.objects.filter(country_code=item['code']).update(latitude=item['latitude'], longitude=item['longitude']) - if updates: - print(item['code']) \ No newline at end of file diff --git a/country/management/commands/country_update_from_old.py b/country/management/commands/country_update_from_old.py deleted file mode 100644 index 5c70e1f9..00000000 --- a/country/management/commands/country_update_from_old.py +++ /dev/null @@ -1,39 +0,0 @@ -# -*- coding: utf-8 -*- -import MySQLdb -from MySQLdb.cursors import DictCursor -from django.core.management.base import BaseCommand, CommandError -from django.utils import translation -from country.models import Country - - -def get_from_old(country): - db = MySQLdb.connect(host="localhost", - user="kotzilla", - passwd="qazedc", - db="test2", - charset='utf8', - cursorclass=DictCursor) - cursor = db.cursor() - sql = """SELECT url, inflect FROM old_expomap.products_places WHERE title="%(name)s" """%{'name': country.name.encode('utf-8')} - #print(country.name.encode('utf-8')) -# print(sql) - cursor.execute(sql) - result = cursor.fetchone() - - return result - - -class Command(BaseCommand): - def handle(self, *args, **options): - translation.activate('ru') - for country in Country.objects.all(): - old_data = get_from_old(country) - if old_data is None: - continue - country.old_url = old_data['url'] - country.inflect = old_data['inflect'] - try: - country.save() - print(country) - except: - continue \ No newline at end of file diff --git a/country/manager.py b/country/manager.py index 1d4b278e..672ca2a2 100644 --- a/country/manager.py +++ b/country/manager.py @@ -1,19 +1,12 @@ import datetime from django.utils import translation from django.core.cache import cache -from django.utils.translation import get_language as lang from hvad.models import TranslationManager class CountryManager(TranslationManager): cache_time = 600 - ''' - 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: diff --git a/country/models.py b/country/models.py index 36bb5a99..d4125c12 100644 --- a/country/models.py +++ b/country/models.py @@ -1,34 +1,36 @@ # -*- coding: utf-8 -*- from datetime import date from django.db import models +from django.utils import translation +from django.utils.translation import ugettext_lazy as _ from django.contrib.contenttypes import generic from django.db.models.signals import post_save, pre_save from hvad.models import TranslatableModel, TranslatedFields from bitfield import BitField from manager import CountryManager, AreaManager -# models from directories.models import Language, Currency from city.models import City -from service.models import Service from exposition.models import Exposition from place_exposition.models import PlaceExposition -from organiser.models import Organiser from conference.models import Conference from seminar.models import Seminar from webinar.models import Webinar -# func -from functions.db import db_table_exists from functions.signal_handlers import post_save_handler, pre_save_handler -from django.utils import translation +from service.models import Service +from functions.db import db_table_exists # check if table exist and create flags if true -flags = [str(item.url) for item in Service.objects.all()] if db_table_exists('service_service') else [] +#flags = [str(item.url) for item in Service.objects.all()] if db_table_exists('service_service') else [] +flags = ['catalog', 'translator', 'participation', 'remote', 'tickets', 'visit', 'buildstand'] class Area(TranslatableModel): + """ + Store information about geographical zones + """ translations = TranslatedFields( - name = models.CharField(max_length=255), + name=models.CharField(verbose_name=_(u'Название'), max_length=255), ) objects = AreaManager() @@ -39,23 +41,40 @@ class Area(TranslatableModel): return self.lazy_translation_getter('name', unicode(self.pk)) def countries(self): + """ + returns countries of current area + """ lang = translation.get_language() return Country.objects.select_related('exposition_country')\ - .filter(exposition_country__country__isnull=False, translations__language_code=lang, area=self).distinct().order_by('translations__name') + .filter(exposition_country__country__isnull=False, translations__language_code=lang, area=self)\ + .distinct().order_by('translations__name') def expos(self): + """ + return expos that occur in current area + """ countries = self.countries() return Exposition.objects.filter(country__in=countries) def get_sub_categories(self): - objects = [{'text':item.name, 'id':item.id, 'name':'co', 'sub':True} for item in self.countries()] + """ + returns list with countries data that connected to current area + uses in search + """ + objects = [{'text': item.name, 'id': item.id, 'name': 'co', 'sub': True} for item in self.countries()] return objects def get_parent(self): - parent = {} - return parent + """ + returns empty dict, cause area has no parents + uses in search + """ + return {} def get_index_text(self): + """ + returns string of names in all languages for indexing it in search engine + """ translation.activate('ru') translations = self.translations.all() names = ' '.join([tr.name for tr in translations]) @@ -64,51 +83,46 @@ class Area(TranslatableModel): class Country(TranslatableModel): """ - Create Country model - - Uses hvad.TranslatableModel which is child of django.db.models class - + Stores information about countries + area- parent, city - child in search """ objects = CountryManager() catalog = '/country/' services = BitField(flags=flags) - url = models.SlugField(unique=True) - old_url = models.CharField(unique=True, max_length=55) - inflect = models.CharField(max_length=255, blank=True) - # relations - area = models.ForeignKey(Area) - big_cities = models.ManyToManyField(City, blank=True, null=True, related_name='cities') - capital = models.ForeignKey(City,blank=True, null=True, on_delete=models.PROTECT, related_name='capital') + url = models.SlugField(verbose_name=_(u'Url'), unique=True) + old_url = models.CharField(verbose_name=_(u'Старый урл'), unique=True, max_length=55) + # inflect name for russian language. example- в Росии + inflect = models.CharField(verbose_name=_(u'Склонение'), max_length=255, blank=True) + area = models.ForeignKey(Area, verbose_name=_(u'Географическая зона')) + logo = models.ImageField(verbose_name='Logo', upload_to='country/logo/', blank=True, max_length=255) + big_cities = models.ManyToManyField(City, verbose_name=_(u'Большые города'), blank=True, null=True, related_name='cities') + capital = models.ForeignKey(City, verbose_name=_(u'Столица'), blank=True, null=True, on_delete=models.PROTECT, related_name='capital') language = models.ManyToManyField(Language, blank=True, null=True) - currency = models.ManyToManyField(Currency, blank=True, null=True) - - population = models.PositiveIntegerField(blank=True, null=True) - teritory = models.PositiveIntegerField(blank=True, null=True) - timezone = models.FloatField(blank=True, null=True) - phone_code = models.PositiveIntegerField(blank=True, null=True) + currency = models.ManyToManyField(Currency, verbose_name=_(u'Валюта'), blank=True, null=True) + population = models.PositiveIntegerField(verbose_name=_(u'Население'), blank=True, null=True) + teritory = models.PositiveIntegerField(verbose_name=_(u'Територия'), blank=True, null=True) + timezone = models.FloatField(verbose_name=_(u'Часовой пояс'), blank=True, null=True) + phone_code = models.PositiveIntegerField(verbose_name=_(u'Тел. Код страны'), blank=True, null=True) time_delivery = models.PositiveSmallIntegerField(blank=True, null=True) - latitude = models.FloatField(blank=True, null=True) - longitude = models.FloatField(blank=True, null=True) + latitude = models.FloatField(verbose_name=_(u'Широта'), blank=True, null=True) + longitude = models.FloatField(verbose_name=_(u'Долгота'), blank=True, null=True) created = models.DateTimeField(auto_now_add=True) modified = models.DateTimeField(auto_now=True) - country_code = models.CharField(max_length=2) + country_code = models.CharField(verbose_name=_(u'Код страны(Alpha2)'), max_length=2) # connection with FileModel by ContentType files = generic.GenericRelation('file.FileModel',content_type_field='content_type', object_id_field='object_id') - #translated fields translations = TranslatedFields( - name = models.CharField(max_length=255), - description = models.TextField(blank=True), - transport = models.TextField(blank=True), - #------visa inf - rules = models.TextField(blank=True), - documents = models.TextField(blank=True),#pdf? - consulate = models.TextField(blank=True), + name=models.CharField(max_length=255), + description=models.TextField(blank=True), + transport=models.TextField(blank=True), + rules=models.TextField(blank=True), + documents=models.TextField(blank=True), + consulate=models.TextField(blank=True), #-----meta data - title = models.CharField(max_length=255), - descriptions = models.CharField(max_length=255), - keywords = models.CharField(max_length=255), + title=models.CharField(max_length=255), + descriptions=models.CharField(max_length=255), + keywords=models.CharField(max_length=255), ) - logo = models.ImageField(verbose_name='Logo', upload_to='country/logo/', blank=True, max_length=255) class Meta: ordering = ['translations__name'] @@ -117,63 +131,52 @@ class Country(TranslatableModel): return self.lazy_translation_getter('name', unicode(self.pk)) def get_events(self): + """ + returns nearest expos in this country + """ now = date.today() return Exposition.objects.filter(data_begin__gte=now, country=self).order_by('data_begin')[:3] def get_places(self): return PlaceExposition.objects.filter(country=self)[:3] - def get_organisers(self): - return Organiser.objects.filter(country=self) - def get_permanent_url(self): return self.catalog+self.url - def events_catalog(self): - return Exposition.catalog+'country-%s'%self.url - - def places_catalog(self): - return PlaceExposition.catalog+'country-%s'%self.url - def expositions_number(self): - - return len(Exposition.objects.filter(country=self.id)) + return Exposition.objects.filter(country=self).count() def conferences_number(self): - - return Conference.objects.filter(country=self.id).count() + return Conference.objects.filter(country=self).count() def seminars_number(self): - - return Seminar.objects.filter(country=self.id).count() + return Seminar.objects.filter(country=self).count() def webinars_number(self): - - return Webinar.objects.filter(country=self.id).count() + return Webinar.objects.filter(country=self).count() def active_cities(self): result = list(set(City.used.active_qs().filter(country=self))) - result.sort(key=lambda x:x.name) + result.sort(key=lambda x: x.name) return result - lang = translation.get_language() - #return City.objects.select_related('exposition_city')\ - # .filter(exposition_city__city__isnull=False, translations__language_code=lang, country=self).distinct().order_by('translations__name') def get_sub_categories(self): - objects = [{'text':item.name, 'id':item.id, 'name':'ci', 'sub': False} for item in self.active_cities()] + objects = [{'text': item.name, 'id': item.id, 'name': 'ci', 'sub': False} for item in self.active_cities()] return objects def get_parent(self): - parent = {'text' : self.area.name, 'id': self.area.id, 'name': 'area'} + parent = {'text': self.area.name, 'id': self.area.id, 'name': 'area'} return parent def get_index_text(self): + """ + returns string of names in all languages for indexing it in search engine + """ translation.activate('ru') translations = self.translations.all() names = ' '.join([tr.name for tr in translations]) return names - pre_save.connect(pre_save_handler, sender=Country) post_save.connect(post_save_handler, sender=Country) \ No newline at end of file diff --git a/country/signals.py b/country/signals.py deleted file mode 100644 index 40a96afc..00000000 --- a/country/signals.py +++ /dev/null @@ -1 +0,0 @@ -# -*- coding: utf-8 -*- diff --git a/country/tests.py b/country/tests.py deleted file mode 100644 index 501deb77..00000000 --- a/country/tests.py +++ /dev/null @@ -1,16 +0,0 @@ -""" -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) diff --git a/country/urls.py b/country/urls.py index 3d53c33d..52e6ca2d 100644 --- a/country/urls.py +++ b/country/urls.py @@ -4,5 +4,6 @@ from views import CountryView urlpatterns = patterns('', + # does not uses yet url(r'(?P.*)', CountryView.as_view()), ) diff --git a/country/views.py b/country/views.py index 01300306..a92fe892 100644 --- a/country/views.py +++ b/country/views.py @@ -3,6 +3,9 @@ from models import Country class CountryView(DetailView): + """ + this view is not used yet + """ model = Country slug_field = 'url' - template_name = 'country/country.html' \ No newline at end of file + template_name = 'client/country/country.html' \ No newline at end of file diff --git a/directories/management/commands/fill_currencies.py b/directories/management/commands/fill_currencies.py deleted file mode 100644 index 6122cee9..00000000 --- a/directories/management/commands/fill_currencies.py +++ /dev/null @@ -1,36 +0,0 @@ -# -*- coding: utf-8 -*- -import MySQLdb -from MySQLdb.cursors import DictCursor -from django.core.management.base import BaseCommand, CommandError -from directories.models import Currency - - -class Command(BaseCommand): - def handle(self, *args, **options): - # local database(will not work on production) - db = MySQLdb.connect(host="localhost", - user="root", - passwd="qazedc", - db="test", - charset='utf8', - cursorclass=DictCursor) - cursor = db.cursor() - # !!!database can change - sql = "SELECT code, name FROM localization.currencies;" - cursor.execute(sql) - result = cursor.fetchall() - for item in result: - try: - currency = Currency.objects.get(code=item['code']) - print('currency with code %s already exist'%currency.code) - continue - except Currency.DoesNotExist: - currency = Currency(code=item['code']) - - currency.translate('ru') - currency.name = item['name'] - currency.save() - currency.translate('en') - currency.name = item['name'] - currency.save() - print(currency.code) \ No newline at end of file diff --git a/directories/models.py b/directories/models.py index 74b0d266..87d0a73d 100644 --- a/directories/models.py +++ b/directories/models.py @@ -5,7 +5,7 @@ from hvad.models import TranslatableModel, TranslatedFields, TranslationManager class Language(TranslatableModel): """ - Creates Language model + stores information about languages used in Country model """ language = models.CharField(max_length=255)# native language name code = models.CharField(max_length=2) @@ -19,7 +19,7 @@ class Language(TranslatableModel): class Currency(TranslatableModel): """ - Creates Currency model + stores information about curencies used in Country model """ code = models.CharField(max_length=3) @@ -32,11 +32,10 @@ class Currency(TranslatableModel): class Iata (models.Model): """ - Creates Iata model + stores information about iata codes used in City model """ airport = models.CharField(max_length=255) code = models.CharField(max_length=4) def __unicode__(self): - return self.code - + return self.code \ No newline at end of file diff --git a/django_messages/expomap_views.py b/django_messages/expomap_views.py index 3f8f7736..eed66462 100644 --- a/django_messages/expomap_views.py +++ b/django_messages/expomap_views.py @@ -1,18 +1,20 @@ # -*- coding: utf-8 -*- +import json from django.http import HttpResponseRedirect, HttpResponse -from django.shortcuts import render_to_response, get_object_or_404 -from django.views.generic import ListView, DetailView, TemplateView, FormView -from accounts.models import User - +from django.shortcuts import get_object_or_404 +from django.views.generic import TemplateView, FormView from django.db.models import Q from django.utils import timezone -from forms import ComposeForm, ReplyForm, SendForm +from accounts.models import User +from forms import ReplyForm, SendForm from models import Message -import json class InboxView(TemplateView): - template_name = 'accounts/messages.html' + """ + returns template with user messages + """ + template_name = 'client/accounts/messages.html' def get_context_data(self, **kwargs): context = super(InboxView, self).get_context_data(**kwargs) @@ -20,51 +22,18 @@ class InboxView(TemplateView): context['senders'] = [{'sender': s, 'message': Message.objects.filter(recipient=self.request.user, sender=s)[0]}\ for s in senders] reply_form = ReplyForm() - context['reply_form'] = reply_form return context -def message_reply(request, message_id): - response = {'success': False} - if request.POST: - - form = ReplyForm(request.POST) - if form.is_valid(): - parent_msg =get_object_or_404(Message, id=message_id)# Message.objects.get(id=parent) - form.save(sender=request.user, parent_msg=parent_msg) - response['success'] = True - return HttpResponse(json.dumps(response), content_type='application/json') - - else: - return HttpResponse('error') - return HttpResponse('not ajax') - - -def send_message(request, url): - response = {'success': False} - try: - url = int(url) - recipient = get_object_or_404(User, id=url) - except ValueError: - - recipient = get_object_or_404(User, url=url) - if request.POST: - form = SendForm(request.POST) - if form.is_valid(): - form.save(sender=request.user, recipient=recipient) - response['success'] = True - return HttpResponse(json.dumps(response), content_type='application/json') - - else: - return HttpResponse('error') - return HttpResponse('not ajax') class MessageHistory(FormView): - template_name = 'accounts/messages_history.html' + """ + returns message history with one user and form to reply to it + """ + template_name = 'client/accounts/messages_history.html' form_class = ReplyForm success_url = '' - def get_initial(self): return {'recipient':self.kwargs.get('user_id')} @@ -84,13 +53,13 @@ class MessageHistory(FormView): def form_invalid(self, form): user_id = self.kwargs.get('user_id') return HttpResponseRedirect('/profile/messages/history/'+user_id+'/') + def form_valid(self, form): form.save(sender=self.request.user) user_id = self.kwargs.get('user_id') return HttpResponseRedirect('/profile/messages/history/'+user_id+'/') - """ class ReplyView(FormView): form_class = ComposeForm @@ -108,3 +77,42 @@ class ReplyView(FormView): context['parent_msg'] = parent_msg return context """ + + +def message_reply(request, message_id): + """ + reply to message + """ + response = {'success': False} + if request.POST: + form = ReplyForm(request.POST) + if form.is_valid(): + parent_msg = get_object_or_404(Message, id=message_id) + form.save(sender=request.user, parent_msg=parent_msg) + response['success'] = True + return HttpResponse(json.dumps(response), content_type='application/json') + else: + return HttpResponse('error') + return HttpResponse('not ajax') + + +def send_message(request, url): + """ + send message to user with url=url + """ + response = {'success': False} + try: + url = int(url) + recipient = get_object_or_404(User, id=url) + except ValueError: + + recipient = get_object_or_404(User, url=url) + if request.POST: + form = SendForm(request.POST) + if form.is_valid(): + form.save(sender=request.user, recipient=recipient) + response['success'] = True + return HttpResponse(json.dumps(response), content_type='application/json') + else: + return HttpResponse('error') + return HttpResponse('not ajax') \ No newline at end of file diff --git a/expobanner/views.py b/expobanner/views.py index 3d6df21c..a9517d05 100644 --- a/expobanner/views.py +++ b/expobanner/views.py @@ -27,7 +27,10 @@ def get_banners(request): good_urls = [] for u in urls: if u.regex: - url_re = re.compile(u.url) + try: + url_re = re.compile(u.url) + except: + continue if url_re.findall(url): good_urls.append(u) elif url == u.url: diff --git a/exposition/admin.py b/exposition/admin.py index 0345864a..19b3d7f2 100644 --- a/exposition/admin.py +++ b/exposition/admin.py @@ -243,22 +243,8 @@ class ExpositionView(AdminView): template_name = 'admin/exposition/exposition.html' def form_valid(self, form): - #StatisticFormSet = formset_factory(StatisticForm) - #formset_statistic = StatisticFormSet(self.request.POST) self.set_obj() expo = form.save(obj=self.obj) - """ - # delete old halls - Statistic.objects.filter(exposition=getattr(expo, '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 = expo - statistic.save() - """ - return HttpResponseRedirect(self.success_url) def get_form(self, form_class): @@ -321,35 +307,22 @@ class ExpositionView(AdminView): data['keywords_%s' % code] = trans_obj.keywords data['descriptions_%s' % code] = trans_obj.descriptions - form =form_class(initial=data) + form = form_class(initial=data) form.fields['city'].widget.attrs['data-init-text'] = obj.city.name form.fields['tag'].choices = [(item.id, item.name) for item in Tag.objects.language().filter(theme__in=data['theme'])] return form else: return form_class() - def get_context_data(self, **kwargs): context = super(ExpositionView, self).get_context_data(**kwargs) obj = self.set_obj() if obj: - #StatisticFormSet = modelformset_factory(Statistic, form=StatisticForm, exclude=('exposition',)) - # get existing statistic - #statistic = Statistic.objects.filter(exposition=getattr(obj, 'id')) - # fill HallFormSet - #formset_statistic = StatisticFormSet(queryset=statistic) context['stat_form'] = StatisticForm() context['file_form'] = FileForm(initial={'model': 'exposition.Exposition'}) files = FileModel.objects.filter(content_type=ContentType.objects.get_for_model(obj),object_id=getattr(obj, 'id')) context['files'] = files - else: - #StatisticFormSet = formset_factory(StatisticForm) - #formset_statistic = StatisticFormSet() - pass - - #context['formset_statistic'] = formset_statistic - context['photo_form'] = PhotoForm() context['timetable_form'] = TimeTableForm() context['timetables'] = TimeTable.objects.filter(exposition=obj) @@ -387,23 +360,6 @@ def search_expo(request): return HttpResponse(json.dumps(result), content_type='application/json') -from django.views.generic import FormView -from forms import PaidForm -class PaidView(FormView): - form_class = PaidForm - success_url = '/admin/exposition/all/' - template_name = 'admin/exposition/paid.html' - - def form_valid(self, form): - expo = Exposition.objects.get(url=self.kwargs.get('url')) - paid = form.save(commit=False) - paid.expo = expo - paid.save() - - return HttpResponseRedirect(self.success_url) - - - def expo_copy(request): response = {'redirect': ''} expo = Exposition.objects.get(id=request.GET['id']) diff --git a/exposition/admin_urls.py b/exposition/admin_urls.py index 7b521cb3..9adda27b 100644 --- a/exposition/admin_urls.py +++ b/exposition/admin_urls.py @@ -1,11 +1,10 @@ # -*- coding: utf-8 -*- from django.conf.urls import patterns, include, url -from admin import ExpositionListView, ExpositionView, PaidView +from admin import ExpositionListView, ExpositionView urlpatterns = patterns('exposition.admin', url(r'^upload-photo/(?P.*)/$', 'upload_exposition_photo'), url(r'^copy/$', 'expo_copy'), - url(r'^(?P.*)/paid/$', PaidView.as_view()), #url(r'^add.*/$', 'exposition_add'), url(r'^delete/(?P.*)/$', 'exposition_delete'), diff --git a/exposition/forms.py b/exposition/forms.py index 8b431736..d93d0da2 100644 --- a/exposition/forms.py +++ b/exposition/forms.py @@ -32,10 +32,9 @@ class ExpositionCreateForm(forms.Form): save function saves data in Exposition object. If it doesnt exist create new object """ - 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 года')) + 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 года'), (0.2, u'Раз в 5 лет')) public = [(item1, item2) for item1, item2 in BIT_AUDIENCE] currencies = [(item, item) for item in CURRENCY] @@ -615,12 +614,4 @@ class ExpositionFilterForm(AdminFilterForm): if month: qs = qs.filter(data_begin__month=month) - return qs - -from exposition.models import Paid - -class PaidForm(forms.ModelForm): - class Meta: - model = Paid - exclude = ('expo',) - + return qs \ No newline at end of file diff --git a/exposition/management/commands/exposition_en.py b/exposition/management/commands/exposition_en.py index a0ae9d69..67addd68 100644 --- a/exposition/management/commands/exposition_en.py +++ b/exposition/management/commands/exposition_en.py @@ -4,7 +4,7 @@ from city.models import City from country.models import Country from place_exposition.models import PlaceExposition import xlrd, xlwt -from import_xls.excel_settings import import_settings, place_exp_sett +from import_xls.excel_settings import place_exp_sett from django.conf import settings diff --git a/exposition/models.py b/exposition/models.py index 0ba5874a..2b98d837 100644 --- a/exposition/models.py +++ b/exposition/models.py @@ -17,8 +17,7 @@ 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, ExpoMixin -from functions.translate import fill_with_signal -from photologue.models import Gallery + from import_xls.model_utils import ExpoImportManager from functions.models_methods import hvad_to_dict @@ -37,7 +36,8 @@ BIT_AUDIENCE = settings.BIT_AUDIENCE CURRENCY = settings.CURRENCY # check if table exist and create flags if true -flags = [item.url for item in Service.objects.all()] if db_table_exists('service_service') else [] +#flags = [item.url for item in Service.objects.all()] if db_table_exists('service_service') else [] +flags = ['catalog', 'translator', 'participation', 'remote', 'tickets', 'visit', 'buildstand'] class Exposition(TranslatableModel, EventMixin, ExpoMixin): @@ -79,7 +79,7 @@ class Exposition(TranslatableModel, EventMixin, ExpoMixin): blank=True, null=True, related_name='exposition_companies') users = models.ManyToManyField('accounts.User', verbose_name='Посетители выставки', blank=True, null=True, related_name='exposition_users') - photogallery = models.ForeignKey('photologue.Gallery', blank=True, null=True) + photogallery = models.ForeignKey('photologue.Gallery', blank=True, null=True, on_delete=models.SET_NULL) logo = models.ImageField(verbose_name='Logo', upload_to='exposition/logo/', blank=True) rating = models.IntegerField(default=0) # добавить индекс в базе @@ -208,48 +208,13 @@ class Exposition(TranslatableModel, EventMixin, ExpoMixin): return '' def upload_photo_url(self): - return '/admin/exposition/upload-photo/%s/'%self.id - - def get_gallery(self): - if self.photogallery: - return self.photogallery - - data = {} - model = type(self) - for code, name in settings.LANGUAGES: - obj = model._meta.translations_model.objects.get(language_code = code,master__id=self.id) #access to translated fields - data['title_%s'%code] = obj.name - data['description_%s'%code] = obj.description - - gallery = Gallery() - - fill_with_signal(Gallery, gallery, data) - self.photogallery = gallery - self.save() - - - return gallery + return '/admin/exposition/upload-photo/%s/' % self.id def tags(self): return self.tag.language().all() def statistic_exists(self): - return Statistic.objects,filter(exposition=self).exists() - - - def upload_photo(self, photo ,gallery=None): - """ - uploading photo to gallery - """ - if gallery is None: - gallery = self.get_gallery() - - gallery.photos.add(photo) - - -# def get_index_text(self): -# names = [tr.name for tr in self.translations.all()] -# return names + return Statistic.objects.filter(exposition=self).exists() def get_audience(self): checked = [item for item, bool in self.audience if bool==True] @@ -261,11 +226,10 @@ class Exposition(TranslatableModel, EventMixin, ExpoMixin): 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 года')} + 0.33: _(u'Раз в 3 года'), 0.25: _(u'Раз в 4 года'), 0.2: _(u'Раз в 5 лет')} return periodic.get(self.periodic) def get_nearest_events(self): @@ -280,8 +244,6 @@ class Exposition(TranslatableModel, EventMixin, ExpoMixin): def get_catalog_url(self): return self.catalog - #return '/expositions/' - def get_event_type(self): return _(u'Выставки') @@ -344,7 +306,7 @@ class TimeTable(TranslatableModel): TimeTable for business program """ - exposition = models.ForeignKey(Exposition, related_name='business_program') + exposition = models.ForeignKey(Exposition, related_name='TimeTable') begin = models.DateTimeField(verbose_name='Начало') end = models.DateTimeField(verbose_name='Конец') timetable_organiser = models.ForeignKey(Organiser, null=True, blank=True) @@ -386,14 +348,6 @@ def logo_name(instance, filename): url = instance.expo.url return '/'.join(['exposition', url, url+'_org_logo.jpg']) -class Paid(models.Model): - expo = models.OneToOneField(Exposition) - org_logo = models.ImageField(upload_to=logo_name, blank=True, max_length=255) - oficial_link = models.ForeignKey('banners.Redirect', null=True, blank=True, related_name='expo_oficial') - participation_link = models.ForeignKey('banners.Redirect', null=True, blank=True, related_name='expo_participation') - tickets_link = models.ForeignKey('banners.Redirect', null=True, blank=True, related_name='expo_tickets') - organiser = models.EmailField(blank=True) - pre_save.connect(pre_save_handler, sender=Exposition) post_save.connect(post_save_handler, sender=Exposition) diff --git a/exposition/urls.py b/exposition/urls.py index 5290ea71..e61f77d4 100644 --- a/exposition/urls.py +++ b/exposition/urls.py @@ -1,10 +1,8 @@ # -*- coding: utf-8 -*- from django.conf.urls import patterns, include, url -from views import ExpositionStatistic, ExpositionPrice,\ - ExpositionProgramme, ExpositionSearchView, ExpositionByCountry, ExpositionByTheme, ExpositionByCity, ExpositionByTag +from views import ExpositionStatistic, ExpositionPrice, ExpositionProgramme, ExpositionSearchView, \ + ExpositionByCountry, ExpositionByTheme, ExpositionByCity, ExpositionByTag, ExpoPhotoView - -from django.views.decorators.cache import cache_page from views import ExpositionServiceView from views import ExpoCountryCatalog, ExpoCityCatalog, ExpoThemeCatalog, ExpoTagCatalog, ExpoList, ExpoDetail,\ ExpoVisitors, ExpoMembers, ExpositionThankView @@ -69,6 +67,8 @@ urlpatterns = patterns('', url(r'^expo/(?P.*)/program/$', ExpositionProgramme.as_view(), {'meta_id':62}), url(r'^expo/(?P.*)/visitors/page/(?P\d+)/$', ExpoVisitors.as_view(), {'meta_id':64}), url(r'^expo/(?P.*)/visitors/$', ExpoVisitors.as_view(), {'meta_id':64}), + url(r'^expo/(?P.*)/photo/page/(?P\d+)/$', ExpoPhotoView.as_view()), + url(r'^expo/(?P.*)/photo/$', ExpoPhotoView.as_view()), url(r'^expo/(?P.*)/members/page/(?P\d+)/$', ExpoMembers.as_view(), {'meta_id':63}), url(r'^expo/(?P.*)/members/$', ExpoMembers.as_view(), {'meta_id':63}), url(r'^expo/(?P.*)/service/thanks/', ExpositionThankView.as_view()), diff --git a/exposition/views.py b/exposition/views.py index b35e42a6..965d6147 100644 --- a/exposition/views.py +++ b/exposition/views.py @@ -548,6 +548,30 @@ class ExpoMembers(MetadataMixin, ListView): return context +class ExpoPhotoView(MetadataMixin, ListView): + template_name = 'client/exposition/photo.html' + obj = None + paginate_by = settings.CLIENT_PAGINATION + + def get_queryset(self): + slug = self.kwargs.get('slug') + expo = get_object_or_404(Exposition, url=slug) + self.obj = expo + if expo.photogallery: + return expo.photogallery.photos.all() + else: + raise Http404() + + def get_context_data(self, **kwargs): + context = super(ExpoPhotoView, self).get_context_data(**kwargs) + obj = self.obj + context['object'] = obj + context['city'] = str(obj.city_id) + context['country'] = str(obj.country_id) + context['themes'] = [str(item.id) for item in obj.theme.all()] + return context + + def add_note(request, slug): args = {'success': False} diff --git a/functions/admin_views.py b/functions/admin_views.py index d20b361d..8a8ce342 100644 --- a/functions/admin_views.py +++ b/functions/admin_views.py @@ -128,9 +128,9 @@ class AdminListView(FormView): def get_context_data(self, **kwargs): context = super(AdminListView, self).get_context_data(**kwargs) if issubclass(self.model, TranslatableModel): - qs = self.model.objects.language('all').all().order_by('name') + qs = self.model.objects.language().all().order_by('name') else: - qs = self.model.objects.all().order_by('name') + qs = self.model.objects.all().order_by('-modified') result = paginate_results(qs, page=self.request.GET.get('page')) context['object_list'] = result return context diff --git a/functions/model_mixin.py b/functions/model_mixin.py index 30b0a6de..a918c972 100644 --- a/functions/model_mixin.py +++ b/functions/model_mixin.py @@ -1,7 +1,10 @@ # -*- coding: utf-8 -*- import copy +from django.conf import settings +from functions.translate import fill_with_signal import calendar as python_calendar from service.models import Service +from photologue.models import Gallery class ExpoMixin(object): @@ -103,6 +106,36 @@ class EventMixin(object): return 0 + def upload_photo(self, photo, gallery=None): + """ + uploading photo to gallery + """ + if gallery is None: + gallery = self.get_gallery() + + gallery.photos.add(photo) + + def get_gallery(self): + if self.photogallery: + return self.photogallery + + data = {} + model = type(self) + for code, name in settings.LANGUAGES: + # access to translated fields + obj = model._meta.translations_model.objects.get(language_code=code, master__id=self.id) #access to translated fields + data['title_%s' % code] = obj.name + data['description_%s ' % code] = obj.description + + gallery = Gallery() + + fill_with_signal(Gallery, gallery, data) + self.photogallery = gallery + self.save() + + + return gallery + def copy(self, url): """ Copy event with new url diff --git a/functions/signal_handlers.py b/functions/signal_handlers.py index a0c3a07a..6c170a1e 100644 --- a/functions/signal_handlers.py +++ b/functions/signal_handlers.py @@ -1,5 +1,7 @@ +import random +import string +from django.db.models.fields.files import FieldFile from signal_additional_func import fill_missing_languages, fill_meta_information -import random, string from functions.form_check import translit_with_separator @@ -34,14 +36,14 @@ def post_save_handler(sender, **kwargs): fill_missing_languages(obj) fill_meta_information(obj) -''' -def post_save_translation_handler(sender, **kwargs): + +def file_cleanup(sender, instance, *args, **kwargs): """ - receiver function - take object and change url + Deletes the file(s) associated with a model instance. The model + is not saved after deletion of the file(s) since this is meant + to be used with the pre_delete signal. """ - obj = kwargs['instance'] - if obj.language_code == 'ru': - obj.master.url = translit_with_separator(obj.name) - obj.master.save() -''' \ No newline at end of file + for field_name, _ in instance.__dict__.iteritems(): + field = getattr(instance, field_name) + if issubclass(field.__class__, FieldFile) and field.name: + field.delete(save=False) \ No newline at end of file diff --git a/functions/views_help.py b/functions/views_help.py index 3d764778..35e36cad 100644 --- a/functions/views_help.py +++ b/functions/views_help.py @@ -1,5 +1,8 @@ # -*- coding: utf-8 -*- import re +import datetime +from django.shortcuts import get_object_or_404 +from accounts.models import User def get_referer(request, default=None): referer = request.META.get('HTTP_REFERER') @@ -20,4 +23,19 @@ def split_params(st): if n != -1: params.append({'type': item[:n], 'url':item[n+1:]}) - return params \ No newline at end of file + return params + +def dates_range(date1, date2): + delta = date2 - date1 + dates = [] + for i in range(delta.days + 1): + dates.append(date1 + datetime.timedelta(days=i)) + return dates + +def get_user(url): + try: + url = int(url) + user = get_object_or_404(User, id=url) + except ValueError: + user = get_object_or_404(User, url=url) + return user \ No newline at end of file diff --git a/import_xls/admin.py b/import_xls/admin.py index e1cff126..c0820c30 100644 --- a/import_xls/admin.py +++ b/import_xls/admin.py @@ -1,22 +1,17 @@ # -*- coding: utf-8 -*- -from django.core.context_processors import csrf from django.shortcuts import render_to_response from django.http import HttpResponseRedirect, HttpResponse -from django.contrib.auth.decorators import login_required -from django.db.models.loading import get_model -# -import xlwt -import xlrd -# -from import_forms import ImportEventForm, ImportThemeForm, ImportTagForm, ImportOrganiserForm,\ - ImportPlaceConferenceForm, ImportPlaceExpositionForm -from export_forms import ExportEventForm, ExportOrganiserForm, ExportThemeForm, ExportTagForm,\ - ExportUserForm, ExportCompanyForm, ExportPlaceConferenceForm, ExportPlaceExpositionForm, ExportBlogForm,\ - ExportCityForm from django.views.generic import FormView, ListView, DeleteView from django.conf import settings from django.contrib import messages from django.shortcuts import get_object_or_404 +from import_xls.models import Log +from import_forms import ImportEventForm, ImportThemeForm, ImportTagForm, \ + ImportPlaceConferenceForm, ImportPlaceExpositionForm +from export_forms import ExportEventForm, ExportThemeForm, ExportTagForm,\ + ExportUserForm, ExportCompanyForm, ExportPlaceConferenceForm, ExportPlaceExpositionForm, ExportBlogForm,\ + ExportCityForm + def xls_to_response(xls, fname): response = HttpResponse(mimetype="application/ms-excel") @@ -56,85 +51,93 @@ class ExportView(FormView): return HttpResponseRedirect(self.success_url) return xls_to_response(workbook, f_name) -class ExportOrganiser(ExportView): - form_class = ExportOrganiserForm - success_url = '/admin/export-organiser' class ExportTheme(ExportView): form_class = ExportThemeForm success_url = '/admin/export-theme' + class ExportTag(ExportView): form_class = ExportTagForm success_url = '/admin/export-tag' + class ExportUser(ExportView): form_class = ExportUserForm success_url = '/admin/export-user' + class ExportCompany(ExportView): form_class = ExportCompanyForm success_url = '/admin/export-company' + class ExportPlaceConference(ExportView): form_class = ExportPlaceConferenceForm success_url = '/admin/export-place_conference' + class ExportPlaceExposition(ExportView): form_class = ExportPlaceExpositionForm success_url = '/admin/export-place_exposition' + class ExportBlog(ExportView): form_class = ExportBlogForm success_url = '/admin/export-blog/' + class ExportBlog(ExportView): form_class = ExportBlogForm success_url = '/admin/export-blog/' + class ExportCity(ExportView): form_class = ExportCityForm success_url = '/admin/export-city/' - -from import_xls.models import Log class ImportEvent(FormView): form_class = ImportEventForm success_url = '/admin/import-event/' template_name = 'admin/import templates/import_event.html' + def form_valid(self, form): errors = form.save_file_debug() return HttpResponseRedirect('/admin/import/log/') - #messages.success(self.request, 'Success') - #context = self.get_context_data() - #context['import_errors'] = errors - #context['form'] = form - #return render_to_response(self.template_name, context) +class ImportPlaceExposition(FormView): + form_class = ImportPlaceExpositionForm + success_url = '/admin/import-place_exposition/' + template_name = 'admin/import templates/import.html' + + def form_valid(self, form): + errors = form.save_file_debug() + return HttpResponseRedirect(self.success_url) + +class ImportPlaceConference(ImportView): + form_class = ImportPlaceConferenceForm + success_url = '/admin/import-place_conference' + + def form_valid(self, form): + errors = form.save_file_debug() + return HttpResponseRedirect(self.success_url) class ImportTheme(ImportView): form_class = ImportThemeForm success_url = '/admin/import-theme' + class ImportTag(ImportView): form_class = ImportTagForm success_url = '/admin/import-tag' -class ImportOrganiser(ImportView): - form_class = ImportOrganiserForm - success_url = '/admin/import-organiser' -class ImportPlaceExposition(ImportView): - form_class = ImportPlaceExpositionForm - success_url = '/admin/import-place_exposition' -class ImportPlaceConference(ImportView): - form_class = ImportPlaceConferenceForm - success_url = '/admin/import-place_conference' + class ExportEvent(ExportView): form_class = ExportEventForm @@ -147,6 +150,7 @@ class LogList(ListView): paginate_by = settings.ADMIN_PAGINATION template_name = 'admin/import templates/log.html' + class LogDelete(DeleteView): model = Log success_url = '/admin/import/log/' @@ -162,11 +166,12 @@ def log_file(request, log_id): response['X-Accel-Redirect'] = log.log.url return response + def work_file(request, log_id): log = get_object_or_404(Log, id=log_id) response = HttpResponse() response['content-type'] = 'application/x-executable' - filename = 'import_%s_file.xls'%str(log.id) + filename = 'import_%s_file.xls' % str(log.id) response['content-disposition'] = 'attachment;filename=%s'%filename response['X-Accel-Redirect'] = log.work_file.url return response \ No newline at end of file diff --git a/import_xls/admin_urls.py b/import_xls/admin_urls.py index 0d7af157..1aae00e4 100644 --- a/import_xls/admin_urls.py +++ b/import_xls/admin_urls.py @@ -1,25 +1,21 @@ # -*- coding: utf-8 -*- from django.conf.urls import patterns, url - -from admin import ImportTheme, ImportEvent, ImportOrganiser, ImportTag, ImportPlaceExposition, ImportPlaceConference - -from admin import ExportTheme, ExportEvent, ExportOrganiser, ExportTag, ExportPlaceExposition,\ - ExportPlaceConference, ExportCompany, ExportUser, ExportBlog, ExportCity, LogList from import_xls.admin import LogDelete +from admin import ImportTheme, ImportEvent, ImportTag, ImportPlaceExposition, ImportPlaceConference +from admin import ExportTheme, ExportEvent, ExportTag, ExportPlaceExposition,\ + ExportPlaceConference, ExportCompany, ExportUser, ExportBlog, ExportCity, LogList urlpatterns = patterns('', url(r'^import-event/$', ImportEvent.as_view()), url(r'^import-theme/$', ImportTheme.as_view()), url(r'^import-tag/$', ImportTag.as_view()), - url(r'^import-organiser/$', ImportOrganiser.as_view()), url(r'^import-place_exposition/$', ImportPlaceExposition.as_view()), url(r'^import-place_conference/$', ImportPlaceConference.as_view()), # url(r'^export-event/$', ExportEvent.as_view()), url(r'^export-theme/$', ExportTheme.as_view()), url(r'^export-tag/$', ExportTag.as_view()), - url(r'^export-organiser/$', ExportOrganiser.as_view()), url(r'^export-place_exposition/$', ExportPlaceExposition.as_view()), url(r'^export-place_conference/$', ExportPlaceConference.as_view()), url(r'^export-user/$', ExportUser.as_view()), diff --git a/import_xls/excel_settings.py b/import_xls/excel_settings.py index 936c5913..770e1561 100644 --- a/import_xls/excel_settings.py +++ b/import_xls/excel_settings.py @@ -1,12 +1,22 @@ # -*- coding: utf-8 -*- +import urllib2 +from django.conf import settings +from django.contrib.contenttypes.models import ContentType +from django.core.validators import validate_email, URLValidator +from file.models import FileModel +from functions.files import get_alternative_filename +from place_exposition.models import EXPOSITION_TYPE +from place_exposition.models import Hall # bad practice of importing, but to many functions must be imported from .utils import * + def get_bool(value): if value: return 1 return '' + def get_int(value): if not value: return '' @@ -30,12 +40,14 @@ def get_tag(value): tag_names = [item['name'] for item in value.language('ru').all().values('name')] return ','.join(tag_names) + def get_place_type(value): for t in EXPOSITION_TYPE: if value == t[0]: return t[1] return t[0][1] + def get_periodic(value): if value: value = float(value) @@ -45,6 +57,7 @@ def get_periodic(value): return periodic.get(value, '') return '' + def get_quality(value, field): flags = {u'UFI': 'ufi', u'РСВЯ': 'rsva', u'EXPORATING': 'exporating'} v = flags.get(field) @@ -56,45 +69,6 @@ def get_quality(value, field): return '' - -place_settings=[ - {'name': 'id', 'verbose_name': u'id', 'type': get_int, 'width':1500}, - {'name': 'url', 'verbose_name': u'URL', 'type': unicode}, - {'name': 'name', 'verbose_name': u'Название', 'type': unicode}, - {'name': 'type', 'verbose_name': u'Тип', 'type': get_place_type},########## - {'name': 'main_title', 'verbose_name': u'Краткое описание', 'type': unicode}, - {'name': 'country', 'verbose_name': u'Страна', 'type': unicode}, - {'name': 'city', 'verbose_name': u'Город', 'type': unicode}, - {'name': 'address', 'verbose_name': u'Адресс', 'type': unicode}, - {'name': 'phone', 'verbose_name': u'Тел.', 'type': get_int}, - {'name': 'fax', 'verbose_name': u'Факс', 'type': get_int}, - {'name': 'web_page', 'verbose_name': u'Веб-сайт', 'type': unicode}, - {'name': 'email', 'verbose_name': u'Email', 'type': unicode}, - {'name': 'virtual_tour', 'verbose_name': u'Виртуальный тур', 'type': unicode}, - {'name': 'virtual_tour', 'verbose_name': u'Виртуальный тур', 'type': unicode}, - {'name': 'foundation_year', 'verbose_name': u'Год основания', 'type': get_int}, - {'name': 'event_in_year', 'verbose_name': u'Количество мероприятий в год', 'type': get_int}, - {'name': 'total_area', 'verbose_name': u'Общая выставочная площадь, кв. м.', 'type': get_int}, - {'name': 'closed_area', 'verbose_name': u'Закрытая выставочная площадь, кв. м.', 'type': get_int}, - {'name': 'open_area', 'verbose_name': u'Открытая выставочная площадь, кв. м.', 'type': get_int}, - {'name': 'total_pavilions', 'verbose_name': u'Количество павильонов', 'type': get_int}, - {'name': 'total_halls', 'verbose_name': u'Конференц-залы', 'type': get_int}, - {'name': 'bank', 'verbose_name': u'Банк/Банкоматы/Обмен валюты', 'type': get_bool}, - {'name': 'children_room', 'verbose_name': u'Детская комната', 'type': get_bool}, - {'name': 'disabled_service', 'verbose_name': u'Сервис для людей с ограниченными физическими возможностями', 'type': get_bool}, - {'name': 'conference_centre', 'verbose_name': u'Конгресс-центр', 'type': get_bool}, - {'name': 'business_centre', 'verbose_name': u'Бизнес-центр', 'type': get_bool}, - {'name': 'online_registration', 'verbose_name': u'On-line регистрация', 'type': get_bool}, - {'name': 'wifi', 'verbose_name': u'Wi-Fi', 'type': get_bool}, - {'name': 'cafe', 'verbose_name': u'Кафе и рестораны', 'type': get_bool}, - {'name': 'terminals', 'verbose_name': u'Информационные терминалы', 'type': get_bool}, - {'name': 'parking', 'verbose_name': u'Парковка', 'type': get_bool}, - {'name': 'press_centre', 'verbose_name': u'Пресс-центр', 'type': get_bool}, - {'name': 'mobile_application', 'verbose_name': u'Мобильное приложение', 'type': get_bool}, - -] - - def to_theme_type(st): if not st: return 15 @@ -105,37 +79,15 @@ def to_theme_type(st): return flag - - - -def to_currency(value): - if value=='USD': - return value - if value=='EUR': - return value - print(value) - return 'USD' - -def to_logo(url): - return None - -def to_photo(url): - return None - -def to_map(url): - return None - -from django.core.validators import validate_email, URLValidator - def to_url(url): validate = URLValidator() - try: validate(url) except: return '' return url + def to_email(email): try: validate_email(email) @@ -143,12 +95,6 @@ def to_email(email): return '' return email -from file.models import FileModel -import urllib2 -from django.conf import settings -from django.contrib.contenttypes.models import ContentType -from functions.files import get_alternative_filename - def save_file(obj, value, purpose): if not obj.id: @@ -178,42 +124,13 @@ def save_file(obj, value, purpose): file.save() -from file.models import Photo -def save_photo(obj, value): - if not obj.id: - return None - - urls = value.split(';') - - for url in urls: - - file_name = url.split('/')[-1] - alt_name = get_alternative_filename(settings.MEDIA_ROOT+'imgs/', file_name) - download_to = settings.MEDIA_ROOT+'photos/'+alt_name - try: - response = urllib2.urlopen(url, timeout=3) - except: - continue - - with open(download_to,'wb') as f: - f.write(response.read()) - f.close() - - - file_name ='photos/'+alt_name - content_type = ContentType.objects.get_for_model(obj) - photo = Photo(file_path=file_name, file_type='JPG', - content_type=content_type, object_id=obj.id) - photo.save() - - -from place_exposition.models import EXPOSITION_TYPE def to_type(value): for t in EXPOSITION_TYPE: if value == t[1]: return t[0] return 'Exposition complex' + def to_phone(value): if value: if isinstance(value, float) or isinstance(value, int): @@ -227,9 +144,6 @@ def to_phone(value): return value - - -from place_exposition.models import Hall def save_halls(obj, value): halls = value.split(';') res = [] @@ -266,51 +180,11 @@ def save_halls(obj, value): print('---------------------------------') - - - -place_exp_sett = { - u'ID':{u'field': u'id', u'func': to_int}, - u'Название ВЦ':{u'field': u'name', u'func': unicode}, - u'Тип':{u'field': u'type', u'func': to_type}, - u'Краткое описание':{u'field': u'main_title', u'func': unicode}, - u'Страна':{u'field': u'country', u'func': to_country}, - u'Город':{u'field': u'city_id', u'func': to_city, 'extra_values': 'country'}, - u'Описание':{u'field': u'description', u'func': unicode}, - u'Адрес':{u'field': u'adress', u'func': unicode}, - u'Тел.':{u'field': u'phone', u'func': to_phone}, - u'Факс':{u'field': u'fax', u'func': to_phone}, - u'Фото':{u'field': u'photo', u'func': save_photo, u'method': True}, - u'Лого':{u'field': u'logo', u'func': save_logo, u'method': True}, - u'Веб-сайт':{u'field': u'web_page', u'func': unicode}, - u'Email':{u'field': u'email', u'func': unicode}, - u'Карта проезда':{u'field': u'map', u'func': save_file, u'method': True, u'purpose': 'map'}, - u'Виртуальный тур':{u'field': u'virtual_tour', u'func': to_url}, - u'Год основания':{u'field': u'foundation_year', u'func': to_int}, - u'Валюта':{u'field': u'currency', u'func': to_currency}, - u'Количество мероприятий в год':{u'field': u'event_in_year', u'func': to_int}, - u'Общая выставочная площадь, кв. м.':{u'field': u'total_area', u'func': to_int}, - u'Закрытая выставочная площадь, кв. м.':{u'field': u'closed_area', u'func': to_int}, - u'Открытая выставочная площадь, кв. м.':{u'field': u'open_area', u'func': to_int}, - u'Количество павильонов':{u'field': u'total_pavilions', u'func': to_int}, - u'Площадь павильона':{u'field': u'halls', u'func': save_halls, u'method': True}, - u'Конференц-залы':{u'field': u'total_halls', u'func': to_int}, - u'Схема территории':{u'field': u'scheme', u'func': save_file, u'method': True, u'purpose': 'scheme teritory'},#сделать - u'Банк/Банкоматы/Обмен валюты':{u'field': u'bank', u'func': bool}, - u'Детская комната':{u'field': u'children_room', u'func': bool}, - u'Сервис для людей с ограниченными физическими возможностями':{u'field': u'disabled_service', u'func': bool}, - u'Конгресс-центр':{u'field': u'conference_centre', u'func': bool}, - u'Бизнес-центр':{u'field': u'business_centre', u'func': bool}, - u'On-line регистрация':{u'field': u'online_registration', u'func': bool}, - u'Wi-Fi':{u'field': u'wifi', u'func': bool}, - u'Кафе и рестораны':{u'field': u'cafe', u'func': bool}, - u'Информационные терминалы':{u'field': u'terminals', u'func': bool}, - u'Парковка':{u'field': u'parking', u'func': bool}, - u'Пресс-центр':{u'field': u'press_centre', u'func': bool}, - u'Мобильное приложение':{u'field': u'mobile_application', u'func': bool}, -} - - +def get_date(value): + try: + return value.strftime('%d.%m.%Y') + except AttributeError: + return '' article_sett = { @@ -321,66 +195,7 @@ article_sett = { u'Создана':{u'field': u'created', u'func': to_datetime} } -def get_date(value): - try: - return value.strftime('%d.%m.%Y') - except AttributeError: - return '' - - -event_export_sett = [ - {'name': 'id', 'verbose_name': u'ID', 'type': get_int, 'width':1500}, - {'name': 'url', 'verbose_name': u'Url', 'type': unicode}, - {'name': 'name', 'verbose_name': u'Название', 'type': unicode}, - {'name': 'main_title', 'verbose_name': u'Краткое описание', 'type': unicode}, - {'name': 'data_begin', 'verbose_name': u'Дата начала:(YYYY-MM-DD)', 'type': get_date}, - {'name': 'data_end', 'verbose_name': u'Дата окончания:(YYYY-MM-DD)', 'type': get_date}, - {'name': 'country', 'verbose_name': u'Страна', 'type': unicode}, - {'name': 'city', 'verbose_name': u'Город', 'type': unicode}, - {'name': 'place', 'verbose_name': u'Место проведения', 'type': get_place}, - {'name': 'theme', 'verbose_name': u'ID Тематики', 'type': get_theme, 'width':8000}, - {'name': 'tag', 'verbose_name': u'Теги', 'type': get_tag, 'width':8000}, - {'name': 'description', 'verbose_name': u'Описание события', 'type': unicode}, - {'name': 'org', 'verbose_name': u'Организатор №1', 'type': get_int}, - {'name': 'periodic', 'verbose_name': 'Периодичность', 'type': get_periodic}, - {'name': 'audience', 'verbose_name': u'Аудитория', 'type': get_audience}, - {'name': 'web_page', 'verbose_name': u'Официальный веб-сайт', 'type': unicode}, - {'name': 'products', 'verbose_name': u'Экспонируемые продукты', 'type': unicode}, - {'name': 'time', 'verbose_name': u'Время работы', 'type': unicode}, - {'name': 'logo', 'verbose_name': u'Логотип', 'type': unicode}, - {'name': 'currency', 'verbose_name': u'Валюта', 'type': unicode}, - {'name': 'price_day', 'verbose_name': u'Стоимость билета 1 день', 'type': unicode}, - {'name': 'price_all', 'verbose_name': u'Стоимость билета все дни', 'type': unicode}, - {'name': 'pre_condition', 'verbose_name': u'Условия предварительной регистрации', 'type': unicode}, - {'name': 'price_day_bar', 'verbose_name': u'Стоимость на стойке 1 день', 'type': unicode}, - {'name': 'price_all_bar', 'verbose_name': u'Стоимость на стойке все дни', 'type': unicode}, - {'name': 'stand_condition', 'verbose_name': u'Условия регистрации на стойке', 'type': unicode}, - {'name': 'visit_note', 'verbose_name': u'Примечание по посещению', 'type': unicode}, - {'name': 'price_catalog', 'verbose_name': u'Каталог', 'type': get_int}, - {'name': 'tax', 'verbose_name': u'Налог включен', 'type': get_bool, 'width':1000}, - {'name': 'foundation_year', 'verbose_name': u'Год основания', 'type': get_int}, - {'name': 'visitors', 'verbose_name': u'Посетители', 'type': get_int}, - {'name': 'members', 'verbose_name': u'Участники', 'type': get_int}, - #{'name': 'visit_note', 'verbose_name': u'Страны', 'type': unicode}, !!! delete from import - {'name': 'area', 'verbose_name': u'Площадь', 'type': get_int}, - {'name': 'min_closed_area', 'verbose_name': u'Min_Raw кв.м.', 'type': get_int}, - {'name': 'max_closed_area', 'verbose_name': u'Max_Raw кв.м.', 'type': get_int}, - {'name': 'min_closed_equipped_area', 'verbose_name': u'Min_Pack кв.м.', 'type': get_int}, - {'name': 'max_closed_equipped_area', 'verbose_name': u'Max_Pack кв.м.', 'type': get_int}, - {'name': 'max_open_area', 'verbose_name': u'Открытая площадь', 'type': get_int}, - {'name': 'min_stand_size', 'verbose_name': u'Мин. Площадь кв.м.', 'type': get_int}, - {'name': 'registration_payment', 'verbose_name': u'Регистрационный взнос', 'type': get_int}, - {'name': 'participation_note', 'verbose_name': u'Примечание по участии', 'type': unicode}, - {'name': 'application_deadline', 'verbose_name': u'Крайний срок подачи заявки', 'type': get_date}, - {'name': 'quality_label', 'verbose_name': u'UFI', 'type': get_quality}, #???? - {'name': 'quality_label', 'verbose_name': u'РСВЯ', 'type': get_quality},#??? - {'name': 'quality_label', 'verbose_name': u'EXPORATING', 'type': get_quality}, #??? - {'name': 'canceled_by_administrator', 'verbose_name': u'Отменена администратором', 'type': get_bool}, - {'name': 'expohit', 'verbose_name': u'ExpoHIT', 'type': get_bool}, - {'name': 'is_published', 'verbose_name': u'Опубликована', 'type': get_bool}, - -] - +# default export settings field_settings = [ {'name': 'id', 'verbose_name': u'ID', 'type': get_int, 'width':1500}, {'name': 'url', 'verbose_name': u'Url', 'type': unicode}, @@ -412,8 +227,6 @@ field_settings = [ {'name': 'price_catalog', 'verbose_name': u'Каталог', 'type': get_int}, {'name': 'tax', 'verbose_name': u'Налог включен', 'type': get_bool, 'width':1000}, {'name': 'foundation_year', 'verbose_name': u'Год основания', 'type': get_int}, - - {'name': 'visit_note', 'verbose_name': u'Посетители', 'type': unicode}, {'name': 'visit_note', 'verbose_name': u'Участники', 'type': unicode}, {'name': 'visit_note', 'verbose_name': u'Страны', 'type': unicode}, @@ -424,7 +237,6 @@ field_settings = [ {'name': 'visit_note', 'verbose_name': u'Max_Pack кв.м.', 'type': unicode}, {'name': 'visit_note', 'verbose_name': u'Открытая площадь', 'type': unicode}, {'name': 'visit_note', 'verbose_name': u'Мин. Площадь кв.м.', 'type': unicode}, - {'name': 'visit_note', 'verbose_name': u'Примечание по участии', 'type': unicode}, {'name': 'visit_note', 'verbose_name': u'Крайний срок подачи заявки', 'type': unicode}, {'name': 'visit_note', 'verbose_name': u'UFI', 'type': unicode}, @@ -432,21 +244,13 @@ field_settings = [ {'name': 'visit_note', 'verbose_name': u'EXPORATING', 'type': unicode}, {'name': 'canceled_by_administrator', 'verbose_name': u'Отменена администратором', 'type': get_bool}, {'name': 'visit_note', 'verbose_name': u'ExpoHIT', 'type': unicode}, - {'name': 'address', 'verbose_name': u'Адрес', 'type': unicode}, - - {'name': 'email', 'verbose_name': u'Email', 'type': unicode}, {'name': 'phone', 'verbose_name': u'Телефон', 'type': get_int}, - - {'name': 'foundation', 'verbose_name': u'Год основания', 'type': get_int}, #{'name': 'events_number', 'verbose_name': u'Год основания', 'type': get_int}, {'name': 'staff_number', 'verbose_name': u'Год основания', 'type': get_int}, {'name': 'specialization', 'verbose_name': u'Год основания', 'type': unicode}, - - - {'name': 'max_price', 'verbose_name': u'Максимальная цена', 'type': get_int}, {'name': 'min_price', 'verbose_name': u'Минимальная цена', 'type': get_int}, {'name': 'registration_payment', 'verbose_name': u'Регистрационный взнос', 'type': get_int}, @@ -459,68 +263,221 @@ field_settings = [ {'name': 'min_area', 'verbose_name': u'Минимальная площадь', 'type': get_int}, {'name': 'max_area', 'verbose_name': u'Максимальная площадь', 'type': get_int}, {'name': 'is_published', 'verbose_name': u'Опубликована', 'type': get_bool}, - ] - +# ----------------------EVENT SETTINGS ------------------------- event_sett = { - u'ID':{u'field': u'id', u'func': to_int}, - u'Url':{u'field': u'url', u'func': unicode}, - u'Название':{u'field': u'name', u'func': unicode}, - u'Краткое описание':{u'field': u'main_title', u'func': unicode}, - u'Дата начала:(YYYY-MM-DD)':{u'field': u'data_begin', u'func': to_date}, - u'Дата окончания:(YYYY-MM-DD)':{u'field': u'data_end', u'func': to_date}, - u'Страна':{u'field': u'country', u'func': to_country}, - u'Город':{u'field': u'city_id', u'func': to_city, 'extra_values': 'country'}, - u'Место проведения':{u'field': u'place', u'func': to_place}, - u'ID Тематики':{u'field': u'theme', u'func': to_theme, u'method': True},### - u'Теги':{u'field': u'tag', u'func': to_tag, u'method': True}, - u'Организатор №1':{u'field': u'org', u'func': unicode},#### + u'ID': {u'field': u'id', u'func': to_int}, + u'Url': {u'field': u'url', u'func': unicode}, + u'Название': {u'field': u'name', u'func': unicode}, + u'Краткое описание': {u'field': u'main_title', u'func': unicode}, + u'Дата начала:(YYYY-MM-DD)': {u'field': u'data_begin', u'func': to_date}, + u'Дата окончания:(YYYY-MM-DD)': {u'field': u'data_end', u'func': to_date}, + u'Страна': {u'field': u'country', u'func': to_country}, + u'Город': {u'field': u'city_id', u'func': to_city, 'extra_values': 'country'}, + u'Место проведения': {u'field': u'place', u'func': to_place}, + u'ID Тематики': {u'field': u'theme', u'func': to_theme, u'method': True},### + u'Теги': {u'field': u'tag', u'func': to_tag, u'method': True}, + u'Организатор №1': {u'field': u'org', u'func': unicode},#### #u'Организатор №2':{u'field': u'organiser', u'func': to_tag},#### - u'Описание события':{u'field': u'description', u'func': unicode}, - u'Основные темы':{u'field': u'main_themes', u'func': unicode}, - u'Условия и скидка':{u'field': u'discount_description', u'func': unicode}, - u'Периодичность':{u'field': u'periodic', u'func': to_periodic},### - u'Аудитория':{u'field': u'audience', u'func': to_audience}, - u'Официальный веб-сайт':{u'field': u'web_page', u'func': to_url}, - u'Линк на регистрацию':{u'field': u'link', u'func': to_url}, - u'Экспонируемые продукты':{u'field': u'products', u'func': unicode}, - u'Время работы':{u'field': u'time', u'func': unicode}, + u'Описание события': {u'field': u'description', u'func': unicode}, + u'Основные темы': {u'field': u'main_themes', u'func': unicode}, + u'Условия и скидка': {u'field': u'discount_description', u'func': unicode}, + u'Периодичность': {u'field': u'periodic', u'func': to_periodic},### + u'Аудитория': {u'field': u'audience', u'func': to_audience}, + u'Официальный веб-сайт': {u'field': u'web_page', u'func': to_url}, + u'Линк на регистрацию': {u'field': u'link', u'func': to_url}, + u'Экспонируемые продукты': {u'field': u'products', u'func': unicode}, + u'Время работы': {u'field': u'time', u'func': unicode}, u'Логотип':{u'field': u'logo', u'func': save_logo, u'method': True}, - u'Валюта':{u'field': u'currency', u'func': unicode}, - u'Стоимость билета 1 день':{u'field': u'price_day', u'func': unicode}, - u'Стоимость билета все дни':{u'field': u'price_all', u'func': unicode}, - u'Условия предварительной регистрации':{u'field': u'pre_condition', u'func': unicode}, - u'Стоимость на стойке 1 день':{u'field': u'price_day_bar', u'func': unicode}, - u'Стоимость на стойке все дни':{u'field': u'price_all_bar', u'func': unicode}, - u'Условия регистрации на стойке':{u'field': u'stand_condition', u'func': unicode}, - u'Примечание по посещению':{u'field': u'visit_note', u'func': unicode}, - u'Каталог':{u'field': u'price_catalog', u'func': to_int}, - u'Налог включен':{u'field': u'tax', u'func': bool}, - u'Год основания':{u'field': u'foundation_year', u'func': to_int}, - #???u'Данные за год':{u'field': u'periodic', u'func': to_int}, - u'Посетители':{u'field': u'visitors', u'func': to_int}, - u'Участники':{u'field': u'members', u'func': to_int}, - u'Страны':{u'field': u'stat_countries', u'func': unicode}, - u'Площадь':{u'field': u'area', u'func': to_int}, - u'Мин стоимость':{u'field': u'min_price', u'func': to_int}, - u'Макс стоимость':{u'field': u'max_price', u'func': to_int}, - u'Min_Raw кв.м.':{u'field': u'min_closed_area', u'func': to_int}, - u'Max_Raw кв.м.':{u'field': u'max_closed_area', u'func': to_int}, - u'Min_Pack кв.м.':{u'field': u'min_closed_equipped_area', u'func': to_int}, - u'Max_Pack кв.м.':{u'field': u'max_closed_equipped_area', u'func': to_int}, - u'Открытая площадь':{u'field': u'max_open_area', u'func': to_int}, - u'Мин. Площадь кв.м.':{u'field': u'min_stand_size', u'func': to_int}, - u'Регистрационный взнос':{u'field': u'registration_payment', u'func': to_int}, - u'Примечание по участии':{u'field': u'participation_note', u'func': unicode}, - u'Крайний срок подачи заявки':{u'field': u'application_deadline', u'func': to_date}, - u'UFI':{u'field': u'quality_label', u'func': check_quality_label, u'bitfield':True, u'label': 'ufi'}, - u'РСВЯ':{u'field': u'quality_label', u'func': check_quality_label, u'bitfield':True, u'label': 'rsva'}, - u'EXPORATING':{u'field': u'quality_label', u'func': check_quality_label, u'bitfield':True, u'label': 'exporating'}, - u'Отменена':{u'field': u'canceled', u'func': bool}, - u'ExpoHIT':{u'field': u'expohit', u'func': bool}, + u'Валюта': {u'field': u'currency', u'func': unicode}, + u'Стоимость билета 1 день': {u'field': u'price_day', u'func': unicode}, + u'Стоимость билета все дни': {u'field': u'price_all', u'func': unicode}, + u'Условия предварительной регистрации': {u'field': u'pre_condition', u'func': unicode}, + u'Стоимость на стойке 1 день': {u'field': u'price_day_bar', u'func': unicode}, + u'Стоимость на стойке все дни': {u'field': u'price_all_bar', u'func': unicode}, + u'Условия регистрации на стойке': {u'field': u'stand_condition', u'func': unicode}, + u'Примечание по посещению': {u'field': u'visit_note', u'func': unicode}, + u'Каталог': {u'field': u'price_catalog', u'func': to_int}, + u'Налог включен': {u'field': u'tax', u'func': bool}, + u'Год основания': {u'field': u'foundation_year', u'func': to_int}, + u'Посетители': {u'field': u'visitors', u'func': to_int}, + u'Участники': {u'field': u'members', u'func': to_int}, + u'Страны': {u'field': u'stat_countries', u'func': unicode}, + u'Площадь': {u'field': u'area', u'func': to_int}, + u'Мин стоимость': {u'field': u'min_price', u'func': to_int}, + u'Макс стоимость': {u'field': u'max_price', u'func': to_int}, + u'Min_Raw кв.м.': {u'field': u'min_closed_area', u'func': to_int}, + u'Max_Raw кв.м.': {u'field': u'max_closed_area', u'func': to_int}, + u'Min_Pack кв.м.': {u'field': u'min_closed_equipped_area', u'func': to_int}, + u'Max_Pack кв.м.': {u'field': u'max_closed_equipped_area', u'func': to_int}, + u'Открытая площадь': {u'field': u'max_open_area', u'func': to_int}, + u'Мин. Площадь кв.м.': {u'field': u'min_stand_size', u'func': to_int}, + u'Регистрационный взнос': {u'field': u'registration_payment', u'func': to_int}, + u'Примечание по участии': {u'field': u'participation_note', u'func': unicode}, + u'Крайний срок подачи заявки': {u'field': u'application_deadline', u'func': to_date}, + u'UFI': {u'field': u'quality_label', u'func': check_quality_label, u'bitfield':True, u'label': 'ufi'}, + u'РСВЯ': {u'field': u'quality_label', u'func': check_quality_label, u'bitfield':True, u'label': 'rsva'}, + u'EXPORATING': {u'field': u'quality_label', u'func': check_quality_label, u'bitfield':True, u'label': 'exporating'}, + u'Отменена': {u'field': u'canceled', u'func': bool}, + u'ExpoHIT': {u'field': u'expohit', u'func': bool}, +} + +event_export_sett = [ + {'name': 'id', 'verbose_name': u'ID', 'type': get_int, 'width':1500}, + {'name': 'url', 'verbose_name': u'Url', 'type': unicode}, + {'name': 'name', 'verbose_name': u'Название', 'type': unicode}, + {'name': 'main_title', 'verbose_name': u'Краткое описание', 'type': unicode}, + {'name': 'data_begin', 'verbose_name': u'Дата начала:(YYYY-MM-DD)', 'type': get_date}, + {'name': 'data_end', 'verbose_name': u'Дата окончания:(YYYY-MM-DD)', 'type': get_date}, + {'name': 'country', 'verbose_name': u'Страна', 'type': unicode}, + {'name': 'city', 'verbose_name': u'Город', 'type': unicode}, + {'name': 'place', 'verbose_name': u'Место проведения', 'type': get_place}, + {'name': 'theme', 'verbose_name': u'ID Тематики', 'type': get_theme, 'width':8000}, + {'name': 'tag', 'verbose_name': u'Теги', 'type': get_tag, 'width':8000}, + {'name': 'description', 'verbose_name': u'Описание события', 'type': unicode}, + {'name': 'org', 'verbose_name': u'Организатор №1', 'type': get_int}, + {'name': 'periodic', 'verbose_name': 'Периодичность', 'type': get_periodic}, + {'name': 'audience', 'verbose_name': u'Аудитория', 'type': get_audience}, + {'name': 'web_page', 'verbose_name': u'Официальный веб-сайт', 'type': unicode}, + {'name': 'products', 'verbose_name': u'Экспонируемые продукты', 'type': unicode}, + {'name': 'time', 'verbose_name': u'Время работы', 'type': unicode}, + {'name': 'logo', 'verbose_name': u'Логотип', 'type': unicode}, + {'name': 'currency', 'verbose_name': u'Валюта', 'type': unicode}, + {'name': 'price_day', 'verbose_name': u'Стоимость билета 1 день', 'type': unicode}, + {'name': 'price_all', 'verbose_name': u'Стоимость билета все дни', 'type': unicode}, + {'name': 'pre_condition', 'verbose_name': u'Условия предварительной регистрации', 'type': unicode}, + {'name': 'price_day_bar', 'verbose_name': u'Стоимость на стойке 1 день', 'type': unicode}, + {'name': 'price_all_bar', 'verbose_name': u'Стоимость на стойке все дни', 'type': unicode}, + {'name': 'stand_condition', 'verbose_name': u'Условия регистрации на стойке', 'type': unicode}, + {'name': 'visit_note', 'verbose_name': u'Примечание по посещению', 'type': unicode}, + {'name': 'price_catalog', 'verbose_name': u'Каталог', 'type': get_int}, + {'name': 'tax', 'verbose_name': u'Налог включен', 'type': get_bool, 'width':1000}, + {'name': 'foundation_year', 'verbose_name': u'Год основания', 'type': get_int}, + {'name': 'visitors', 'verbose_name': u'Посетители', 'type': get_int}, + {'name': 'members', 'verbose_name': u'Участники', 'type': get_int}, + #{'name': 'visit_note', 'verbose_name': u'Страны', 'type': unicode}, !!! delete from import + {'name': 'area', 'verbose_name': u'Площадь', 'type': get_int}, + {'name': 'min_closed_area', 'verbose_name': u'Min_Raw кв.м.', 'type': get_int}, + {'name': 'max_closed_area', 'verbose_name': u'Max_Raw кв.м.', 'type': get_int}, + {'name': 'min_closed_equipped_area', 'verbose_name': u'Min_Pack кв.м.', 'type': get_int}, + {'name': 'max_closed_equipped_area', 'verbose_name': u'Max_Pack кв.м.', 'type': get_int}, + {'name': 'max_open_area', 'verbose_name': u'Открытая площадь', 'type': get_int}, + {'name': 'min_stand_size', 'verbose_name': u'Мин. Площадь кв.м.', 'type': get_int}, + {'name': 'registration_payment', 'verbose_name': u'Регистрационный взнос', 'type': get_int}, + {'name': 'participation_note', 'verbose_name': u'Примечание по участии', 'type': unicode}, + {'name': 'application_deadline', 'verbose_name': u'Крайний срок подачи заявки', 'type': get_date}, + {'name': 'quality_label', 'verbose_name': u'UFI', 'type': get_quality}, #???? + {'name': 'quality_label', 'verbose_name': u'РСВЯ', 'type': get_quality},#??? + {'name': 'quality_label', 'verbose_name': u'EXPORATING', 'type': get_quality}, #??? + {'name': 'canceled_by_administrator', 'verbose_name': u'Отменена администратором', 'type': get_bool}, + {'name': 'expohit', 'verbose_name': u'ExpoHIT', 'type': get_bool}, + {'name': 'is_published', 'verbose_name': u'Опубликована', 'type': get_bool}, +] +# -----------------------END EVENT SETTINGS --------------------------------- + +# --------------PLACE EXPO SETTINGS----------------------------- + +# import +place_exp_sett = { + u'ID': {u'field': u'id', u'func': to_int}, + u'Название': {u'field': u'name', u'func': unicode}, + u'Тип': {u'field': u'type', u'func': to_type}, + u'Краткое описание': {u'field': u'main_title', u'func': unicode}, + u'Страна': {u'field': u'country', u'func': to_country}, + u'Город': {u'field': u'city_id', u'func': to_city, 'extra_values': 'country'}, + u'Описание': {u'field': u'description', u'func': unicode}, + u'Адрес': {u'field': u'adress', u'func': unicode}, + u'Тел.': {u'field': u'phone', u'func': to_phone}, + u'Факс': {u'field': u'fax', u'func': to_phone}, + u'Лого': {u'field': u'logo', u'func': save_logo, u'method': True}, + u'Веб-сайт': {u'field': u'web_page', u'func': unicode}, + u'Email': {u'field': u'email', u'func': unicode}, + u'Карта проезда': {u'field': u'map', u'func': save_file, u'method': True, u'purpose': 'map'}, + u'Виртуальный тур': {u'field': u'virtual_tour', u'func': to_url}, + u'Год основания': {u'field': u'foundation_year', u'func': to_int}, + u'Количество мероприятий в год': {u'field': u'event_in_year', u'func': to_int}, + u'Общая выставочная площадь, кв. м.': {u'field': u'total_area', u'func': to_int}, + u'Закрытая выставочная площадь, кв. м.': {u'field': u'closed_area', u'func': to_int}, + u'Открытая выставочная площадь, кв. м.': {u'field': u'open_area', u'func': to_int}, + u'Количество павильонов': {u'field': u'total_pavilions', u'func': to_int}, + u'Площадь павильона': {u'field': u'halls', u'func': save_halls, u'method': True}, + u'Конференц-залы': {u'field': u'total_halls', u'func': to_int}, + u'Схема территории': {u'field': u'scheme', u'func': save_file, u'method': True, u'purpose': 'scheme teritory'},#сделать + u'Банк/Банкоматы/Обмен валюты': {u'field': u'bank', u'func': bool}, + u'Детская комната': {u'field': u'children_room', u'func': bool}, + u'Сервис для людей с ограниченными физическими возможностями': {u'field': u'disabled_service', u'func': bool}, + u'Конгресс-центр': {u'field': u'conference_centre', u'func': bool}, + u'Бизнес-центр': {u'field': u'business_centre', u'func': bool}, + u'On-line регистрация': {u'field': u'online_registration', u'func': bool}, + u'Wi-Fi': {u'field': u'wifi', u'func': bool}, + u'Кафе и рестораны': {u'field': u'cafe', u'func': bool}, + u'Информационные терминалы': {u'field': u'terminals', u'func': bool}, + u'Парковка': {u'field': u'parking', u'func': bool}, + u'Пресс-центр': {u'field': u'press_centre', u'func': bool}, + u'Мобильное приложение': {u'field': u'mobile_application', u'func': bool}, + # place_conf settings + u'Мультимедийное оборудование': {u'field': u'multimedia_equipment', u'func': bool}, + u'Конференц-связь': {u'field': u'conference_call', u'func': bool}, + u'Оборудование для синхронного перевода': {u'field': u'translate_equipment', u'func': bool}, + u'Банкетный зал': {u'field': u'banquet_hall', u'func': bool}, + u'Кейтеринг': {u'field': u'catering', u'func': bool}, + u'Гостиница': {u'field': u'hotel', u'func': bool}, + u'Выставочный зал': {u'field': u'exposition_hall', u'func': bool}, + u'Площадь выст. зала': {u'field': u'exp_hall_area', u'func': to_int}, + u'Общая вместимость': {u'field': u'total_capacity', u'func': to_int}, + u'Количество залов': {u'field': u'amount_halls', u'func': bool}, } +# export +place_settings=[ + {'name': 'id', 'verbose_name': u'ID', 'type': get_int, 'width':1500}, + {'name': 'url', 'verbose_name': u'Url', 'type': unicode}, + {'name': 'name', 'verbose_name': u'Название', 'type': unicode}, + {'name': 'type', 'verbose_name': u'Тип', 'type': get_place_type},########## + {'name': 'main_title', 'verbose_name': u'Краткое описание', 'type': unicode}, + {'name': 'country', 'verbose_name': u'Страна', 'type': unicode}, + {'name': 'city', 'verbose_name': u'Город', 'type': unicode}, + {'name': 'adress', 'verbose_name': u'Адресс', 'type': unicode}, + {'name': 'phone', 'verbose_name': u'Тел.', 'type': get_int}, + {'name': 'fax', 'verbose_name': u'Факс', 'type': get_int}, + {'name': 'logo', 'verbose_name': u'Логотип', 'type': unicode}, + {'name': 'web_page', 'verbose_name': u'Веб-сайт', 'type': unicode}, + {'name': 'email', 'verbose_name': u'Email', 'type': unicode}, + {'name': 'virtual_tour', 'verbose_name': u'Виртуальный тур', 'type': unicode}, + {'name': 'foundation_year', 'verbose_name': u'Год основания', 'type': get_int}, + {'name': 'event_in_year', 'verbose_name': u'Количество мероприятий в год', 'type': get_int}, + {'name': 'total_area', 'verbose_name': u'Общая выставочная площадь, кв. м.', 'type': get_int}, + {'name': 'closed_area', 'verbose_name': u'Закрытая выставочная площадь, кв. м.', 'type': get_int}, + {'name': 'open_area', 'verbose_name': u'Открытая выставочная площадь, кв. м.', 'type': get_int}, + {'name': 'total_pavilions', 'verbose_name': u'Количество павильонов', 'type': get_int}, + {'name': 'total_halls', 'verbose_name': u'Конференц-залы', 'type': get_int}, + {'name': 'total_capacity', 'verbose_name': u'Общая вместимость', 'type': get_int}, + {'name': 'exposition_hall', 'verbose_name': u'Выставочный зал', 'type': get_bool}, + {'name': 'exp_hall_area', 'verbose_name': u'Площадь выст. зала', 'type': get_int}, + {'name': 'amount_halls', 'verbose_name': u'Количество залов', 'type': get_int}, + {'name': 'bank', 'verbose_name': u'Банк/Банкоматы/Обмен валюты', 'type': get_bool}, + {'name': 'children_room', 'verbose_name': u'Детская комната', 'type': get_bool}, + {'name': 'disabled_service', 'verbose_name': u'Сервис для людей с ограниченными физическими возможностями', 'type': get_bool}, + {'name': 'conference_centre', 'verbose_name': u'Конгресс-центр', 'type': get_bool}, + {'name': 'business_centre', 'verbose_name': u'Бизнес-центр', 'type': get_bool}, + {'name': 'online_registration', 'verbose_name': u'On-line регистрация', 'type': get_bool}, + {'name': 'wifi', 'verbose_name': u'Wi-Fi', 'type': get_bool}, + {'name': 'cafe', 'verbose_name': u'Кафе и рестораны', 'type': get_bool}, + {'name': 'terminals', 'verbose_name': u'Информационные терминалы', 'type': get_bool}, + {'name': 'parking', 'verbose_name': u'Парковка', 'type': get_bool}, + {'name': 'press_centre', 'verbose_name': u'Пресс-центр', 'type': get_bool}, + {'name': 'mobile_application', 'verbose_name': u'Мобильное приложение', 'type': get_bool}, + {'name': 'multimedia_equipment', 'verbose_name': u'Мультимедийное оборудование', 'type': get_bool}, + {'name': 'conference_call', 'verbose_name': u'Конференц-связь', 'type': get_bool}, + {'name': 'translate_equipment', 'verbose_name': u'Оборудование для синхронного перевода', 'type': get_bool}, + {'name': 'banquet_hall', 'verbose_name': u'Банкетный зал', 'type': get_bool}, + {'name': 'catering', 'verbose_name': u'Кейтеринг', 'type': get_bool}, + {'name': 'hotel', 'verbose_name': u'Гостиница', 'type': get_bool}, + +] +# -----------------END PLACE EXPO SETTINGS------------------------------ +# default import settings import_settings={ 'name': {'func': unicode}, 'url': {'func': unicode}, diff --git a/import_xls/export_forms.py b/import_xls/export_forms.py index 363c9ba3..4f1bf333 100644 --- a/import_xls/export_forms.py +++ b/import_xls/export_forms.py @@ -13,7 +13,7 @@ from place_exposition.models import PlaceExposition from place_conference.models import PlaceConference from django.db.models.loading import get_model import xlwt -from excel_settings import import_settings, field_settings, event_export_sett +from excel_settings import field_settings, event_export_sett languages = [code for code in settings.LANGUAGES] @@ -75,13 +75,6 @@ class ExportForm(forms.Form): return self.workbook - -class ExportOrganiserForm(ExportForm): - model = Organiser - - def get_fname(self): - return 'organisers.xls' - class ExportUserForm(ExportForm): model = User @@ -106,7 +99,9 @@ class ExportTagForm(ExportForm): from excel_settings import place_settings class ExportPlaceExpositionForm(ExportForm): + model = PlaceExposition + def export(self): data = self.cleaned_data objects = self.get_objects(data) @@ -130,21 +125,18 @@ class ExportPlaceExpositionForm(ExportForm): self.worksheet.write(0, col, field.get('verbose_name', 'default'), self.style) #self.worksheet.write(1, col, field.get('name'), self.style) self.worksheet.col(col).width = field.get('width', 3333) - if field['name']=='tag': - self.worksheet.write(row+1, col, field.get('type')(value, object.theme)) - else: - self.worksheet.write(row+1, col, field.get('type')(value)) + + self.worksheet.write(row+1, col, field.get('type')(value)) + col += 1 return self.workbook def get_fname(self): return 'places.xls' -class ExportPlaceConferenceForm(ExportForm): +class ExportPlaceConferenceForm(ExportPlaceExpositionForm): model = PlaceConference - def get_fname(self): - return 'places.xls' class ExportCompanyForm(ExportForm): model = Company diff --git a/import_xls/import_forms.py b/import_xls/import_forms.py index e6172900..5afc2717 100644 --- a/import_xls/import_forms.py +++ b/import_xls/import_forms.py @@ -1,18 +1,32 @@ # -*- coding: utf-8 -*- +import urllib +import json +import xlrd +from django.db import IntegrityError from django import forms from django.conf import settings +from django.db.models.loading import get_model from theme.models import Theme, Tag from place_exposition.models import PlaceExposition from place_conference.models import PlaceConference -from country.models import Country -from organiser.models import Organiser -from django.db.models.loading import get_model -import xlrd, xlwt +from import_xls.models import Log from excel_settings import import_settings from functions.form_check import translit_with_separator +from excel_settings import place_exp_sett +from import_xls.excel_settings import event_sett languages = [code for code in settings.LANGUAGES] +typical_errors = {'(1048, "Column \'city_id\' cannot be null")':u'Неправильная страна или город', + '(1048, "Column \'country_id\' cannot be null")':u'Неправильная страна или город', + '(1048, "Column \'data_end\' cannot be null")':u'НЕправильный формат или не заполнена дата окончания', + '(1048, "Column \'data_end\' cannot be null")':u'НЕправильный формат или не заполнена дата начала'} + + +def logcall(f, msg): + with open(f.file.name, 'a') as logfile: + logfile.write(msg.encode('utf8')) + class ImportForm(forms.Form): """ @@ -82,19 +96,11 @@ class ImportForm(forms.Form): object.save() -class ImportOrganiserForm(ImportForm): - model = Organiser - class ImportThemeForm(ImportForm): model = Theme -from excel_settings import place_exp_sett -from django.db import IntegrityError -import urllib, json - - def google_address(address): if address: address = address.encode('utf') @@ -112,13 +118,131 @@ def google_address(address): return '' return '' -from djutils.decorators import async -from djutils.queue.decorators import queue_command + # place class ImportPlaceExpositionForm(ImportForm): model = PlaceExposition settings = place_exp_sett + def get_row_object(self, row): + if row[0] != '': + # in first column id + try: + obj = self.model.objects.language(self.lang).get(id=int(row[0])) + except ValueError: + obj = self.model() + obj.translate(self.lang) + + except self.model.DoesNotExist: + obj = self.model(id= int(row[0])) + obj.translate(self.lang) + else: + # if id blank - its a new object + obj = self.model() + obj.translate(self.lang) + return obj + + + + def save_file_debug(self): + data = self.cleaned_data + lang, self.lang = data['language'], data['language'] + f = data['excel_file'] + book = xlrd.open_workbook(file_contents=f.read()) + sheet = book.sheet_by_index(0) + row_list = [sheet.row_values(row_number) for row_number in range(sheet.nrows)] + field_names = [name for name in row_list[0]] + model = self.model + labels = [label for label in row_list[0]] + errors = [] + + #log = Log.custom.create_log_name(f) + for row_number, row in enumerate(row_list): + if row_number == 0: + continue + #log_msg = u'[%s] %s: '%(str(row_number), row[2]) + obj = self.get_row_object(row) + methods = [] + # go through row cells + for col_number, cell in enumerate(row): + # get current label + label = labels[col_number] + + setting = event_sett.get(label) + if setting is None: + # no label in settings + continue + + if setting.get('method'): + # this cell contains data that must be written after creating object + if cell != "": + methods.append({'func': setting['func'], 'value': cell, + 'purpose': setting.get('purpose'), 'field': label}) + continue + + field_name = setting['field'] + func = setting.get('func') + if func is None: + # no function in settings + continue + + extra_value = setting.get('extra_values') + if extra_value is not None: + # if setting has extra value then + # it is some field like city, tag + # that has relation and can be created + + # in function we add language(need for relation fields) + # and extra value from object (like for city need country) + try: + extra = getattr(obj, extra_value) + except Exception: + continue + value = func(cell, 'ru', extra) + else: + value = func(cell) + + #try: + setattr(obj, field_name, value) + #except ValueError: + # continue + + if not obj.url: + obj.url = translit_with_separator(obj.name) + + # try: + obj.save() + # except IntegrityError, e: + # error = str(e) + # if typical_errors.get(error): + # error = typical_errors[error] + # if error.startswith('(1062, "Duplicate entry') and error.endswith('for key \'url\'")'): + # + # error = u'Событие с таким названием или урлом уже существует' + # + # errors.append([obj.name, error]) + # log_msg += error + # logcall(log.log, log_msg + '\n') + # continue + + for method in methods: + func = method['func'] + if method.get('purpose'): + try: + func(obj, method['value'], method['purpose']) + except: + #log_msg += '(%s: Ошибка);'%method['field'] + continue + else: + msg = func(obj, method['value']) + if msg: + #log_msg += '(%s: %s);'%(method['field'], msg) + pass + + #logcall(log.log, log_msg + '\n') + + + def save_file(self): data = self.cleaned_data lang = data['language'] @@ -234,27 +358,10 @@ class ImportPlaceExpositionForm(ImportForm): return errors - -class ImportPlaceConferenceForm(ImportForm): +class ImportPlaceConferenceForm(ImportPlaceExpositionForm): model = PlaceConference -from import_xls.excel_settings import event_sett -typical_errors = {'(1048, "Column \'city_id\' cannot be null")':u'Неправильная страна или город', - '(1048, "Column \'country_id\' cannot be null")':u'Неправильная страна или город', - '(1048, "Column \'data_end\' cannot be null")':u'НЕправильный формат или не заполнена дата окончания', - '(1048, "Column \'data_end\' cannot be null")':u'НЕправильный формат или не заполнена дата начала'} - -# event -import time -def logcall(f, msg): - with open(f.file.name, 'a') as logfile: - logfile.write(msg.encode('utf8')) - - - - -from import_xls.models import Log class ImportEventForm(ImportForm): """ extended form for importing one type of event @@ -359,8 +466,8 @@ class ImportEventForm(ImportForm): except Exception: setattr(obj, 'place_alt', cell) if not obj.url: - a = obj.name obj.url = translit_with_separator(obj.name) + obj.is_published = True try: obj.save() diff --git a/import_xls/models.py b/import_xls/models.py index 8bb0d818..f9980f28 100644 --- a/import_xls/models.py +++ b/import_xls/models.py @@ -3,23 +3,13 @@ from django.db import models from django.conf import settings from django.db.models.fields.files import FieldFile from django.db.models.signals import pre_delete +from functions.signal_handlers import file_cleanup def get_doc_dir(instance, filename): from pytils import translit return u'import_xls/import/%s' %translit.translify(filename) -def file_cleanup(sender, instance, *args, **kwargs): - ''' - Deletes the file(s) associated with a model instance. The model - is not saved after deletion of the file(s) since this is meant - to be used with the pre_delete signal. - ''' - for field_name, _ in instance.__dict__.iteritems(): - field = getattr(instance, field_name) - if issubclass(field.__class__, FieldFile) and field.name: - field.delete(save=False) - class LogManager(models.Manager): def create_log(self, work_file, errors): """ diff --git a/meta/models.py b/meta/models.py index 98c6c5cd..3e5587a5 100644 --- a/meta/models.py +++ b/meta/models.py @@ -1,25 +1,25 @@ # -*- coding: utf-8 -*- +import copy from django.db import models from django.utils import translation from django.db.models.signals import post_save from django.utils.translation import ugettext_lazy as _ from django.conf import settings -from django.core.urlresolvers import reverse_lazy from django.core.cache import cache +from functions.signal_handlers import post_save_handler from hvad.models import TranslatableModel, TranslatedFields, TranslationManager from pymorphy.django_conf import default_morph as morph -from functions.signal_handlers import post_save_handler -import copy - # additional funcs -MONTHES = {'jan': _(u'январе'), 'feb': _(u'феврале'), 'mar': _(u'марте'), 'apr': _(u'апреле'), +def get_month_inflect(value, key): + MONTHES = {'jan': _(u'январе'), 'feb': _(u'феврале'), 'mar': _(u'марте'), 'apr': _(u'апреле'), 'may': _(u'мае'), 'jun': _(u'июне'), u'jul': _(u'июле'), 'aug': _(u'августе'), 'sep': _(u'сентябре'), 'oct': _(u'октябре'), 'nov': _(u'ноябре'), 'dec': _(u'декабре'),} -def get_month_inflect(value, key): + return {key: MONTHES.get(value, '') } + def get_obj_inflect(obj, key): if translation.get_language() == 'ru': result = {key: getattr(obj, 'inflect', '')} @@ -27,6 +27,7 @@ def get_obj_inflect(obj, key): result = {key: getattr(obj, 'name', '')} return result + def get_theme_inflect(obj, key): if translation.get_language() == 'ru': result = {'theme_inflect': getattr(obj, 'inflect', ''), @@ -36,6 +37,7 @@ def get_theme_inflect(obj, key): 'theme_name': getattr(obj, 'name', '')} return result + def get_tag_inflect(obj, key): if translation.get_language() == 'ru': result = {'tag_inflect': getattr(obj, 'inflect', ''), @@ -47,47 +49,54 @@ def get_tag_inflect(obj, key): class MetaSetting(TranslatableModel): + """ + setting that generates meta fields + """ name = models.CharField(max_length=100, unique=True) translations = TranslatedFields( - title = models.CharField(max_length=255, blank=True), - description = models.CharField(max_length=255, blank=True), - keywords = models.CharField(max_length=255, blank=True), - h1 = models.CharField(max_length=255, blank=True), + title=models.CharField(max_length=255, blank=True), + description=models.CharField(max_length=255, blank=True), + keywords=models.CharField(max_length=255, blank=True), + h1=models.CharField(max_length=255, blank=True), ) - + # params that handles for objects object_params = {'object_name': 'name', 'object_title': 'main_title', 'city': 'city', 'country': 'country'} - + # default params params = {'month': get_month_inflect, 'country': get_obj_inflect, 'city': get_obj_inflect, 'theme': get_theme_inflect, 'tag': get_tag_inflect} + monthes = {'jan': _(u'январе'), 'feb': _(u'феврале'), 'mar': _(u'марте'), 'apr': _(u'апреле'), 'may': _(u'мае'), 'jun': _(u'июне'), u'jul': _(u'июле'), 'aug': _(u'августе'), 'sep': _(u'сентябре'), 'oct': _(u'октябре'), 'nov': _(u'ноябре'), 'dec': _(u'декабре'),} - def __unicode__(self): return self.name - def generate_meta(self, params, obj=None): """ + generating meta fields by given params and current object fields + obj must be in current language """ - + # current language lang = translation.get_language() + updates = {} if obj: + # if objects - generate fields from object_params field for key, value in self.object_params.iteritems(): updates.update({key: getattr(obj, value, '')}) for key, value in params.iteritems(): + # iterate through default params if key in self.params: updates.update(self.params[key](value, key)) params.update(updates) - + # current translation object tr = self.translations.get(language_code=lang) title = tr.title.format(**params) description = tr.description.format(**params) - keywords = []#tr.keywords.format(**params) + keywords = []#tr.keywords.format(**params) uncoment if keywords need h1 = tr.h1.format(**params) return {'title': title, 'description': description, 'keywords': keywords, 'h1': h1} @@ -101,7 +110,6 @@ class MetaSetting(TranslatableModel): s = morph.inflect_ru(s, u'пр') return s - def get_title(self): title = self.title return title @@ -119,11 +127,6 @@ class MetaSetting(TranslatableModel): return [] -post_save.connect(post_save_handler, sender=MetaSetting) - - -# SEO - tests # - class SeoTextManager(TranslationManager): cache_time = 120 @@ -142,6 +145,9 @@ class SeoTextManager(TranslationManager): class SeoText(TranslatableModel): + """ + store seo data for specified urls + """ url = models.CharField(max_length=50, unique=True, verbose_name=u"URL: www.expomap.ru") translations = TranslatedFields( @@ -191,3 +197,6 @@ class SeoText(TranslatableModel): def __unicode__(self): return self.url + + +post_save.connect(post_save_handler, sender=MetaSetting) \ No newline at end of file diff --git a/photologue/admin.py b/photologue/admin.py index 4686e1bf..53481d2b 100644 --- a/photologue/admin.py +++ b/photologue/admin.py @@ -14,247 +14,6 @@ MULTISITE = getattr(settings, 'PHOTOLOGUE_MULTISITE', False) ENABLE_TAGS = getattr(settings, 'PHOTOLOGUE_ENABLE_TAGS', False) -""" -class GalleryAdminForm(forms.ModelForm): - - class Meta: - model = Gallery - if MULTISITE: - exclude = [] - else: - exclude = ['sites'] - if not ENABLE_TAGS: - exclude.append('tags') - - -class GalleryAdmin(admin.ModelAdmin): - list_display = ('title', 'date_added', 'photo_count', 'is_public') - list_filter = ['date_added', 'is_public'] - if MULTISITE: - list_filter.append('sites') - date_hierarchy = 'date_added' - prepopulated_fields = {'slug': ('title',)} - form = GalleryAdminForm - if MULTISITE: - filter_horizontal = ['sites'] - if MULTISITE: - actions = [ - 'add_to_current_site', - 'add_photos_to_current_site', - 'remove_from_current_site', - 'remove_photos_from_current_site' - ] - - def formfield_for_manytomany(self, db_field, request, **kwargs): - ''' Set the current site as initial value. ''' - if db_field.name == "sites": - kwargs["initial"] = [Site.objects.get_current()] - return super(GalleryAdmin, self).formfield_for_manytomany(db_field, request, **kwargs) - - def save_related(self, request, form, *args, **kwargs): - ''' - If the user has saved a gallery with a photo that belongs only to - different Sites - it might cause much confusion. So let them know. - ''' - super(GalleryAdmin, self).save_related(request, form, *args, **kwargs) - orphaned_photos = form.instance.orphaned_photos() - if orphaned_photos: - msg = ungettext( - 'The following photo does not belong to the same site(s)' - ' as the gallery, so will never be displayed: %(photo_list)s.', - 'The following photos do not belong to the same site(s)' - ' as the gallery, so will never be displayed: %(photo_list)s.', - len(orphaned_photos) - ) % {'photo_list': ", ".join([photo.title for photo in orphaned_photos])} - messages.warning(request, msg) - - def add_to_current_site(modeladmin, request, queryset): - current_site = Site.objects.get_current() - current_site.gallery_set.add(*queryset) - msg = ungettext( - "The gallery has been successfully added to %(site)s", - "The galleries have been successfully added to %(site)s", - len(queryset) - ) % {'site': current_site.name} - messages.success(request, msg) - - add_to_current_site.short_description = \ - _("Add selected galleries from the current site") - - def remove_from_current_site(modeladmin, request, queryset): - current_site = Site.objects.get_current() - current_site.gallery_set.remove(*queryset) - msg = ungettext( - "The gallery has been successfully removed from %(site)s", - "The selected galleries have been successfully removed from %(site)s", - len(queryset) - ) % {'site': current_site.name} - messages.success(request, msg) - - remove_from_current_site.short_description = \ - _("Remove selected galleries from the current site") - - def add_photos_to_current_site(modeladmin, request, queryset): - photos = Photo.objects.filter(galleries__in=queryset) - current_site = Site.objects.get_current() - current_site.photo_set.add(*photos) - msg = ungettext( - 'All photos in gallery %(galleries)s have been successfully added to %(site)s', - 'All photos in galleries %(galleries)s have been successfully added to %(site)s', - len(queryset) - ) % { - 'site': current_site.name, - 'galleries': ", ".join(["'{0}'".format(gallery.title) - for gallery in queryset]) - } - messages.success(request, msg) - - add_photos_to_current_site.short_description = \ - _("Add all photos of selected galleries to the current site") - - def remove_photos_from_current_site(modeladmin, request, queryset): - photos = Photo.objects.filter(galleries__in=queryset) - current_site = Site.objects.get_current() - current_site.photo_set.remove(*photos) - msg = ungettext( - 'All photos in gallery %(galleries)s have been successfully removed from %(site)s', - 'All photos in galleries %(galleries)s have been successfully removed from %(site)s', - len(queryset) - ) % { - 'site': current_site.name, - 'galleries': ", ".join(["'{0}'".format(gallery.title) - for gallery in queryset]) - } - messages.success(request, msg) - - remove_photos_from_current_site.short_description = \ - _("Remove all photos in selected galleries from the current site") - -admin.site.register(Gallery, GalleryAdmin) - - -class GalleryUploadAdmin(admin.ModelAdmin): - - def has_change_permission(self, request, obj=None): - return False # To remove the 'Save and continue editing' button - - def save_model(self, request, obj, form, change): - # Warning the user when things go wrong in a zip upload. - obj.request = request - obj.save() - -admin.site.register(GalleryUpload, GalleryUploadAdmin) - - -class PhotoAdminForm(forms.ModelForm): - - class Meta: - model = Photo - if MULTISITE: - exclude = [] - else: - exclude = ['sites'] - if not ENABLE_TAGS: - exclude.append('tags') - - -class PhotoAdmin(admin.ModelAdmin): - list_display = ('title', 'date_taken', 'date_added', - 'is_public', 'tags', 'view_count', 'admin_thumbnail') - list_filter = ['date_added', 'is_public'] - if MULTISITE: - list_filter.append('sites') - search_fields = ['title', 'slug', 'caption'] - list_per_page = 10 - prepopulated_fields = {'slug': ('title',)} - form = PhotoAdminForm - if MULTISITE: - filter_horizontal = ['sites'] - if MULTISITE: - actions = ['add_photos_to_current_site', 'remove_photos_from_current_site'] - - def formfield_for_manytomany(self, db_field, request, **kwargs): - ''' Set the current site as initial value. ''' - if db_field.name == "sites": - kwargs["initial"] = [Site.objects.get_current()] - return super(PhotoAdmin, self).formfield_for_manytomany(db_field, request, **kwargs) - - def add_photos_to_current_site(modeladmin, request, queryset): - current_site = Site.objects.get_current() - current_site.photo_set.add(*queryset) - msg = ungettext( - 'The photo has been successfully added to %(site)s', - 'The selected photos have been successfully added to %(site)s', - len(queryset) - ) % {'site': current_site.name} - messages.success(request, msg) - - add_photos_to_current_site.short_description = \ - _("Add selected photos to the current site") - - def remove_photos_from_current_site(modeladmin, request, queryset): - current_site = Site.objects.get_current() - current_site.photo_set.remove(*queryset) - msg = ungettext( - 'The photo has been successfully removed from %(site)s', - 'The selected photos have been successfully removed from %(site)s', - len(queryset) - ) % {'site': current_site.name} - messages.success(request, msg) - - remove_photos_from_current_site.short_description = \ - _("Remove selected photos from the current site") - -admin.site.register(Photo, PhotoAdmin) - - -class PhotoEffectAdmin(admin.ModelAdmin): - list_display = ('name', 'description', 'color', 'brightness', - 'contrast', 'sharpness', 'filters', 'admin_sample') - fieldsets = ( - (None, { - 'fields': ('name', 'description') - }), - ('Adjustments', { - 'fields': ('color', 'brightness', 'contrast', 'sharpness') - }), - ('Filters', { - 'fields': ('filters',) - }), - ('Reflection', { - 'fields': ('reflection_size', 'reflection_strength', 'background_color') - }), - ('Transpose', { - 'fields': ('transpose_method',) - }), - ) - -admin.site.register(PhotoEffect, PhotoEffectAdmin) - - -class PhotoSizeAdmin(admin.ModelAdmin): - list_display = ('name', 'width', 'height', 'crop', 'pre_cache', 'effect', 'increment_count') - fieldsets = ( - (None, { - 'fields': ('name', 'width', 'height', 'quality') - }), - ('Options', { - 'fields': ('upscale', 'crop', 'pre_cache', 'increment_count') - }), - ('Enhancements', { - 'fields': ('effect', 'watermark',) - }), - ) - -admin.site.register(PhotoSize, PhotoSizeAdmin) - - -class WatermarkAdmin(admin.ModelAdmin): - list_display = ('name', 'opacity', 'style') - - -admin.site.register(Watermark, WatermarkAdmin) -""" #------------------EXPOMAP VIEWS---------------------------------------------- from django.views.generic import ListView, FormView @@ -301,7 +60,7 @@ class AdminViewObject(FormView): class PhotoView(AdminViewObject): model = Photo form_class = PhotoForm - template_name = 'photogallery/admin_photo.html' + template_name = 'admin/photogallery/admin_photo.html' success_url = '/admin/photogallery/photo/all/' def get_form(self, form_class): @@ -315,6 +74,7 @@ class PhotoView(AdminViewObject): photo = self.obj data = {} data['image'] = photo.image.url + data['sort'] = photo.sort for code, name in settings.LANGUAGES: obj = Photo._meta.translations_model.objects.get(language_code = code,master__id=getattr(photo, 'id')) #access to translated fields @@ -328,7 +88,7 @@ class PhotoView(AdminViewObject): class GalleryView(AdminViewObject): model = Gallery form_class = GalleryForm - template_name = 'photogallery/admin_gallery.html' + template_name = 'admin/photogallery/admin_gallery.html' success_url = '/admin/photogallery/gallery/all/' def get_form(self, form_class): @@ -355,13 +115,13 @@ class GalleryView(AdminViewObject): class PhotoListView(ListView): paginate_by = settings.ADMIN_PAGINATION model = Photo - template_name = 'photogallery/admin_photo_list.html' + template_name = 'admin/photogallery/admin_photo_list.html' class GalleryListView(ListView): paginate_by = settings.ADMIN_PAGINATION model = Gallery - template_name = 'photogallery/admin_gallery_list.html' + template_name = 'admin/photogallery/admin_gallery_list.html' def delete_photo(request, photo_id): diff --git a/photologue/client_urls.py b/photologue/client_urls.py index e8b48b22..eed40034 100644 --- a/photologue/client_urls.py +++ b/photologue/client_urls.py @@ -5,7 +5,7 @@ from client_view import GalleryView, PhotoView urlpatterns = patterns('', #url(r'gallery/(?P.*)$', GalleryView.as_view()), #url(r'photo/(?P.*)$', PhotoView.as_view()), - url(r'^show/photo/(?P.*)$', 'photologue.client_view.ajax_photo'), + url(r'^show/photo/(?P.*)/$', 'photologue.client_view.ajax_photo'), ) diff --git a/photologue/forms.py b/photologue/forms.py index 788b94a8..79bf4e7b 100644 --- a/photologue/forms.py +++ b/photologue/forms.py @@ -18,8 +18,8 @@ class GalleryForm(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['title_%s' % code] = forms.CharField(label='Описание', required=required) - self.fields['description_%s' % code] = forms.CharField(label='Заголовок', required=required) + self.fields['title_%s' % code] = forms.CharField(label='Заголовок', required=required) + self.fields['description_%s' % code] = forms.CharField(label='Описание', required=False) def save(self, obj=None): data = self.cleaned_data @@ -35,6 +35,7 @@ class GalleryForm(forms.Form): class PhotoForm(forms.Form): image = forms.ImageField(label=u'Изображение', required=False) + sort = forms.IntegerField(label=u'Позиция', initial=10, required=False) def __init__(self, *args, **kwargs): """ @@ -60,9 +61,11 @@ class PhotoForm(forms.Form): else: photo = obj photo.image = obj.image - + if data.get('sort'): + photo.sort = data['sort'] fill_with_signal(Photo, photo, data) + photo.save() return photo diff --git a/photologue/models.py b/photologue/models.py index 7e5ab25c..fc3e46d3 100644 --- a/photologue/models.py +++ b/photologue/models.py @@ -15,7 +15,7 @@ except ImportError: import django from django.utils.timezone import now from django.db import models -from django.db.models.signals import post_init, post_save +from django.db.models.signals import post_init, post_save, pre_delete from django.conf import settings from django.core.files.base import ContentFile from django.core.files.storage import default_storage @@ -29,6 +29,7 @@ from django.utils.encoding import python_2_unicode_compatible from django.core.validators import RegexValidator from django.contrib import messages from django.contrib.sites.models import Site +from functions.signal_handlers import post_save_handler, file_cleanup # Required PIL classes may or may not be available from the root namespace # depending on the installation method used. @@ -171,8 +172,8 @@ class UserMark(models.Model): @python_2_unicode_compatible class Gallery(TranslatableModel): translations = TranslatedFields( - title = models.CharField(_('title'), max_length=200), - description = models.TextField(_('description'), blank=True) + title=models.CharField(_('title'), max_length=200), + description=models.TextField(_('description'), blank=True) ) date_added = models.DateTimeField(_('date published'), default=now) @@ -693,17 +694,14 @@ class ImageModel(models.Model): @python_2_unicode_compatible class Photo(TranslatableModel, ImageModel): translations = TranslatedFields( - title = models.CharField(_('title'), - max_length=200), - caption = models.TextField(_('caption'), - blank=True) + caption=models.TextField(_('caption'), blank=True), + title=models.CharField(_('title'), max_length=200) ) - slug = models.SlugField(_('slug'), unique=True, help_text=_('A "slug" is a unique URL-friendly title for an object.'), max_length=200) - + sort = models.PositiveIntegerField(verbose_name="Sort", null=True, default=10, db_index=True) date_added = models.DateTimeField(_('date added'), default=now) is_public = models.BooleanField(_('is public'), @@ -712,19 +710,18 @@ class Photo(TranslatableModel, ImageModel): tags = TagField(help_text=tagfield_help_text, verbose_name=_('tags')) sites = models.ManyToManyField(Site, verbose_name=_(u'sites'), blank=True, null=True) - users = models.ManyToManyField(UserMark, null=True) objects = PhotologueManager() class Meta: - ordering = ['-date_added'] + ordering = ['sort'] get_latest_by = 'date_added' verbose_name = _("photo") verbose_name_plural = _("photos") def __str__(self): - return self.get_available_title() + return str(self.id) def translation_model(self): return self._meta.translations_model @@ -1107,9 +1104,6 @@ def add_default_site(instance, created, **kwargs): post_save.connect(add_default_site, sender=Gallery) post_save.connect(add_default_site, sender=Photo) - -from django.db.models.signals import post_save -from functions.signal_handlers import post_save_handler - +pre_delete.connect(file_cleanup, sender=Photo) post_save.connect(post_save_handler, sender=Photo) post_save.connect(post_save_handler, sender=Gallery) \ No newline at end of file diff --git a/place_conference/admin.py b/place_conference/admin.py index 9fc3f793..1202bd5f 100644 --- a/place_conference/admin.py +++ b/place_conference/admin.py @@ -189,6 +189,63 @@ def conference_change(request, url): return render_to_response('place_conference_add.html', args) +from photologue.forms import PhotoForm +from functions.admin_views import AdminView +from file.forms import FileModelForm, FileForm +class PlaceConferenceView(AdminView): + form_class = ConferenceForm + model = PlaceConference + success_url = '/admin/place_conference/all/' + template_name = 'admin/place_conference/place_conference.html' + + def get_form(self, form_class): + if self.request.POST: + return super(PlaceConferenceView, self).get_form(form_class) + obj = self.set_obj() + if obj: + data = {'type': obj.type, 'address': obj.address, + 'phone': obj.phone, 'fax': obj.fax, 'web_page': obj.web_page, 'email': obj.email, + 'foundation_year': obj.foundation_year, 'total_capacity': obj.total_capacity, + 'amount_halls': obj.amount_halls, 'wifi':obj.wifi, 'multimedia_equipment': obj.multimedia_equipment, + 'conference_call':obj.conference_call, 'translate_equipment': obj.translate_equipment, + 'banquet_hall': obj.banquet_hall, 'catering': obj.catering, 'hotel': obj.hotel, + 'video_link':obj.video_link, 'logo': obj.logo, 'exposition_hall': obj.exposition_hall, + 'exp_hall_area': obj.exp_hall_area} + + data['country'] = obj.country_id + data['city'] = obj.city_id + + for code, name in settings.LANGUAGES: + trans_obj = self.model._meta.translations_model.objects.get(language_code = code,master__id=obj.id) #access to translated fields + data['name_%s'%code] = obj.name + data['main_title_%s'%code] = obj.main_title + data['description_%s'%code] = obj.description + data['adress_%s'%code] = obj.adress + data['hall_capacity_%s'%code] = obj.hall_capacity + data['title_%s'%code] = obj.title + data['keywords_%s'%code] = obj.keywords + data['descriptions_%s'%code] = obj.descriptions + data['total_year_action_%s'%code] = obj.total_year_action + + form = form_class(initial=data) + form.fields['city'].widget.attrs['data-init-text'] = obj.city.name + return form + else: + return form_class() + + + def get_context_data(self, **kwargs): + context = super(PlaceConferenceView, self).get_context_data(**kwargs) + obj = self.set_obj() + if obj: + context['file_form'] = FileForm(initial={'model': 'place_conference.PlaceConference'}) + files = FileModel.objects.filter(content_type=ContentType.objects.get_for_model(obj),object_id=getattr(obj, 'id')) + context['files'] = files + + context['photo_form'] = PhotoForm() + + return context + class PlaceConferenceListView(AdminListView): template_name = 'admin/place_conference/place_conference_list.html' form_class = PlaceConferenceFilterForm diff --git a/place_conference/admin_urls.py b/place_conference/admin_urls.py index aa45ae8a..4816e171 100644 --- a/place_conference/admin_urls.py +++ b/place_conference/admin_urls.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- from django.conf.urls import patterns, include, url -from admin import PlaceConferenceListView +from admin import PlaceConferenceListView, PlaceConferenceView urlpatterns = patterns('place_conference.admin', url(r'^add.*/$', 'conference_add'), @@ -9,4 +9,6 @@ urlpatterns = patterns('place_conference.admin', url(r'^copy/(?P.*)/$', 'place_conference_copy'), #url(r'^all/$', 'conference_all'), url(r'^all/$', PlaceConferenceListView.as_view()), + url(r'^(?P.*)/$', PlaceConferenceView.as_view()), + url(r'^$', PlaceConferenceView.as_view()), ) diff --git a/place_conference/forms.py b/place_conference/forms.py index 94b1dee6..f2e38aa5 100644 --- a/place_conference/forms.py +++ b/place_conference/forms.py @@ -28,12 +28,12 @@ class ConferenceForm(forms.Form): """ types = [(item1, item2) for item1, item2 in CONFERENCE_TYPE] type = forms.ChoiceField(label='Краткое описание', required=False, choices=types) - + logo = forms.ImageField(label='Logo', required=False, max_length=500) country = forms.ModelChoiceField(label='Страна', queryset=Country.objects.all(), empty_label=None) #creates select input with empty choices cause it will be filled with ajax - city = forms.ChoiceField(label='Город', choices=[('','')]) + city = forms.CharField(label='Город', widget=forms.HiddenInput()) - address = forms.CharField(label='Адресс', widget=LocationWidget) + address = forms.CharField(label='Адресс', widget=LocationWidget, required=False) foundation_year = forms.CharField(label='Год основания', required=False, widget=forms.TextInput(attrs={'placeholder': 'Год основания'})) phone = forms.CharField(label='Телефон', required=False, @@ -108,7 +108,7 @@ class ConferenceForm(forms.Form): """ - def save(self, id=None): + def save(self, obj=None): """ change PlaceConference model object with id = id N/A add new PlaceConference model object @@ -117,13 +117,20 @@ class ConferenceForm(forms.Form): """ data = self.cleaned_data #create new place_conference object or get exists - if not id: + if not obj: place_conference = PlaceConference() else: - place_conference = PlaceConference.objects.get(id=id) + place_conference = obj + + if not getattr(place_conference, 'url'): + if data.get('name_en'): + place_conference.url = translit_with_separator(data['name_en'].strip()).lower() + else: + place_conference.url = translit_with_separator(data['name_ru'].strip()).lower() + if data.get('logo'): + place_conference.logo = data['logo'] #simple fields - place_conference.url = translit_with_separator(data['name_ru'].strip()).lower() place_conference.type = data['type'] place_conference.address = data['address'] place_conference.phone = data['phone'] @@ -152,22 +159,9 @@ class ConferenceForm(forms.Form): fill_with_signal(PlaceConference, place_conference, data) #save files - check_tmp_files(place_conference, data['key']) - - return PlaceConference.objects.get(id=place_conference.id) - - def clean(self): - id = self.cleaned_data.get('place_conference_id') - name_ru = self.cleaned_data.get('name_ru') - - place_conference = PlaceConference.objects.filter(url=translit_with_separator(name_ru)) - if place_conference and str(place_conference[0].id) != id: - msg = 'Место проведения с таким названием уже существует' - self._errors['name_ru'] = ErrorList([msg]) - del self.cleaned_data['name_ru'] - - return self.cleaned_data + place_conference.save() + return place_conference def clean_web_page(self): """ @@ -318,4 +312,17 @@ class HallForm(forms.ModelForm): class PlaceConferenceFilterForm(AdminFilterForm): - model = PlaceConference \ No newline at end of file + model = PlaceConference + + country = forms.MultipleChoiceField(choices=[(item.id, item.name) for item in list(Country.objects.all())], + required=False, widget=forms.SelectMultiple()) + + def filter(self): + qs = super(PlaceConferenceFilterForm, self).filter() + data = self.cleaned_data + country = data['country'] + + if country: + qs = qs.filter(country_id__in=country) + + return qs \ No newline at end of file diff --git a/place_conference/models.py b/place_conference/models.py index 170a8806..03fe4f1b 100644 --- a/place_conference/models.py +++ b/place_conference/models.py @@ -1,11 +1,11 @@ # -*- coding: utf-8 -*- from django.db import models from django.contrib.contenttypes import generic -from django.db.models.signals import post_save +from django.db.models.signals import post_save, pre_save from hvad.models import TranslatableModel, TranslatedFields, TranslationManager from functions.custom_fields import EnumField from functions.custom_fields import LocationField -from functions.signal_handlers import post_save_handler +from functions.signal_handlers import post_save_handler, pre_save_handler from functions.models_methods import ExpoManager import copy from django.utils.translation import ugettext as _ @@ -15,6 +15,11 @@ from functions.model_mixin import ExpoMixin CONFERENCE_TYPE = (('Convention centre', 'Конгресс-центр'), ('Exposition centre', 'Конференц зал'),) +def logo_name(instance, filename): + url = instance.url + return '/'.join(['place_conference', url, url+'_logo.jpg']) + + class PlaceConference(TranslatableModel, ExpoMixin): """ Create PlaceConference model @@ -22,28 +27,33 @@ class PlaceConference(TranslatableModel, ExpoMixin): Uses hvad.TranslatableModel which is child of django.db.models class """ - #set manager of this model + catalog = '/places/' + place = 'place_conference' + catalog_name = _(u'Места:') + search_name = None objects = ExpoManager() url = models.SlugField(unique=True) - country = models.ForeignKey('country.Country', on_delete=models.PROTECT) - city = models.ForeignKey('city.City', on_delete=models.PROTECT, related_name='place_conferences') + country = models.ForeignKey('country.Country', on_delete=models.PROTECT, verbose_name=_(u'Страна')) + city = models.ForeignKey('city.City', on_delete=models.PROTECT, + related_name='place_conferences', verbose_name=_(u'Город')) #type uses EnumField for creating Enum type field in Mysql database - type = EnumField(values = [item1 for item1, item2 in CONFERENCE_TYPE]) + type = EnumField(values = [item1 for item1, item2 in CONFERENCE_TYPE], default=CONFERENCE_TYPE[0][0], + verbose_name=_(u'Тип')) #information + address = LocationField(verbose_name=_(u'Адресс')) # - address= LocationField(verbose_name='Адресс') - # - phone = models.BigIntegerField(blank=True, null=True) - fax = models.BigIntegerField(blank=True, null=True) - web_page = models.URLField(blank=True) - email = models.EmailField(blank=True) - foundation_year = models.PositiveIntegerField(blank=True, null=True) - total_capacity = models.PositiveIntegerField(blank=True, null=True) - amount_halls = models.PositiveIntegerField(blank=True, null=True) - exposition_hall = models.NullBooleanField() - exp_hall_area = models.PositiveIntegerField(blank=True, null=True) + phone = models.BigIntegerField(blank=True, null=True, verbose_name=_(u'Телефон')) + fax = models.BigIntegerField(blank=True, null=True, verbose_name=_(u'Факс')) + web_page = models.URLField(blank=True, verbose_name=_(u'Веб сайт')) + email = models.EmailField(blank=True, verbose_name=_(u'Email')) + foundation_year = models.PositiveIntegerField(blank=True, null=True, verbose_name=_(u'Год основания')) + total_capacity = models.PositiveIntegerField(blank=True, null=True, verbose_name=_(u'Общая вместимость')) + amount_halls = models.PositiveIntegerField(blank=True, null=True, verbose_name=_(u'Количество залов')) + exposition_hall = models.NullBooleanField(verbose_name=_(u'Выставочный зал')) + exp_hall_area = models.PositiveIntegerField(blank=True, null=True, verbose_name=_(u'Площадь выст. зала')) video_link = models.CharField(max_length=255, blank=True) + virtual_tour = models.URLField(blank=True, verbose_name=_(u'Виртуальный тур')) # wifi = models.NullBooleanField() multimedia_equipment = models.NullBooleanField() @@ -53,6 +63,7 @@ class PlaceConference(TranslatableModel, ExpoMixin): catering = models.NullBooleanField() hotel = models.NullBooleanField() # + logo = models.ImageField(verbose_name='Logo', upload_to=logo_name, blank=True, max_length=255) files = generic.GenericRelation('file.FileModel',content_type_field='content_type', object_id_field='object_id') #translations is translated fields translations = TranslatedFields( @@ -162,5 +173,5 @@ class Hall(models.Model): number = models.PositiveIntegerField(blank=True, null=True) capacity = models.PositiveIntegerField(blank=True, null=True) - +pre_save.connect(pre_save_handler, sender=PlaceConference) post_save.connect(post_save_handler, sender=PlaceConference) \ No newline at end of file diff --git a/place_exposition/forms.py b/place_exposition/forms.py index ad71fde8..c9b6cd6e 100644 --- a/place_exposition/forms.py +++ b/place_exposition/forms.py @@ -112,7 +112,7 @@ class ExpositionForm(forms.Form): else: place_exposition = obj - #simple fields + if not getattr(place_exposition, 'url'): if data.get('name_en'): place_exposition.url = translit_with_separator(data['name_en'].strip()).lower() @@ -252,30 +252,6 @@ class PlaceExpositionFormDelete(forms.ModelForm): model = PlaceExposition fields = ('url',) -''' -class HallForm(forms.ModelForm): - """ - form for Hall model - uses ModelForm cause Hall doesnt have translated fields - """ - number = forms.CharField(widget=forms.TextInput(attrs={'style': 'width:30px'}),required=False) - capacity = forms.CharField(widget=forms.TextInput(attrs={'style': 'width:60px'}), required=False) - name = forms.CharField(required=False) - class Meta: - model = Hall - exclude = ('place_exposition',) - - def clean_number(self): - cleaned_data = super(HallForm, self).clean() - number = cleaned_data.get('number').strip() - return is_positive_integer(number, 'Номер должен состоять из цифр') - - def clean_capacity(self): - cleaned_data = super(HallForm, self).clean() - capacity = cleaned_data.get('capacity').strip() - return is_positive_integer(capacity, 'Вместимость должна состоять из цифр') - -''' class HallForm(forms.Form): url = '/admin/place_exposition/add-hall/' diff --git a/place_exposition/models.py b/place_exposition/models.py index 78b329d8..f4fa2c47 100644 --- a/place_exposition/models.py +++ b/place_exposition/models.py @@ -39,6 +39,7 @@ class PlaceExposition(TranslatableModel, ExpoMixin): """ catalog = '/places/' + place = 'place_exposition' catalog_name = _(u'Места:') search_name = None #set manager of this model @@ -47,7 +48,7 @@ class PlaceExposition(TranslatableModel, ExpoMixin): url = models.SlugField(unique=True, max_length=255) country = models.ForeignKey('country.Country', on_delete=models.PROTECT) city = models.ForeignKey('city.City', on_delete=models.PROTECT, related_name='place_expositions') - photogallery = models.ForeignKey('photologue.Gallery', null=True, blank=True) + photogallery = models.ForeignKey('photologue.Gallery', null=True, blank=True, on_delete=models.SET_NULL) #type uses EnumField for creating Enum type field in Mysql database type = EnumField(values = [item1 for item1, item2 in EXPOSITION_TYPE]) #information @@ -289,17 +290,3 @@ def create_place(sender, instance, created, **kwargs): pre_save.connect(pre_save_handler, sender=PlaceExposition) post_save.connect(create_place, sender=PlaceExposition) post_save.connect(post_save_handler, sender=Hall) - - - - -""" -def calculate_rating_for_translations(sender, instance, created, **kwargs): - company = instance.master - post_save.disconnect(calculate_rating_for_translations, sender=Company._meta.translations_model) - calculate_rating(company) - post_save.connect(calculate_rating_for_translations, sender=Company._meta.translations_model) - -post_save.connect(create_company, sender=Company) -post_save.connect(calculate_rating_for_translations, sender=Company._meta.translations_model) -""" \ No newline at end of file diff --git a/place_exposition/views.py b/place_exposition/views.py index ba8f939a..66732911 100644 --- a/place_exposition/views.py +++ b/place_exposition/views.py @@ -80,7 +80,7 @@ class PlaceDetail(JitterCacheMixin, MetadataMixin, DetailView): obj = queryset.get() except queryset.model.DoesNotExist: try: - PlaceConference.objects.get(url=slug) + obj = PlaceConference.objects.get(url=slug) except PlaceConference.DoesNotExist: raise Http404(_("No %(verbose_name)s found matching the query") % @@ -94,9 +94,11 @@ class PlaceDetail(JitterCacheMixin, MetadataMixin, DetailView): context['country'] = str(obj.country_id) return context + class PlacePhoto(ListView): template_name = 'client/place/photo.html' obj = None + paginate_by = settings.CLIENT_PAGINATION def get_queryset(self): slug = self.kwargs.get('slug') @@ -109,7 +111,10 @@ class PlacePhoto(ListView): raise Http404(_("No %(verbose_name)s found matching the query") % {'verbose_name': PlaceExposition._meta.verbose_name}) self.obj = place - return place.photogallery.photos.all() + if place.photogallery: + return place.photogallery.photos.all() + else: + raise Http404() def get_context_data(self, **kwargs): context = super(PlacePhoto, self).get_context_data(**kwargs) @@ -122,7 +127,7 @@ class PlacePhoto(ListView): class PlaceList(JitterCacheMixin, MetadataMixin, ListView): model = PlaceExposition - paginate_by = 10 + paginate_by = settings.CLIENT_PAGINATION template_name = 'client/place/place_list.html' @@ -136,7 +141,7 @@ class PlaceList(JitterCacheMixin, MetadataMixin, ListView): class PlaceCatalog(JitterCacheMixin, MetadataMixin, ListView): cache_range = settings.CACHE_RANGE model = PlaceExposition - paginate_by = 10 + paginate_by = settings.CLIENT_PAGINATION template_name = 'client/place/catalog.html' filter_object = None diff --git a/proj/settings.py b/proj/settings.py index 5dded7d3..161dcb90 100644 --- a/proj/settings.py +++ b/proj/settings.py @@ -4,6 +4,7 @@ import os import django from django.utils.translation import ugettext_lazy as _ + DJANGO_ROOT = os.path.dirname(os.path.realpath(django.__file__)) SITE_ROOT = os.path.split(os.path.dirname(os.path.realpath(__file__)))[0] @@ -348,7 +349,6 @@ INSTALLED_APPS = ( 'translator', 'webinar', 'meta', - 'banners', #django modules 'sorl.thumbnail', # for logos 'photologue', # photogallery diff --git a/proj/urls.py b/proj/urls.py index ab09c7d5..71777d32 100644 --- a/proj/urls.py +++ b/proj/urls.py @@ -56,13 +56,11 @@ urlpatterns = patterns('', url(r'^', include('company.urls')), url(r'^', include('photoreport.urls')), url(r'^', include('article.urls')), - url(r'^country/', include('country.urls')), url(r'^city/', include('city.urls')), url(r'^organiser/', include('organiser.urls')), url(r'^gallery/', include('photologue.client_urls')), url(r'^', include('file.urls')), url(r'^', include('django_messages.expomap_urls')), - url(r'^messages/', include('django_messages.urls')), url(r'^advertising/$', AdvertisingView.as_view(), {'meta_id':58}), url(r'^about/$', AboutView.as_view(), {'meta_id':56}), url(r'^partners/$', AboutView.as_view(), {'meta_id':57}), @@ -73,7 +71,6 @@ urlpatterns = patterns('', url(r'^accounts/', include('registration.backends.default.urls')), url(r'^', include('password_reset.urls')), url(r'^i18n/', include('django.conf.urls.i18n')), - url(r'^redirect/', include('banners.urls')), url(r'^', include('settings.old_urls')), url(r'^', include('service.urls')), ) diff --git a/registration/backends/default/views.py b/registration/backends/default/views.py index 667ea2a3..bf4d2e1f 100644 --- a/registration/backends/default/views.py +++ b/registration/backends/default/views.py @@ -8,7 +8,8 @@ from registration import signals from registration.models import RegistrationProfile from registration.views import ActivationView as BaseActivationView from registration.views import RegistrationView as BaseRegistrationView -from django.views.generic import View +from accounts.forms import RegistrationCompleteForm, SocialRegistrationCompleteForm +from social.apps.django_app.default.models import UserSocialAuth import json @@ -248,8 +249,7 @@ def LoginView(request): else: HttpResponseRedirect('/') -from accounts.forms import RegistrationCompleteForm, RecoveryForm, SocialRegistrationCompleteForm -from social.apps.django_app.default.models import UserSocialAuth + def complete_registration(request): @@ -290,22 +290,4 @@ def acquire_email(request, template_name="registration/acquire_email.html"): def inactive_user_message(request): - return render(request, 'registration/social_registration_complete.html') - - - -def pswd_recovery(request): - #if request.is_ajax(): - response = {'success': False} - form = RecoveryForm(request.POST) - if form.is_valid(): - user = form.get_user() - user.se - response['success']=True - else: - response['errors'] = form.errors - return HttpResponse(json.dumps(response), content_type='application/json') - - #else: - # return HttpResponse('not ajax') - + return render(request, 'registration/social_registration_complete.html') \ No newline at end of file diff --git a/seminar/models.py b/seminar/models.py index f25ac9d5..14ba3096 100644 --- a/seminar/models.py +++ b/seminar/models.py @@ -14,7 +14,8 @@ from functions.models_methods import ExpoManager from functions.model_mixin import EventMixin, ExpoMixin # 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 [] +#flags = [str(item.id) for item in Service.objects.all()] if db_table_exists('service_service') else [] +flags = ['catalog', 'translator', 'participation', 'remote', 'tickets', 'visit', 'buildstand'] CURRENCY = ('RUB', 'USD', 'EUR') diff --git a/templates/admin/exposition/paid.html b/templates/admin/exposition/paid.html deleted file mode 100644 index 2345c4df..00000000 --- a/templates/admin/exposition/paid.html +++ /dev/null @@ -1,59 +0,0 @@ -{% extends 'base.html' %} -{% load static %} -{% load thumbnail %} - -{% block scripts %} - - - - -{% endblock %} - -{% block body %} -
{% csrf_token %} -
- {% if object %} Изменить {% else %} Добавить {% endif %}выставку{% if object %}(на сайте){% endif %} - -
-
-

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

-
-
-
- -
{{ form.org_logo }} - {{ form.org_logo.errors }} -
-
- -
- -
{{ form.oficial_link }} - {{ form.oficial_link.errors }} -
-
- -
- -
{{ form.participation_link }} - {{ form.participation_link.errors }} -
-
- -
- -
{{ form.tickets_link }} - {{ form.tickets_link.errors }} -
-
-
-
- -
- - -
-
-
- -{% endblock %} \ No newline at end of file diff --git a/templates/admin/includes/admin_nav.html b/templates/admin/includes/admin_nav.html index c89e71e1..d0135aa4 100644 --- a/templates/admin/includes/admin_nav.html +++ b/templates/admin/includes/admin_nav.html @@ -66,11 +66,8 @@ Импорт @@ -78,12 +75,11 @@ Экспорт diff --git a/templates/admin/includes/photo_form.html b/templates/admin/includes/photo_form.html index 92aa80c6..0244da32 100644 --- a/templates/admin/includes/photo_form.html +++ b/templates/admin/includes/photo_form.html @@ -14,6 +14,13 @@ +
+ +
{{ form.sort }} + {{ form.sort.errors }} +
+
+ {% with field='caption' form=form languages=languages %} {% include 'admin/forms/multilang.html' %} {% endwith %} diff --git a/templates/admin/photogallery/admin_gallery.html b/templates/admin/photogallery/admin_gallery.html index 4230176b..2f09274d 100644 --- a/templates/admin/photogallery/admin_gallery.html +++ b/templates/admin/photogallery/admin_gallery.html @@ -25,11 +25,10 @@

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

- {# description #} - {% include 'admin/forms/multilang.html' with field='description' form=form languages=languages %} {# title #} {% include 'admin/forms/multilang.html' with field='title' form=form languages=languages %} - + {# description #} + {% include 'admin/forms/multilang.html' with field='description' form=form languages=languages %}
diff --git a/templates/admin/photogallery/admin_photo.html b/templates/admin/photogallery/admin_photo.html index ded4b4e8..be7a3eaa 100644 --- a/templates/admin/photogallery/admin_photo.html +++ b/templates/admin/photogallery/admin_photo.html @@ -39,6 +39,14 @@
{% endif %} + {# sort #} +
+ +
+ {{ form.sort }} + {{ form.sort.errors }} +
+
{# caption #} {% include 'admin/forms/multilang.html' with field='caption' form=form languages=languages %} {# title #} diff --git a/templates/admin/photogallery/admin_photo_list.html b/templates/admin/photogallery/admin_photo_list.html index 6cfc93c7..c5723ca6 100644 --- a/templates/admin/photogallery/admin_photo_list.html +++ b/templates/admin/photogallery/admin_photo_list.html @@ -12,6 +12,7 @@ Заголовок     + @@ -19,20 +20,13 @@ {{ item.title }} - - {{ item.title }} - + Изменить - - - Копировать - - diff --git a/templates/admin/place_conference/place_conference.html b/templates/admin/place_conference/place_conference.html new file mode 100644 index 00000000..70d37f4f --- /dev/null +++ b/templates/admin/place_conference/place_conference.html @@ -0,0 +1,340 @@ +{% extends 'base.html' %} +{% load static %} +{% block styles %} +.hover{ + display:none; + margin-bottom:10px; + +} +.photo:hover .hover { + display: block; +} +{% endblock %} + +{% block scripts %} + + + {# google map не забыть скачать скрипты на локал #} + + + + + {# selects #} + + + + + {# ajax #} + + + + +{% endblock %} + +{% block body %} + +
{% csrf_token %} +
+ {% if object %} Изменить {% else %} Добавить {% endif %}место{% if object %}(на сайте){% endif %} + +
+
+

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

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

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

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

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

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

Услуги

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

Файлы

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

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

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

Мета данные

+
+
+ + {# keywords #} + {% with field='keywords' form=form languages=languages %} + {% include 'admin/forms/multilang.html' %} + {% endwith %} + {# title #} + {% with field='title' form=form languages=languages %} + {% include 'admin/forms/multilang.html' %} + {% endwith %} + {# descriptions #} + {% with field='descriptions' form=form languages=languages %} + {% include 'admin/forms/multilang.html' %} + {% endwith %} + +
+
+ + +
+ + +
+ +
+
+ + + + +{% include 'admin/includes/hall_form.html' with form=hall_form object=object %} +{% include 'admin/includes/photo_form.html' with form=photo_form object=object %} +{% include 'admin/includes/file_form.html' with file_form=file_form object=object %} + +{% endblock %} \ No newline at end of file diff --git a/templates/admin/place_conference/place_conference_list.html b/templates/admin/place_conference/place_conference_list.html index cd9c6233..b3f656ac 100644 --- a/templates/admin/place_conference/place_conference_list.html +++ b/templates/admin/place_conference/place_conference_list.html @@ -38,7 +38,7 @@ {% ifnotequal item.country None %}{{ item.country }} {% endifnotequal %} {% ifnotequal item.city None %}{{ item.city }} {% endifnotequal %} - + Изменить diff --git a/templates/client/accounts/feed.html b/templates/client/accounts/feed.html index 7b22e691..d3b7bd06 100644 --- a/templates/client/accounts/feed.html +++ b/templates/client/accounts/feed.html @@ -1,6 +1,7 @@ {% extends 'base_catalog.html' %} {% load i18n %} {% load static %} + {% block bread_scrumbs %}