diff --git a/conference/search_indexes.py b/conference/search_indexes.py
index 92a0b384..d778e459 100644
--- a/conference/search_indexes.py
+++ b/conference/search_indexes.py
@@ -27,6 +27,8 @@ class ConferenceIndex(indexes.SearchIndex, indexes.Indexable, ExpoSearchMixin):
members_choice = indexes.IntegerField()
visitors_choice = indexes.IntegerField()
price_choice = indexes.IntegerField()
+ expohit = indexes.BooleanField(model_attr='expohit')
+ rating = indexes.MultiValueField()
def prepare_form_name(self, obj):
return None
diff --git a/events/forms.py b/events/forms.py
index 59a83ec8..548d71ec 100644
--- a/events/forms.py
+++ b/events/forms.py
@@ -1,6 +1,7 @@
# -*- coding: utf-8 -*-
import re
-from itertools import chain
+import operator
+from itertools import chain, combinations
from collections import namedtuple
from datetime import datetime
from datetime import timedelta
@@ -47,7 +48,7 @@ class FilterCheckboxSelectMultiple(forms.CheckboxSelectMultiple):
if value is None: value = []
has_id = attrs and 'id' in attrs
final_attrs = self.build_attrs(attrs, name=name)
- output = ['
']
+ output = ['' if not self.is_hidden else '']
# Normalize to strings
str_values = set([force_text(v) for v in value])
for i, (option_value, option_label) in enumerate(chain(self.choices, choices)):
@@ -165,12 +166,20 @@ values_mapping = {
}
RATING = (
- (1, _(u'Топовые (HIT)')),
- (2, _(u'Члены РСВЯ')),
- (3, _(u'Члены UFI')),
- (4, _(u'ExpoRating')),
+ ('r1', _(u'Топовые (HIT)')),
+ ('r2', _(u'Члены РСВЯ')),
+ ('r3', _(u'Члены UFI')),
+ ('r4', _(u'ExpoRating')),
)
+rating_mapping = [
+ {'value': 'r1', 'db_value': 1, 'label': _(u'Топовые (HIT)'), 'field': 'expohit'},
+ {'value': 'r2', 'db_value': int(Exposition.quality_label.ufi), 'label': _(u'Члены РСВЯ'), 'field': 'quality_label'},
+ {'value': 'r3', 'db_value': int(Exposition.quality_label.rsva), 'label': _(u'Члены UFI'), 'field': 'quality_label'},
+ {'value': 'r4', 'db_value': int(Exposition.quality_label.exporating), 'label': _(u'ExpoRating'), 'field': 'quality_label'},
+]
+
+
monthes_abr_to_num = {v.lower(): k for k, v in enumerate(calendar.month_abbr)}
monthes_num_to_abr = {v: k for k, v in monthes_abr_to_num.iteritems()}
year_month_regex = re.compile(r'^((?P\d{4})(?P\w{3}))|((?P\d{1,2})/(?P\d{4}))$')
@@ -248,10 +257,11 @@ class FilterForm(forms.Form):
choices=VISITORS,
required=False, widget=FilterCheckboxSelectMultiple())
rating = FilterTypedMultipleChoiceField(
- label=_(u'Рейтинги'), coerce=int,
+ label=_(u'Рейтинги'), coerce=str,
choices=RATING,
required=False, widget=FilterCheckboxSelectMultiple())
-
+ query = forms.CharField(required=False, widget=forms.HiddenInput())
+ where_query = forms.CharField(required=False, widget=forms.HiddenInput())
def __init__(self, *args, **kwargs):
super(FilterForm, self).__init__(*args, **kwargs)
@@ -314,7 +324,7 @@ class FilterForm(forms.Form):
return year
def clean_default_month(self):
- v = self.cleaned_data.get('default_month')
+ v = self.cleaned_data.get('default_month')
if v and v in settings.MONTHES.keys():
self.fields['month'].default_month = v
return v
@@ -353,19 +363,32 @@ class FilterForm(forms.Form):
# print(new_values, self.data)
return new_values
+ def clean_rating(self):
+ types = self.cleaned_data.get('event_type')
+ if TYPES.CONF in types and not TYPES.EXPO in types:
+ self.fields['rating'].widget.input_type = 'hidden'
+ self.fields['rating'].widget.is_hidden = True
+ # self.fields['rating'].widget = forms.HiddenInput()
+ return []
+ return self.cleaned_data.get('rating')
+
+ def clean_visitors(self):
+ types = self.cleaned_data.get('event_type')
+ if TYPES.CONF in types and not TYPES.EXPO in types:
+ self.fields['visitors'].widget.input_type = 'hidden'
+ self.fields['visitors'].widget.is_hidden = True
+ # self.fields['visitors'].widget = forms.HiddenInput()
+ return []
+ return self.cleaned_data.get('visitors')
+
def _post_clean(self):
# нужно для того, чтобы год зашел в поле month
# print(self.get_date_begin_periods())
if not self.cleaned_data.get('default_month') and self.fields['month'].default_month:
self.data['default_month'] = self.fields['month'].default_month
- year = self.cleaned_data.get('year')
- # if year:
- # for val, name in self.fields['month'].additional_choices:
- # self.
- # additional_choices
+ # year = self.cleaned_data.get('year')
def is_valid(self):
- # if getattr(self, '_is_valid', None) is None:
self._is_valid = super(FilterForm, self).is_valid()
# нам нужно сбрасывать сохраненный выбор моделей,
@@ -383,7 +406,18 @@ class FilterForm(forms.Form):
self._models.append(Exposition)
if TYPES.CONF in val:
self._models.append(Conference)
- return self._models or [Exposition, Conference]
+ if not self._models:
+ self._models = [Exposition, Conference]
+ if self.cleaned_data.get('query') or self.cleaned_data.get('where_query'):
+ exclude_models = []
+ for model in self._models:
+ values = self.filter(load_all=False, models=[model]).values_list('pk', flat=True)
+ if values:
+ setattr(self, 'query_{model}_ids'.format(model=model.__name__), map(int, values))
+ else:
+ exclude_models.append(model)
+ self._models = list(filter(lambda x: x not in exclude_models, self._models))
+ return self._models
@property
def lookup_kwargs(self):
@@ -415,10 +449,10 @@ class FilterForm(forms.Form):
self._lookup_kwargs['price_choice__in'] = d.get('price')
return self._lookup_kwargs
- def filter(self, qs=None):
- qs = qs or self.default_filter()
+ def filter(self, qs=None, load_all=True, models=None):
+ qs = qs or self.default_filter(load_all=load_all, _models=models)
# lookup_kwargs = dict(ChainMap({}, *(lookup_kwargs or self.lookup_kwargs).values()))
- qs = self.make_data_begin_filter(qs)
+ qs = self.make_cleaned_sqs_filter(qs)
return qs.filter(**self.lookup_kwargs).order_by('data_begin')
def default_filter(self, load_all=True, _models=None):
@@ -432,10 +466,19 @@ class FilterForm(forms.Form):
qs = qs.filter(data_begin__gte=datetime.now().date())
return qs
- def make_data_begin_filter(self, qs):
- params = self.make_date_begin_sqs_params()
- if params is not None:
- qs = qs.filter(params)
+ def make_cleaned_sqs_filter(self, qs):
+ date_params = self.make_date_begin_sqs_params()
+ if date_params is not None:
+ qs = qs.filter(date_params)
+ rating_params = self.make_rating_sqs_params()
+ if rating_params is not None:
+ qs = qs.filter(rating_params)
+ query = self.cleaned_data.get('query')
+ if query:
+ qs = qs.autocomplete(content_auto=query)
+ where_query = self.cleaned_data.get('where_query')
+ if where_query:
+ qs = qs.filter(where__contains=where_query)
return qs
def recalculate_choices(self):
@@ -470,26 +513,27 @@ class FilterForm(forms.Form):
# для того чтобы взяло чойсы из новых результатов
self.fields[field].cache_choices = False
self.fields[field].choice_cache = None
- print(self.fields[field].queryset.query)
+ # print(self.fields[field].queryset.query)
for field in ['members', 'visitors', 'price']:
self.fields[field].choices = self.make_local_field_count(field) or self.fields[field].choices
self.fields['month'].choices = self.make_date_begin_counts()
+ self.fields['rating'].choices = self.make_rating_counts()
self.make_event_type_choices_count()
# self.fields['month'].choices = self.month_choices()
- # for field in self.fields:
- # field = self.fields[field]
- # if hasattr(field, 'queryset'):
- # field.queryset = field.queryset[:15]
+ for field in self.fields:
+ field = self.fields[field]
+ if hasattr(field, 'queryset'):
+ field.queryset = field.queryset[:150]
def make_event_type_choices_count(self):
types = {1: Exposition, 2: Conference}
choices = []
for _type, label in TYPES:
qs = self.default_filter(load_all=False, _models=[types.get(_type)])
- qs = self.make_data_begin_filter(qs)
+ qs = self.make_cleaned_sqs_filter(qs)
count = qs.filter(**self.lookup_kwargs).count()
choices.append((_type, label + ' ({count})'.format(count=count)))
self.fields['event_type'].choices = choices
@@ -548,6 +592,16 @@ class FilterForm(forms.Form):
'''`{db_table}`.`{attname}` IN {val}'''\
.format(**_format_kwargs))
+ # if self.cleaned_data.get('query') or self.cleaned_data.get('where_query'):
+ values = getattr(self, 'query_{model}_ids'.format(model=model.__name__), [])
+ # values = self.filter(load_all=False, models=[model]).values_list('pk', flat=True)
+ if values:
+ where.append(
+ '''`{db_table}`.`id` IN {val}'''\
+ .format(
+ db_table=model._meta.db_table,
+ val=self.make_ids_in_sql_format(values))
+ )
return joins, where
def make_local_field_count(self, field):
@@ -583,10 +637,11 @@ class FilterForm(forms.Form):
)
_joins, _where = self.make_joins_from_selected(field, model)
- joins.extend(_joins)
- where.extend(_where)
+ joins.extend(_joins or [])
+ where.extend(_where or [])
where.append(self.make_default_where(db_table=model._meta.db_table))
self.make_date_begin_where(where, db_table=model._meta.db_table)
+ self.make_rating_where(where, db_table=model._meta.db_table)
selects.append(select + ''.join(joins) + ' where ' + ' and '.join(where) + group_by)
@@ -669,9 +724,10 @@ class FilterForm(forms.Form):
)
_joins, _where = self.make_joins_from_selected('data_begin', model)
- joins.extend(_joins)
- where.extend(_where)
+ joins.extend(_joins or [])
+ where.extend(_where or [])
where.append(self.make_default_where(db_table=model._meta.db_table))
+ self.make_rating_where(where, db_table=model._meta.db_table)
selects.append(select + ''.join(joins) + ' where ' + ' and '.join(where) + group_by)
@@ -693,6 +749,64 @@ class FilterForm(forms.Form):
# with connection.cursor() as c:
return choices
+ def make_rating_counts(self):
+ choices = []
+ sql = ''
+ selects = []
+ for model in self.models:
+ joins = []
+ where = []
+ group_by = ''
+
+ format_kwargs = {
+ 'db_table': model._meta.db_table,
+ 'lang': self.lang,
+ }
+
+ cases = []
+ for case in filter(lambda x: x['field'] == 'expohit', rating_mapping):
+ cases.append(
+ ''' sum(case when (`{db_table}`.`{field}` = {db_value}) then 1 else 0 end) as '{value}' '''\
+ .format(value=case['value'], field=case['field'], db_value=case['db_value'], **format_kwargs)
+ )
+ for case in filter(lambda x: x['field'] != 'expohit', rating_mapping):
+ cases.append(
+ ''' sum(case when (`{db_table}`.`{field}` = `{db_table}`.`{field}` | {db_value}) then 1 else 0 end) as '{value}' '''\
+ .format(value=case['value'], field=case['field'], db_value=case['db_value'], **format_kwargs)
+ )
+ select = \
+ ''' SELECT {cases} FROM `{db_table}_translation` INNER JOIN `{db_table}` ON (`{db_table}_translation`.`master_id` = `{db_table}`.`id`) '''\
+ .format(cases=', '.join(cases), **format_kwargs)
+
+ where.append(
+ ''' `{db_table}_translation`.`language_code` = '{lang}' '''\
+ .format(**format_kwargs)
+ )
+
+ _joins, _where = self.make_joins_from_selected('rating', model)
+ joins.extend(_joins or [])
+ where.extend(_where or [])
+ where.append(self.make_default_where(db_table=model._meta.db_table))
+ self.make_date_begin_where(where, db_table=model._meta.db_table)
+ selects.append(select + ''.join(joins) + ' where ' + ' and '.join(where) + group_by)
+
+ sql = ' union '.join(selects)
+ choices = []
+ if sql:
+ c = connection.cursor()
+ try:
+ c.execute(sql)
+ mapper = namedtuple('Result', [col[0] for col in c.description])
+ data = [mapper(*raw) for raw in c.fetchall()]
+ for value, label in RATING:
+ count = sum([getattr(x, value, 0) or 0 for x in data])
+ choices.append((value, label + ' ({count})'.format(count=count)))
+ finally:
+ c.close()
+ # some bug with these! AttributeError: __exit__
+ # with connection.cursor() as c:
+ return choices
+
def get_date_begin_periods(self):
periods = getattr(self, '_periods', None)
if periods is None:
@@ -751,7 +865,7 @@ class FilterForm(forms.Form):
return None
def make_date_begin_where(self, where, db_table):
- key = '_where_date_begin_where_{}'.format(db_table)
+ key = '_make_date_begin_where_{}'.format(db_table)
_where = getattr(self, key, None)
if _where is None:
_where = []
@@ -791,9 +905,34 @@ class FilterForm(forms.Form):
_where = [''' ({}) '''.format(' OR '.join(_where))]
setattr(self, key, _where)
# print(_where)
- where.extend(_where)
+ where.extend(_where or [])
return
+ def make_rating_where(self, where, db_table):
+ key = '_make_rating_where_{}'.format(db_table)
+ _where = getattr(self, key, None)
+ if _where is None:
+ cleaned = self.cleaned_data.get('rating', [])
+ _where = []
+ # choices = filter(lambda x: x['value'] in cleaned and x['field'] == 'expohit', rating_mapping)
+ for choice in filter(lambda x: x['field'] == 'expohit' and x['value'] in cleaned, rating_mapping):
+ _where.append(
+ ''' `{db_table}`.`{field}` = {db_value} '''\
+ .format(field=choice['field'], db_value=choice['db_value'], db_table=db_table)
+ )
+ quality_label = []
+ for choice in filter(lambda x: x['field'] == 'quality_label' and x['value'] in cleaned, rating_mapping):
+ quality_label.append(choice['db_value'])
+ if quality_label:
+ _where.append(
+ ''' `{db_table}`.`{field}` = `{db_table}`.`{field}` | {computed} '''\
+ .format(field=choice['field'], computed=reduce(operator.or_, quality_label), db_table=db_table)
+ )
+ if len(_where) > 1:
+ _where = [''' ({}) '''.format(' OR '.join(_where))]
+ setattr(self, key, _where)
+ where.extend(_where or [])
+ return
# def get_prev_month(self, date):
# year = date.year
# month = date.month
@@ -894,6 +1033,19 @@ class FilterForm(forms.Form):
params |= SQ(**lookup)
return params
+ def make_rating_sqs_params(self):
+ params = None
+ if self.cleaned_data.get('rating'):
+ for choice in filter(lambda x: x['field'] == 'expohit' and x['value'] in self.cleaned_data.get('rating'), rating_mapping):
+ params = SQ(**{choice['field']: choice['db_value']})
+ quality_label = [x['db_value'] for x in filter(lambda x: x['field'] != 'expohit' and x['value'] in self.cleaned_data.get('rating'), rating_mapping)]
+ if quality_label:
+ if params is None:
+ params = SQ(**{'rating__in': quality_label})
+ else:
+ params |= SQ(**{'rating__in': quality_label})
+ return params
+
def make_count_select(self, field):
selects = []
case = None
@@ -953,10 +1105,11 @@ class FilterForm(forms.Form):
# FILTER current by other values
_joins, _where = self.make_joins_from_selected(field, model)
- joins.extend(_joins)
- where.extend(_where)
+ joins.extend(_joins or [])
+ where.extend(_where or [])
where.append(self.make_default_where(db_table=model._meta.db_table))
self.make_date_begin_where(where, db_table=model._meta.db_table)
+ self.make_rating_where(where, db_table=model._meta.db_table)
selects.append(select + ''.join(joins) + ' where ' + ' and '.join(where) + group_by)
if len(selects) == 2:
diff --git a/events/views.py b/events/views.py
index 7830de21..5d51439d 100644
--- a/events/views.py
+++ b/events/views.py
@@ -32,11 +32,12 @@ class FilterListView(ContextMixin, FormMixin, ListView):
def get_queryset(self):
if self.form.is_valid():
qs = self.form.filter()
+ # import pdb; pdb.set_trace()
else:
qs = self.form.default_filter()
if self.kwargs.get('with_form', True):
self.form.recalculate_choices()
- print(self.form.data, self.form.cleaned_data, self.form.get_date_begin_periods())
+ # print(self.form.data, self.form.cleaned_data, self.form.get_date_begin_periods())
# import pdb; pdb.set_trace()
return qs
diff --git a/exposition/search_indexes.py b/exposition/search_indexes.py
index 347253a1..1e9dbd29 100644
--- a/exposition/search_indexes.py
+++ b/exposition/search_indexes.py
@@ -28,6 +28,8 @@ class ExpositionIndex(indexes.SearchIndex, indexes.Indexable, ExpoSearchMixin):
members_choice = indexes.IntegerField()
visitors_choice = indexes.IntegerField()
price_choice = indexes.IntegerField()
+ expohit = indexes.BooleanField(model_attr='expohit')
+ rating = indexes.MultiValueField()
def prepare_form_name(self, obj):
return None
diff --git a/functions/custom_views.py b/functions/custom_views.py
index bbc580a9..019635df 100644
--- a/functions/custom_views.py
+++ b/functions/custom_views.py
@@ -413,7 +413,9 @@ class ExpoSearchView(ListView):
if form.cleaned_data.get('to'):
context['date_to'] = form.cleaned_data.get('to').strftime('%d.%m.%Y')
if form.cleaned_data.get('q'):
- context['query'] = self.cleaned_data.get('q', '').strip()
+ context['query'] = form.cleaned_data.get('q', '').strip()
+ if form.cleaned_data.get('w'):
+ context['where_query'] = form.cleaned_data.get('w', '').strip()
else:
form = self.search_form()
diff --git a/functions/search_mixin.py b/functions/search_mixin.py
index 65a78964..1590360e 100644
--- a/functions/search_mixin.py
+++ b/functions/search_mixin.py
@@ -5,7 +5,6 @@ class ExpoSearchMixin(object):
"""
"""
-
def prepare_where(self, obj):
if obj.country:
country = [tr.name for tr in obj.country.translations.all()]
@@ -24,7 +23,6 @@ class ExpoSearchMixin(object):
"""
return obj.get_index_text()
-
def prepare_area_id(self, obj):
if obj.country:
return obj.country.area.id
@@ -46,7 +44,6 @@ class ExpoSearchMixin(object):
def prepare_tag(self, obj):
return [th.id for th in obj.tag.filter()]
-
def prepare_url(self, obj):
return obj.get_permanent_url()
@@ -71,3 +68,6 @@ class ExpoSearchMixin(object):
def prepare_price_choice(self, obj):
return obj.price_choice or 0
+ def prepare_rating(self, obj):
+ q = obj.quality_label
+ return [x.mask for x in filter(lambda x: x.is_set == True, [getattr(q, key) for key in q.iterkeys()])]
diff --git a/schema_22.08.2016.xml b/schema_22.08.2016.xml
new file mode 100644
index 00000000..7621ea32
--- /dev/null
+++ b/schema_22.08.2016.xml
@@ -0,0 +1,215 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ id
+
+
+ text
+
+
+
+
+
diff --git a/schema_new.xml b/schema_new.xml
index a5cc8484..5f140474 100644
--- a/schema_new.xml
+++ b/schema_new.xml
@@ -175,6 +175,8 @@
+
+
@@ -183,6 +185,8 @@
+
+
diff --git a/templates/client/blank.html b/templates/client/blank.html
index 20b5bc9e..90f56977 100644
--- a/templates/client/blank.html
+++ b/templates/client/blank.html
@@ -65,6 +65,7 @@ This template include basic anf main styles and js files,
"date_from": "{{ date_from }}",
"date_to": "{{ date_to }}",
"query": "{{ query }}",
+ "where_query": "{{ where_query }}",
};
{% if not NO_BANNERS %}