правки по документу

remotes/origin/stage6
Alexander Burdeinyi 9 years ago
parent 1135ca5741
commit 61a86e9a1d
  1. 6
      accounts/admin.py
  2. 4
      article/models.py
  3. 5
      conference/views.py
  4. 7
      emencia/django/newsletter/forms.py
  5. 4
      emencia/django/newsletter/models.py
  6. 5
      exposition/views.py
  7. 30
      functions/model_mixin.py
  8. 17
      functions/models_methods.py
  9. 15
      functions/pipeline.py
  10. 5
      proj/middleware.py
  11. 1
      requirements.txt
  12. 4
      sortedm2m/__init__.py
  13. 353
      sortedm2m/fields.py
  14. 104
      sortedm2m/forms.py
  15. 0
      sortedm2m/models.py
  16. 7
      sortedm2m/static/sortedm2m/jquery-ui.js
  17. BIN
      sortedm2m/static/sortedm2m/selector-search.gif
  18. 50
      sortedm2m/static/sortedm2m/widget.css
  19. 91
      sortedm2m/static/sortedm2m/widget.js
  20. 23
      sortedm2m/templates/sortedm2m/sorted_checkbox_select_multiple_widget.html
  21. 7
      static/js/select2-4.0.3/js/select2.full.js
  22. 12
      support/d_dev/settings.py
  23. 8
      support/dev/settings.py
  24. 8
      support/prod/settings.py
  25. 23
      templates/c_admin/conference/conference.html
  26. 11
      templates/c_admin/forms/multilang.html
  27. 7
      templates/client/article/news.html
  28. 9
      templates/client/includes/conference/conference_partner.html
  29. 11
      templates/registration/acquire_email.html

@ -9,6 +9,7 @@ from hashlib import md5
from company.models import Company
from django.conf import settings
from django.contrib.auth.decorators import login_required
# from django.contrib import admin
from django.core.context_processors import csrf
from django.core.exceptions import ImproperlyConfigured
from django.http import HttpResponse, HttpResponseRedirect
@ -30,6 +31,11 @@ from functions.admin_views import AdminListView, AdminView, paginate_results
# models and forms
from .models import User
#
# class UserAdmin(admin.ModelAdmin):
# search_fields = ['email', ]
# admin.site.register(User, UserAdmin)
class DeleteAccount(DeleteView):
model = User

@ -270,13 +270,13 @@ class Article(TranslatableModel):
themes = self.theme.all().values_list('pk', flat=True)
exclude_pks = set([self.pk])
qs = model.objects.language()\
.filter(type=self.type, publish_date__isnull=False).order_by('-publish_date')
.filter(type=self.type, publish_date__isnull=False).distinct().order_by('-publish_date')
tags_sim = qs.filter(tag__in=tags).exclude(pk__in=exclude_pks)[:4]
exclude_pks.update([x.pk for x in tags_sim])
themes_sim = qs.filter(theme__in=themes).exclude(pk__in=exclude_pks)[:4]
exclude_pks.update([x.pk for x in themes_sim])
last_sim = qs.exclude(pk__in=exclude_pks)[:4]
result = list(chain(tags_sim, themes_sim, last_sim)[:4])
result = list(chain(tags_sim, themes_sim, last_sim))[:4]
self._similar = result
return self._similar

@ -33,7 +33,7 @@ from models import Conference
from note.models import Note
from service.models import Service
from service.order_forms import AdvertiseForm
from service.views import order_forms
from service.views import order_forms, get_userlog_data
from stats_collector.mixin import (
ConfSectionKindMixin,
ConfSectionMixin,
@ -406,7 +406,8 @@ class ConferenceServiceView(FormMixin, DetailView):
return context
def form_valid(self, form):
order = form.save(commit=False)
userlog = get_userlog_data(self.request)
order = form.save(commit=False, userlog=userlog)
order.conference = self.object
order.save()
messages.success(self.request, _(u'Ваш запрос был успешно отправлен'))

@ -12,6 +12,7 @@ from django.utils import translation
from django.utils.translation import ugettext_lazy as _
from django.utils.translation import get_language
from django.utils.encoding import smart_text, force_text
from django.conf import settings
from conference.models import Conference
from exposition.models import Exposition
@ -163,6 +164,12 @@ class MailingSettingsForm(forms.ModelForm):
obj.f_countries = self.cleaned_data.get('co')
obj.area = areas
obj.r_cities = self.cleaned_data.get('r_cities') or []
if obj.moscow and not settings.MOSCOW_PK in obj.r_cities:
obj.r_cities.add(settings.MOSCOW_PK)
if not obj.moscow and settings.MOSCOW_PK in obj.r_cities:
obj.moscow = True
obj.tags = self.cleaned_data.get('tg') or []
obj.themes = self.cleaned_data.get('th') or []
obj.from_users = False

@ -164,8 +164,8 @@ class Contact(models.Model):
periodic_day = models.PositiveSmallIntegerField(_(u'День отправки'),
choices=PERIODIC_DAY_CHOICES, default=PERIODIC_DAY_CHOICES.WED)
content_news = models.BooleanField(_(u'Новости событий'), blank=True, default=True)
content_overview = models.BooleanField(_(u'Обзоры'), blank=True, default=True)
content_articles = models.BooleanField(_(u'Статьи из блога по участию в вывставках'), blank=True, default=True)
content_overview = models.BooleanField(_(u'Статьи для экспонентов'), blank=True, default=True)
content_articles = models.BooleanField(_(u'Статьи для организаторов событий'), blank=True, default=True)
tags = models.ManyToManyField('theme.Tag', verbose_name=_(u'Теги'), blank=True, null=True)
themes = models.ManyToManyField('theme.Theme', blank=True, null=True, verbose_name=_(u'Тематики'))

@ -32,7 +32,7 @@ from models import Exposition
from note.models import Note
from service.models import Service
from service.order_forms import AdvertiseForm
from service.views import order_forms
from service.views import order_forms, get_userlog_data
# from stats_collector.models import SectionStats
from stats_collector.mixin import (
ExpoSectionKindMixin,
@ -327,7 +327,8 @@ class ExpositionServiceView(JitterCacheMixin, MetadataMixin, FormMixin, DetailVi
return context
def form_valid(self, form):
order = form.save(commit=False)
userlog = get_userlog_data(self.request)
order = form.save(commit=False, userlog=userlog)
order.exposition = self.object
order.save()
return HttpResponseRedirect(self.object.get_permanent_url()+'service/thanks/')

@ -114,29 +114,39 @@ class EventMixin(object):
}
return ctx
def get_nearest_events(self):
if getattr(self, '_nearest_events', None) is None:
model = self.__class__
result = []
tags = self.tag.all().values_list('pk', flat=True)
themes = self.theme.all().values_list('pk', flat=True)
def get_nearest_events_incl(self, _qs, tags, themes, exclude=None):
now = datetime.datetime.now()
month = now + relativedelta(months=1)
month2 = now + relativedelta(months=2)
exclude_pks = set([self.pk])
exclude_pks = exclude or set([self.pk])
events_m2 = []
events_m = []
events = []
for params in [{'tag__in': tags}, {'theme__in': themes}]:
qs = model.objects.language().filter(**params).order_by('data_begin')
qs = _qs.filter(**params).order_by('data_begin')
events_m2.extend(qs.filter(data_begin__gte=month2).exclude(pk__in=exclude_pks)[:3])
exclude_pks.update([x.pk for x in events_m2])
events_m.extend(qs.filter(data_begin__gte=month).exclude(pk__in=exclude_pks)[:3])
exclude_pks.update([x.pk for x in events_m])
events.extend(qs.filter(data_begin__gte=now).exclude(pk__in=exclude_pks)[:3])
exclude_pks.update([x.pk for x in events])
result = list(sorted((chain(zip(*[x for x in [events_m2, events_m, events] if x]))[:3]), key=lambda x: x.data_begin))
self._nearest_events = result
return (list(
sorted((chain(zip(*[x for x in [events_m2, events_m, events] if x]))[:3]), key=lambda x: x.data_begin)),
exclude_pks)
def get_nearest_events(self):
if getattr(self, '_nearest_events', None) is None:
model = self.__class__
result = []
tags = self.tag.all().values_list('pk', flat=True)
themes = self.theme.all().values_list('pk', flat=True)
qs = model.objects.language().filter(country_id=self.country_id)
result, exclude = self.get_nearest_events_incl(qs, tags, themes)
if len(result) > 3:
qs = model.objects.language()
r, e = self.get_nearest_events_incl(qs, tags, themes, exclude)
result += r
self._nearest_events = result[:3]
return self._nearest_events
def get_nearest_events_url(self):

@ -192,12 +192,21 @@ class CityManager(TranslationManager):
if cached and key in cache:
cities = cache.get(key)
else:
cities = list(
self.language(lang).filter(
cities = []
popular_cities = []
_cities = self.language(lang).filter(
country__url='russia', exposition_city__isnull=False,
conference_city__isnull=False
).exclude(pk=settings.MOSCOW_PK).distinct().order_by('name').values_list('pk', 'name')
)
).distinct().order_by('name').values_list('pk', 'name')
for city in _cities:
if city[0] == settings.MOSCOW_PK:
popular_cities.insert(0, city)
elif city[0] == settings.SPB_PK:
popular_cities.append(city)
else:
cities.append(city)
# .exclude(pk=settings.MOSCOW_PK)
cities = popular_cities + cities
cache.set(key, cities, self.cache_time)
return cities

@ -78,6 +78,21 @@ def require_email(strategy, details, user=None, is_new=False, *args, **kwargs):
return
def social_user(backend, uid, user=None, *args, **kwargs):
provider = backend.name
social = backend.strategy.storage.user.get_social_auth(provider, uid)
if social:
# if user and social.user != user:
# msg = 'This {0} account is already in use.'.format(provider)
# raise AuthAlreadyAssociated(backend, msg)
# elif not user:
user = social.user
return {'social': social,
'user': user,
'is_new': user is None,
'new_association': social is None}
def SendVerificationEmail(strategy, backend, code):
"""
Send an email with an embedded verification code and the necessary details to restore the required session

@ -54,12 +54,17 @@ class Referer(object):
for key, val in data_exists.iteritems():
if val:
if key == 'search':
print(request.session.get('search', []))
print(request.session.get('search', []))[-2:]
search = request.session.get('search', [])[-2:]
search.append(val)
request.session['search'] = search
try:
if userlog is not None:
for i, d in enumerate(search, start=1):
setattr(userlog, key + str(i), d)
except Exception as e:
print(e)
else:
attr1 = key + '1'
attr2 = key + '2'

@ -17,6 +17,7 @@ django-redis==4.0.0
django-redis-cache==0.13.1
django-sortedm2m==1.2.0
django-tinymce==2.0.5
django-widget-tweaks==1.4.1
djutils==0.3.2
docutils==0.12
fpconst==0.7.2

@ -0,0 +1,4 @@
# -*- coding: utf-8 -*-
__version__ = '0.7.0'

@ -0,0 +1,353 @@
# -*- coding: utf-8 -*-
from operator import attrgetter
import sys
from django.db import connections
from django.db import router
from django.db.models import signals
from django.db.models.fields.related import add_lazy_relation, create_many_related_manager
from django.db.models.fields.related import ManyToManyField, ReverseManyRelatedObjectsDescriptor
from django.db.models.fields.related import RECURSIVE_RELATIONSHIP_CONSTANT
from django.conf import settings
from django.utils.functional import curry
from sortedm2m.forms import SortedMultipleChoiceField
if sys.version_info[0] < 3:
string_types = basestring
else:
string_types = str
SORT_VALUE_FIELD_NAME = 'sort_value'
def create_sorted_many_to_many_intermediate_model(field, klass):
from django.db import models
managed = True
if isinstance(field.rel.to, string_types) and field.rel.to != RECURSIVE_RELATIONSHIP_CONSTANT:
to_model = field.rel.to
to = to_model.split('.')[-1]
def set_managed(field, model, cls):
field.rel.through._meta.managed = model._meta.managed or cls._meta.managed
add_lazy_relation(klass, field, to_model, set_managed)
elif isinstance(field.rel.to, string_types):
to = klass._meta.object_name
to_model = klass
managed = klass._meta.managed
else:
to = field.rel.to._meta.object_name
to_model = field.rel.to
managed = klass._meta.managed or to_model._meta.managed
name = '%s_%s' % (klass._meta.object_name, field.name)
if field.rel.to == RECURSIVE_RELATIONSHIP_CONSTANT or to == klass._meta.object_name:
from_ = 'from_%s' % to.lower()
to = 'to_%s' % to.lower()
else:
from_ = klass._meta.object_name.lower()
to = to.lower()
meta = type(str('Meta'), (object,), {
'db_table': field._get_m2m_db_table(klass._meta),
'managed': managed,
'auto_created': klass,
'app_label': klass._meta.app_label,
'unique_together': (from_, to),
'ordering': (field.sort_value_field_name,),
'verbose_name': '%(from)s-%(to)s relationship' % {'from': from_, 'to': to},
'verbose_name_plural': '%(from)s-%(to)s relationships' % {'from': from_, 'to': to},
})
# Construct and return the new class.
def default_sort_value(name):
model = models.get_model(klass._meta.app_label, name)
return model._default_manager.count()
default_sort_value = curry(default_sort_value, name)
return type(str(name), (models.Model,), {
'Meta': meta,
'__module__': klass.__module__,
from_: models.ForeignKey(klass, related_name='%s+' % name),
to: models.ForeignKey(to_model, related_name='%s+' % name),
field.sort_value_field_name: models.IntegerField(default=default_sort_value),
'_sort_field_name': field.sort_value_field_name,
'_from_field_name': from_,
'_to_field_name': to,
})
def create_sorted_many_related_manager(superclass, rel):
RelatedManager = create_many_related_manager(superclass, rel)
class SortedRelatedManager(RelatedManager):
def get_query_set(self):
# We use ``extra`` method here because we have no other access to
# the extra sorting field of the intermediary model. The fields
# are hidden for joins because we set ``auto_created`` on the
# intermediary's meta options.
try:
return self.instance._prefetched_objects_cache[self.prefetch_cache_name]
except (AttributeError, KeyError):
return super(SortedRelatedManager, self).\
get_query_set().\
extra(order_by=['%s.%s' % (
rel.through._meta.db_table,
rel.through._sort_field_name,
)])
if not hasattr(RelatedManager, '_get_fk_val'):
@property
def _fk_val(self):
return self._pk_val
def get_prefetch_query_set(self, instances):
# mostly a copy of get_prefetch_query_set from ManyRelatedManager
# but with addition of proper ordering
db = self._db or router.db_for_read(instances[0].__class__, instance=instances[0])
query = {'%s__pk__in' % self.query_field_name:
set(obj._get_pk_val() for obj in instances)}
qs = super(RelatedManager, self).get_query_set().using(db)._next_is_sticky().filter(**query)
# M2M: need to annotate the query in order to get the primary model
# that the secondary model was actually related to. We know that
# there will already be a join on the join table, so we can just add
# the select.
# For non-autocreated 'through' models, can't assume we are
# dealing with PK values.
fk = self.through._meta.get_field(self.source_field_name)
source_col = fk.column
join_table = self.through._meta.db_table
connection = connections[db]
qn = connection.ops.quote_name
qs = qs.extra(select={'_prefetch_related_val':
'%s.%s' % (qn(join_table), qn(source_col))},
order_by=['%s.%s' % (
rel.through._meta.db_table,
rel.through._sort_field_name,
)])
select_attname = fk.rel.get_related_field().get_attname()
return (qs,
attrgetter('_prefetch_related_val'),
attrgetter(select_attname),
False,
self.prefetch_cache_name)
def _add_items(self, source_field_name, target_field_name, *objs):
# source_field_name: the PK fieldname in join_table for the source object
# target_field_name: the PK fieldname in join_table for the target object
# *objs - objects to add. Either object instances, or primary keys of object instances.
# If there aren't any objects, there is nothing to do.
from django.db.models import Model
if objs:
new_ids = []
for obj in objs:
if isinstance(obj, self.model):
if not router.allow_relation(obj, self.instance):
raise ValueError('Cannot add "%r": instance is on database "%s", value is on database "%s"' %
(obj, self.instance._state.db, obj._state.db))
if hasattr(self, '_get_fk_val'): # Django>=1.5
fk_val = self._get_fk_val(obj, target_field_name)
if fk_val is None:
raise ValueError('Cannot add "%r": the value for field "%s" is None' %
(obj, target_field_name))
new_ids.append(self._get_fk_val(obj, target_field_name))
else: # Django<1.5
new_ids.append(obj.pk)
elif isinstance(obj, Model):
raise TypeError("'%s' instance expected, got %r" % (self.model._meta.object_name, obj))
else:
new_ids.append(obj)
db = router.db_for_write(self.through, instance=self.instance)
vals = self.through._default_manager.using(db).values_list(target_field_name, flat=True)
vals = vals.filter(**{
source_field_name: self._fk_val,
'%s__in' % target_field_name: new_ids,
})
for val in vals:
if val in new_ids:
new_ids.remove(val)
_new_ids = []
for pk in new_ids:
if pk not in _new_ids:
_new_ids.append(pk)
new_ids = _new_ids
new_ids_set = set(new_ids)
if self.reverse or source_field_name == self.source_field_name:
# Don't send the signal when we are inserting the
# duplicate data row for symmetrical reverse entries.
signals.m2m_changed.send(sender=rel.through, action='pre_add',
instance=self.instance, reverse=self.reverse,
model=self.model, pk_set=new_ids_set, using=db)
# Add the ones that aren't there already
sort_field_name = self.through._sort_field_name
sort_field = self.through._meta.get_field_by_name(sort_field_name)[0]
for obj_id in new_ids:
self.through._default_manager.using(db).create(**{
'%s_id' % source_field_name: self._fk_val, # Django 1.5 compatibility
'%s_id' % target_field_name: obj_id,
sort_field_name: sort_field.get_default(),
})
if self.reverse or source_field_name == self.source_field_name:
# Don't send the signal when we are inserting the
# duplicate data row for symmetrical reverse entries.
signals.m2m_changed.send(sender=rel.through, action='post_add',
instance=self.instance, reverse=self.reverse,
model=self.model, pk_set=new_ids_set, using=db)
return SortedRelatedManager
class ReverseSortedManyRelatedObjectsDescriptor(ReverseManyRelatedObjectsDescriptor):
@property
def related_manager_cls(self):
return create_sorted_many_related_manager(
self.field.rel.to._default_manager.__class__,
self.field.rel
)
class SortedManyToManyField(ManyToManyField):
'''
Providing a many to many relation that remembers the order of related
objects.
Accept a boolean ``sorted`` attribute which specifies if relation is
ordered or not. Default is set to ``True``. If ``sorted`` is set to
``False`` the field will behave exactly like django's ``ManyToManyField``.
'''
def __init__(self, to, sorted=True, **kwargs):
self.sorted = sorted
self.sort_value_field_name = kwargs.pop(
'sort_value_field_name',
SORT_VALUE_FIELD_NAME)
super(SortedManyToManyField, self).__init__(to, **kwargs)
if self.sorted:
self.help_text = kwargs.get('help_text', None)
def contribute_to_class(self, cls, name):
if not self.sorted:
return super(SortedManyToManyField, self).contribute_to_class(cls, name)
# To support multiple relations to self, it's useful to have a non-None
# related name on symmetrical relations for internal reasons. The
# concept doesn't make a lot of sense externally ("you want me to
# specify *what* on my non-reversible relation?!"), so we set it up
# automatically. The funky name reduces the chance of an accidental
# clash.
if self.rel.symmetrical and (self.rel.to == "self" or self.rel.to == cls._meta.object_name):
self.rel.related_name = "%s_rel_+" % name
super(ManyToManyField, self).contribute_to_class(cls, name)
# The intermediate m2m model is not auto created if:
# 1) There is a manually specified intermediate, or
# 2) The class owning the m2m field is abstract.
if not self.rel.through and not cls._meta.abstract:
self.rel.through = create_sorted_many_to_many_intermediate_model(self, cls)
# Add the descriptor for the m2m relation
setattr(cls, self.name, ReverseSortedManyRelatedObjectsDescriptor(self))
# Set up the accessor for the m2m table name for the relation
self.m2m_db_table = curry(self._get_m2m_db_table, cls._meta)
# Populate some necessary rel arguments so that cross-app relations
# work correctly.
if isinstance(self.rel.through, string_types):
def resolve_through_model(field, model, cls):
field.rel.through = model
add_lazy_relation(cls, self, self.rel.through, resolve_through_model)
if hasattr(cls._meta, 'duplicate_targets'): # Django<1.5
if isinstance(self.rel.to, string_types):
target = self.rel.to
else:
target = self.rel.to._meta.db_table
cls._meta.duplicate_targets[self.column] = (target, "m2m")
def formfield(self, **kwargs):
defaults = {}
if self.sorted:
defaults['form_class'] = SortedMultipleChoiceField
defaults.update(kwargs)
return super(SortedManyToManyField, self).formfield(**defaults)
# Add introspection rules for South database migrations
# See http://south.aeracode.org/docs/customfields.html
try:
import south
except ImportError:
south = None
if south is not None and 'south' in settings.INSTALLED_APPS:
from south.modelsinspector import add_introspection_rules
add_introspection_rules(
[(
(SortedManyToManyField,),
[],
{"sorted": ["sorted", {"default": True}]},
)],
[r'^sortedm2m\.fields\.SortedManyToManyField']
)
# Monkeypatch South M2M actions to create the sorted through model.
# FIXME: This doesn't detect if you changed the sorted argument to the field.
import south.creator.actions
from south.creator.freezer import model_key
class AddM2M(south.creator.actions.AddM2M):
SORTED_FORWARDS_TEMPLATE = '''
# Adding SortedM2M table for field %(field_name)s on '%(model_name)s'
db.create_table(%(table_name)r, (
('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True)),
(%(left_field)r, models.ForeignKey(orm[%(left_model_key)r], null=False)),
(%(right_field)r, models.ForeignKey(orm[%(right_model_key)r], null=False)),
(%(sort_field)r, models.IntegerField())
))
db.create_unique(%(table_name)r, [%(left_column)r, %(right_column)r])'''
def console_line(self):
if isinstance(self.field, SortedManyToManyField) and self.field.sorted:
return " + Added SortedM2M table for %s on %s.%s" % (
self.field.name,
self.model._meta.app_label,
self.model._meta.object_name,
)
else:
return super(AddM2M, self).console_line()
def forwards_code(self):
if isinstance(self.field, SortedManyToManyField) and self.field.sorted:
return self.SORTED_FORWARDS_TEMPLATE % {
"model_name": self.model._meta.object_name,
"field_name": self.field.name,
"table_name": self.field.m2m_db_table(),
"left_field": self.field.m2m_column_name()[:-3], # Remove the _id part
"left_column": self.field.m2m_column_name(),
"left_model_key": model_key(self.model),
"right_field": self.field.m2m_reverse_name()[:-3], # Remove the _id part
"right_column": self.field.m2m_reverse_name(),
"right_model_key": model_key(self.field.rel.to),
"sort_field": self.field.sort_value_field_name,
}
else:
return super(AddM2M, self).forwards_code()
class DeleteM2M(AddM2M):
def console_line(self):
return " - Deleted M2M table for %s on %s.%s" % (
self.field.name,
self.model._meta.app_label,
self.model._meta.object_name,
)
def forwards_code(self):
return AddM2M.backwards_code(self)
def backwards_code(self):
return AddM2M.forwards_code(self)
south.creator.actions.AddM2M = AddM2M
south.creator.actions.DeleteM2M = DeleteM2M

@ -0,0 +1,104 @@
# -*- coding: utf-8 -*-
import sys
from itertools import chain
from django import forms
from django.conf import settings
from django.db.models.query import QuerySet
from django.template.loader import render_to_string
from django.utils.encoding import force_text
from django.utils.html import conditional_escape, escape
from django.utils.safestring import mark_safe
if sys.version_info[0] < 3:
iteritems = lambda d: iter(d.iteritems())
string_types = basestring,
str_ = unicode
else:
iteritems = lambda d: iter(d.items())
string_types = str,
str_ = str
STATIC_URL = getattr(settings, 'STATIC_URL', settings.MEDIA_URL)
class SortedCheckboxSelectMultiple(forms.CheckboxSelectMultiple):
class Media:
js = (
STATIC_URL + 'sortedm2m/widget.js',
STATIC_URL + 'sortedm2m/jquery-ui.js',
)
css = {'screen': (
STATIC_URL + 'sortedm2m/widget.css',
)}
def build_attrs(self, attrs=None, **kwargs):
attrs = super(SortedCheckboxSelectMultiple, self).\
build_attrs(attrs, **kwargs)
classes = attrs.setdefault('class', '').split()
classes.append('sortedm2m')
attrs['class'] = ' '.join(classes)
return attrs
def render(self, name, value, attrs=None, choices=()):
if value is None: value = []
has_id = attrs and 'id' in attrs
final_attrs = self.build_attrs(attrs, name=name)
# Normalize to strings
str_values = [force_text(v) for v in value]
selected = []
unselected = []
for i, (option_value, option_label) in enumerate(chain(self.choices, choices)):
# If an ID attribute was given, add a numeric index as a suffix,
# so that the checkboxes don't all have the same ID attribute.
if has_id:
final_attrs = dict(final_attrs, id='%s_%s' % (attrs['id'], i))
label_for = ' for="%s"' % conditional_escape(final_attrs['id'])
else:
label_for = ''
cb = forms.CheckboxInput(final_attrs, check_test=lambda value: value in str_values)
option_value = force_text(option_value)
rendered_cb = cb.render(name, option_value)
option_label = conditional_escape(force_text(option_label))
item = {'label_for': label_for, 'rendered_cb': rendered_cb, 'option_label': option_label, 'option_value': option_value}
if option_value in str_values:
selected.append(item)
else:
unselected.append(item)
# re-order `selected` array according str_values which is a set of `option_value`s in the order they should be shown on screen
ordered = []
for value in str_values:
for select in selected:
if value == select['option_value']:
ordered.append(select)
selected = ordered
html = render_to_string(
'sortedm2m/sorted_checkbox_select_multiple_widget.html',
{'selected': selected, 'unselected': unselected})
return mark_safe(html)
def value_from_datadict(self, data, files, name):
value = data.get(name, None)
if isinstance(value, string_types):
return [v for v in value.split(',') if v]
return value
class SortedMultipleChoiceField(forms.ModelMultipleChoiceField):
widget = SortedCheckboxSelectMultiple
def clean(self, value):
queryset = super(SortedMultipleChoiceField, self).clean(value)
if value is None or not isinstance(queryset, QuerySet):
return queryset
object_list = dict((
(str_(key), value)
for key, value in iteritems(queryset.in_bulk(value))))
return [object_list[str_(pk)] for pk in value]

File diff suppressed because one or more lines are too long

Binary file not shown.

After

Width:  |  Height:  |  Size: 552 B

@ -0,0 +1,50 @@
.sortedm2m-container {
margin-right: 10px;
width: 570px;
}
.sortedm2m-container p.selector-filter {
width: 570px;
padding: 0;
margin: 0;
}
.sortedm2m-container p.selector-filter input {
width: 532px;
margin: 5px 4px;
}
ul.sortedm2m {
display: block;
width: 554px;
min-height: 200px;
max-height: 400px;
overflow-x: hidden;
overflow-y: auto;
margin: 0;
padding: 6px 8px;
list-style-type: none;
text-align: left;
}
ul.sortedm2m li {
list-style-type: none;
text-align: left;
width: 550px;
overflow: hidden;
text-overflow: ellipsis;
white-space: pre;
}
ul.sortedm2m li, ul.sortedm2m label {
cursor: move;
}
/* required to work properly in django admin */
body.change-form .sortedm2m-container {
float: left;
}
.module ul.sortedm2m {
margin: 0;
padding: 6px 8px;
}

@ -0,0 +1,91 @@
if (jQuery === undefined) {
jQuery = django.jQuery;
}
(function ($) {
$(function () {
$('.sortedm2m').parents('ul').each(function () {
$(this).addClass('sortedm2m');
var checkboxes = $(this).find('input[type=checkbox]');
var id = checkboxes.first().attr('id').match(/^(.*)_\d+$/)[1];
var name = checkboxes.first().attr('name');
checkboxes.removeAttr('name');
$(this).before('<input type="hidden" id="' + id + '" name="' + name + '" />');
var that = this;
var recalculate_value = function () {
var values = [];
$(that).find(':checked').each(function () {
values.push($(this).val());
});
$('#' + id).val(values.join(','));
}
recalculate_value();
checkboxes.change(recalculate_value);
$(this).sortable({
axis: 'y',
//containment: 'parent',
update: recalculate_value
});
});
$('.sortedm2m-container .selector-filter input').each(function () {
$(this).bind('input', function() {
var search = $(this).val().toLowerCase();
var $el = $(this).closest('.selector-filter');
var $container = $el.siblings('ul').each(function() {
// walk over each child list el and do name comparisons
$(this).children().each(function() {
var curr = $(this).find('label').text().toLowerCase();
if (curr.indexOf(search) === -1) {
$(this).css('display', 'none');
} else {
$(this).css('display', 'inherit');
};
});
});
});
});
if (window.showAddAnotherPopup) {
var django_dismissAddAnotherPopup = window.dismissAddAnotherPopup;
window.dismissAddAnotherPopup = function (win, newId, newRepr) {
// newId and newRepr are expected to have previously been escaped by
// django.utils.html.escape.
newId = html_unescape(newId);
newRepr = html_unescape(newRepr);
var name = windowname_to_id(win.name);
var elem = $('#' + name);
var sortedm2m = elem.siblings('ul.sortedm2m');
if (sortedm2m.length == 0) {
// no sortedm2m widget, fall back to django's default
// behaviour
return django_dismissAddAnotherPopup.apply(this, arguments);
}
if (elem.val().length > 0) {
elem.val(elem.val() + ',');
}
elem.val(elem.val() + newId);
var id_template = '';
var maxid = 0;
sortedm2m.find('li input').each(function () {
var match = this.id.match(/^(.+)_(\d+)$/);
id_template = match[1];
id = parseInt(match[2]);
if (id > maxid) maxid = id;
});
var id = id_template + '_' + (maxid + 1);
var new_li = $('<li/>').append(
$('<label/>').attr('for', id).append(
$('<input class="sortedm2m" type="checkbox" checked="checked" />').attr('id', id).val(newId)
).append($('<span/>').text(' ' + newRepr))
);
sortedm2m.append(new_li);
win.close();
};
}
});
})(jQuery);

@ -0,0 +1,23 @@
{% load i18n static %}
<div class="sortedm2m-container">
<p class="selector-filter">
<img src="{% static "sortedm2m/selector-search.gif" %}" alt="" title="{% trans "Type into this box to filter down the list." %}" />
<input type="text" placeholder="{% trans "Filter" %}" />
</p>
<ul>
{% for row in selected %}
<li><label{{ row.label_for|safe }}>{{ row.rendered_cb }} {{ row.option_label }}</label></li>
{% endfor %}
{% for row in unselected %}
<li><label{{ row.label_for|safe }}>{{ row.rendered_cb }} {{ row.option_label }}</label></li>
{% endfor %}
</ul>
<p class="help">
{% trans "Choose items and order by drag & drop." %}
</p>
</div>

@ -1,3 +1,10 @@
/*!
* Select2 4.0.3
* https://select2.github.io
*
* Released under the MIT license
* https://github.com/select2/select2/blob/master/LICENSE.md
*/
/*!
* Select2 4.0.3
* https://select2.github.io

@ -154,10 +154,11 @@ MIDDLEWARE_CLASSES = (
'django.contrib.messages.middleware.MessageMiddleware',
'social.apps.django_app.middleware.SocialAuthExceptionMiddleware',
# 'django.middleware.cache.FetchFromCacheMiddleware',
# Uncomment the next line for simple clickjacking protection:
'django.middleware.clickjacking.XFrameOptionsMiddleware',
'proj.middleware.Referer',
'django.contrib.redirects.middleware.RedirectFallbackMiddleware',
'proj.middleware.ExpoRedirectFallbackMiddleware',
'proj.middleware.SpacelessMiddleware',
)
@ -259,9 +260,12 @@ SOCIAL_AUTH_USERNAME_IS_FULL_EMAIL = True
SOCIAL_AUTH_PIPELINE = (
'social.pipeline.social_auth.social_details',
'social.pipeline.social_auth.social_uid',
'functions.pipeline.get_email', # vk
'functions.pipeline.load_user',
'social.pipeline.social_auth.auth_allowed',
'social.pipeline.social_auth.social_user',
'functions.pipeline.social_user',
# 'social.pipeline.social_auth.social_user',
'social.pipeline.social_auth.load_extra_data',
'social.pipeline.user.get_username',
'functions.pipeline.require_email',
#'social.pipeline.mail.mail_validation',
@ -269,7 +273,6 @@ SOCIAL_AUTH_PIPELINE = (
#'social.pipeline.user.create_user',
'social.pipeline.social_auth.associate_by_email',
'social.pipeline.social_auth.associate_user',
'social.pipeline.social_auth.load_extra_data',
'social.pipeline.user.user_details'
)
@ -377,6 +380,8 @@ INSTALLED_APPS = (
'specialist_catalog',
'south',
'rosetta',
'widget_tweaks',
)
CRONJOBS = [
@ -499,6 +504,7 @@ MONTHES = {'jan': {'value': 1, 'name': _(u'Январь')}, 'feb': {'value': 2,
SNG_COUNTRIES = [159, 186, 31, 6, 99, 13, 189, 64]
RUSSIA_PK = 159
MOSCOW_PK = -2960561
SPB_PK = -2996338
CLIENT_DATE_FORMAT = ["%d.%m.%Y"]

@ -151,8 +151,8 @@ MIDDLEWARE_CLASSES = (
'django.contrib.messages.middleware.MessageMiddleware',
'social.apps.django_app.middleware.SocialAuthExceptionMiddleware',
# 'django.middleware.cache.FetchFromCacheMiddleware',
# Uncomment the next line for simple clickjacking protection:
'django.middleware.clickjacking.XFrameOptionsMiddleware',
'proj.middleware.Referer',
'django.contrib.redirects.middleware.RedirectFallbackMiddleware',
'proj.middleware.ExpoRedirectFallbackMiddleware',
'proj.middleware.SpacelessMiddleware',
@ -260,7 +260,8 @@ SOCIAL_AUTH_PIPELINE = (
'functions.pipeline.get_email', # vk
'functions.pipeline.load_user',
'social.pipeline.social_auth.auth_allowed',
'social.pipeline.social_auth.social_user',
'functions.pipeline.social_user',
# 'social.pipeline.social_auth.social_user',
'social.pipeline.social_auth.load_extra_data',
'social.pipeline.user.get_username',
'functions.pipeline.require_email',
@ -378,6 +379,8 @@ INSTALLED_APPS = (
'specialist_catalog',
'south',
'rosetta',
'widget_tweaks',
)
CRONJOBS = [
@ -501,6 +504,7 @@ MONTHES = {'jan': {'value': 1, 'name': _(u'Январь')}, 'feb': {'value': 2,
SNG_COUNTRIES = [159, 186, 31, 6, 99, 13, 189, 64]
RUSSIA_PK = 159
MOSCOW_PK = -2960561
SPB_PK = -2996338
CLIENT_DATE_FORMAT = ["%d.%m.%Y"]

@ -151,8 +151,8 @@ MIDDLEWARE_CLASSES = (
'django.contrib.messages.middleware.MessageMiddleware',
'social.apps.django_app.middleware.SocialAuthExceptionMiddleware',
# 'django.middleware.cache.FetchFromCacheMiddleware',
# Uncomment the next line for simple clickjacking protection:
'django.middleware.clickjacking.XFrameOptionsMiddleware',
'proj.middleware.Referer',
'django.contrib.redirects.middleware.RedirectFallbackMiddleware',
'proj.middleware.ExpoRedirectFallbackMiddleware',
'proj.middleware.SpacelessMiddleware',
@ -260,7 +260,8 @@ SOCIAL_AUTH_PIPELINE = (
'functions.pipeline.get_email', # vk
'functions.pipeline.load_user',
'social.pipeline.social_auth.auth_allowed',
'social.pipeline.social_auth.social_user',
'functions.pipeline.social_user',
# 'social.pipeline.social_auth.social_user',
'social.pipeline.social_auth.load_extra_data',
'social.pipeline.user.get_username',
'functions.pipeline.require_email',
@ -378,6 +379,8 @@ INSTALLED_APPS = (
'specialist_catalog',
'south',
'rosetta',
'widget_tweaks',
)
CRONJOBS = [
@ -500,6 +503,7 @@ MONTHES = {'jan': {'value': 1, 'name': _(u'Январь')}, 'feb': {'value': 2,
SNG_COUNTRIES = [159, 186, 31, 6, 99, 13, 189, 64]
RUSSIA_PK = 159
MOSCOW_PK = -2960561
SPB_PK = -2996338
CLIENT_DATE_FORMAT = ["%d.%m.%Y"]

@ -109,7 +109,13 @@
{# return undefined;#}
{# },#}
});
{##}
{# $('#id_tag, #id_theme, #id_city, #id_country, #id_place_conference').on('select2-open', function () {#}
{# $('#id_audience').prop("disabled", true);#}
{# });#}
{# $('#id_tag, #id_theme, #id_city, #id_country, #id_place_conference').on('select2-close', function () {#}
{# $('#id_audience').prop("disabled", false);#}
{# });#}
});
</script>
@ -151,7 +157,13 @@
<span class="help-inline">{{ form.data_end.errors }}</span>
</div>
</div>
{# audience #}
<div class="control-group {% if form.audience.errors %}error{% endif %}">
<label class="control-label">{{ form.audience.label }}:</label>
<div class="controls">{{ form.audience }}
<span class="help-inline">{{ form.audience.errors }}</span>
</div>
</div>
{# country #}
<div class="control-group {% if form.country.errors %}error{% endif %}">
<label class="control-label"><b>{{ form.country.label }}:</b></label>
@ -201,13 +213,6 @@
<span class="help-inline">{{ form.speakers.errors }}</span>
</div>
</div>
{# audience #}
<div class="control-group {% if form.audience.errors %}error{% endif %}">
<label class="control-label">{{ form.audience.label }}:</label>
<div class="controls">{{ form.audience }}
<span class="help-inline">{{ form.audience.errors }}</span>
</div>
</div>
</div>
{# logo #}
<div class="control-group {% if form.logo.errors %}error{% endif %}">

@ -1,4 +1,6 @@
{% load widget_tweaks %}
{% comment %}
Usage: used for creating multilanguage tabs
Uses form, languages dictionary and field which will be in tabs
@ -29,11 +31,14 @@
{% ifequal f.name lang_field %}
<div class="control-group {% if f.errors %}error{% endif %}" >
<label class="control-label">
{% if f.field.required %} <b> {% endif %} {# if field required label - bold #}
{% if f.field.required %}
<b>{{ f.label }}:</b>
{% else %}
{{ f.label }}:
{% if f.field.required %} </b> {% endif %}
{% endif %} {# if field required label - bold #}
</label>
<div class="controls" style="border: 1px solid #ddd; padding: 10px; border-radius: 5px">{{f}}{# style for making content border #}
<div class="controls" style="border: 1px solid #ddd; padding: 10px; border-radius: 5px">
{% if f.field.required %}{{ f|attr:"required" }}{% else %}{{ f }}{% endif %} {# style for making content border #}
<span class="help-inline"> {{f.errors}}</span></div>
</div>
{% endifequal %}

@ -53,11 +53,12 @@
</div>
</div>
{% if object.get_similar %}
<div class="rq-to-hide">
<div class="s-comments">
<div class="sect-title blog_link"><span>{% trans 'Последние новости' %}</span><a class="button more" href="/news/">{% trans 'Все новости' %}</a></div>
<div class="sect-title blog_link"><span>{% trans 'Другие новости, которые могут быть вам интересны' %}</span><a class="button more" href="/news/">{% trans 'Все новости' %}</a></div>
<div class="cat-list sc-comments">
{% for news in object.similar %}
{% for news in object.get_similar %}
<div class="cl-item">
<div class="acticle_list">
<a href="{{ news.get_permanent_url }}" title="">
@ -75,4 +76,6 @@
</div>
</div>
</div>
{% endif %}
{% endblock %}

@ -132,19 +132,24 @@
</div>
<div class="conference_interested">
{% with object.audience.all as audiences %}
{% if audiences %}
<div class="conference_for">
<h3><i class="fa fa-user"></i> {% trans 'Кому будет интересно' %}</h3>
<ul>
{% for audience in object.audience.all %}
{% for audience in audiences %}
<li>{{ audience.title }}</li>
{% endfor %}
</ul>
</div>
{% endif %}
{% endwith %}
{% if object.min_price and object.max_price %}
<div class="confererence_price">
<h3><i class="fa fa-tag"></i> {% trans 'Стоимость участия' %}</h3>
<div class="conference_price">{{ object.min_price }} - {{ object.max_price }} {{ object.get_currency_html }}</div>
</div>
{% endif %}
</div>
<hr>

@ -1,16 +1,16 @@
{% extends "client/base_catalog.html" %}
{% load i18n %}
{% block title %}{% trans "Email confirmation" %}{% endblock %}
{% block title %}{% trans "Подтверждение email" %}{% endblock %}
{% block page_body %}
<h1>{% trans "Enter your email" %}</h1>
<h1>{% trans "Введите ваш email" %}</h1>
<div cl>
</div>
{% if form.errors %}
<p class="error">{% trans "Please correct the errors below:" %}</p>
<p class="error">{% trans "Пожалуйста исправьте ошибки:" %}</p>
{% endif %}
{# {% url "social:complete" backend=backend %}#}
<form class="form-inline" action="." method="post" role="form">{% csrf_token %}
@ -22,11 +22,12 @@
</div>
</div>
{% endfor %}
<button class="btn btn-default" type="submit">{% trans "Submit" %}</button>
<button class="btn btn-default" type="submit">{% trans "Подтвердить" %}</button>
</form>
{% endblock %}
{% block content-related %}
<p>{% trans "Please enter your valid email, to activate account we will send you an email on this e-mail address" %}</p>
<p>{% trans "Пожалуйста введите ваш email. Мы вышлем на него письмо чтобы активировать аккаунт." %}</p>
{#<p>{% trans "Please enter your valid email, to activate account we will send you an email on this e-mail address" %}</p>#}
{% endblock %}

Loading…
Cancel
Save