работа над филтром

remotes/origin/stage5
Alexander Burdeiny 10 years ago
parent bdd4960d68
commit ea66b09f73
  1. 134
      events/forms.py
  2. 4
      proj/views.py
  3. 44
      templates/client/blank.html
  4. 27
      templates/client/includes/banners/tops_head_js.html
  5. 2
      templates/client/includes/events/filter_result.html
  6. 1
      theme/manager.py

@ -3,11 +3,11 @@
from itertools import chain from itertools import chain
from django import forms from django import forms
from django.utils.translation import ugettext as _ from django.utils.translation import get_language, ugettext as _
from django.utils.encoding import smart_text, force_text from django.utils.encoding import smart_text, force_text
from django.utils.html import format_html from django.utils.html import format_html
from django.utils.safestring import mark_safe from django.utils.safestring import mark_safe
from django.db.models import Count, Sum from django.db.models import Count, Sum, Q
from haystack.query import SearchQuerySet, RelatedSearchQuerySet from haystack.query import SearchQuerySet, RelatedSearchQuerySet
@ -19,7 +19,7 @@ from theme.models import Theme, Tag
class CountModelMultipleChoiceField(forms.ModelMultipleChoiceField): class CountModelMultipleChoiceField(forms.ModelMultipleChoiceField):
def label_from_instance(self, obj): def label_from_instance(self, obj):
return u'{0} ({count})'.format(smart_text(obj.name), count=obj.e_count + obj.c_count) return u'{label} ({count})'.format(label=smart_text(obj.name), count=obj.count)
@ -69,27 +69,11 @@ class CountModelMultipleChoiceField(forms.ModelMultipleChoiceField):
# ORDER BY NULL # ORDER BY NULL
# """ # """
# qs = Theme.objects.raw(theme_sql) # qs = Theme.objects.raw(theme_sql)
extra_theme_expo_count = '''SELECT COUNT(`exposition_exposition_theme`.`exposition_id`) FROM `exposition_exposition_theme` WHERE (`theme_theme`.`id` = `exposition_exposition_theme`.`theme_id`) '''
extra_theme_conf_count = '''SELECT COUNT(`conference_conference_theme`.`conference_id`) FROM `conference_conference_theme` WHERE (`theme_theme`.`id` = `conference_conference_theme`.`theme_id`) '''
## 3-й рабочий способ (с родным заполением перевода) extra_tag_expo_count = '''SELECT COUNT(`exposition_exposition_tag`.`exposition_id`) FROM `exposition_exposition_tag` WHERE (`theme_tag`.`id` = `exposition_exposition_tag`.`tag_id`) '''
## в ходе поиска, был найден и 4-й рабочий способ используя RawSQL, но он для Django >= 1.8 extra_tag_conf_count = '''SELECT COUNT(`conference_conference_tag`.`conference_id`) FROM `conference_conference_tag` WHERE (`theme_tag`.`id` = `conference_conference_tag`.`tag_id`) '''
## https://docs.djangoproject.com/en/1.9/ref/models/expressions/#raw-sql-expressions
## from django.db.models.expressions import RawSQL
extra_themes_expo_count = '''
SELECT COUNT(`exposition_exposition_theme`.`exposition_id`)
FROM `exposition_exposition_theme`
WHERE (`theme_theme`.`id` = `exposition_exposition_theme`.`theme_id`)
'''
extra_themes_conf_count = '''
SELECT COUNT(`conference_conference_theme`.`conference_id`)
FROM `conference_conference_theme`
WHERE (`theme_theme`.`id` = `conference_conference_theme`.`theme_id`)
'''
extra_themes_select = {
'e_count': extra_themes_expo_count,
'c_count': extra_themes_conf_count,
}
themes = Theme.objects.language('ru').extra(select=extra_themes_select)
class FilterForm(forms.Form): class FilterForm(forms.Form):
TYPES = EnumChoices( TYPES = EnumChoices(
@ -99,28 +83,82 @@ class FilterForm(forms.Form):
model = forms.TypedMultipleChoiceField(label=_(u'Тип события'), coerce=int, choices=TYPES, required=False, widget=forms.CheckboxSelectMultiple()) model = forms.TypedMultipleChoiceField(label=_(u'Тип события'), coerce=int, choices=TYPES, required=False, widget=forms.CheckboxSelectMultiple())
theme = CountModelMultipleChoiceField(label=_(u'Тематики'), theme = CountModelMultipleChoiceField(label=_(u'Тематики'),
queryset=themes, queryset=Theme.objects.none(),
required=False, widget=forms.CheckboxSelectMultiple())
tag = CountModelMultipleChoiceField(label=_(u'Теги'),
queryset=Tag.objects.none(),
required=False, widget=forms.CheckboxSelectMultiple()) required=False, widget=forms.CheckboxSelectMultiple())
# tag = CountModelMultipleChoiceField(label=_(u'Теги'),
# queryset=Tag.active.all()\
# .annotate(e_count=Count('exposition_tags'), c_count=Count('conference_tags')),
# required=False, widget=forms.CheckboxSelectMultiple())
def get_models(self): def __init__(self, *args, **kwargs):
val = self.cleaned_data.get('model') super(FilterForm, self).__init__(*args, **kwargs)
models = [] self._is_valid = False
if val: self._models = None
self.fields['theme'].queryset = self.get_theme_choices()
self.fields['tag'].queryset = self.get_tag_choices()
def is_valid(self):
# if getattr(self, '_is_valid', None) is None:
self._is_valid = super(FilterForm, self).is_valid()
# нам нужно сбрасывать сохраненные модели,
# т.к. после валидации нужно вернуть только выбранные
self._models = None
return self._is_valid
@property
def models(self):
if self._models is None and self._is_valid:
val = self.cleaned_data.get('model')
self._models = []
if self.TYPES.EXPO in val: if self.TYPES.EXPO in val:
models.append(Exposition) self._models.append(Exposition)
if self.TYPES.CONF in val: if self.TYPES.CONF in val:
models.append(Conference) self._models.append(Conference)
else: return self._models or [Exposition, Conference]
models = [Conference, Exposition]
return models def get_theme_choices(self):
# 3-й рабочий способ (с родным заполением перевода)
# в ходе поиска решения, был найден и 4-й рабочий способ используя RawSQL, но он для Django >= 1.8
# https://docs.djangoproject.com/en/1.9/ref/models/expressions/#raw-sql-expressions
# from django.db.models.expressions import RawSQL
if getattr(self, '_theme_choices', None) is None:
if Exposition in self.models and Conference in self.models:
count_query = '({q1}) + ({q2})'.format(
q1=extra_theme_expo_count,
q2=extra_theme_conf_count)
filter_types = Q(types=Theme.types.conference) | Q(types=Theme.types.exposition)
elif Exposition in self.models:
count_query = extra_theme_expo_count
filter_types = Q(types=Theme.types.exposition)
elif Conference in self.models:
count_query = extra_theme_conf_count
filter_types = Q(types=Theme.types.conference)
self._theme_choices = Theme.objects.language()\
.filter(filter_types)\
.extra(select={'count': count_query})\
.order_by('-count', '-name')
return self._theme_choices
def get_tag_choices(self):
extra_tag_select = {}
if getattr(self, '_tag_choices', None) is None:
if Exposition in self.models and Conference in self.models:
count_query = '({q1}) + ({q2})'.format(
q1=extra_tag_expo_count,
q2=extra_tag_conf_count)
elif Exposition in self.models:
count_query = extra_tag_expo_count
elif Conference in self.models:
count_query = extra_tag_conf_count
self._tag_choices = Tag.objects.language()\
.extra(select={'count': count_query})\
.order_by('-count', '-name')
return self._tag_choices
def filter(self): def filter(self):
qs = self.default_filter(self.get_models()) qs = self.default_filter()
d = self.cleaned_data d = self.cleaned_data
if d.get('theme'): if d.get('theme'):
qs = qs.filter(theme__in=d.get('theme')) qs = qs.filter(theme__in=d.get('theme'))
@ -128,9 +166,17 @@ class FilterForm(forms.Form):
qs = qs.filter(tag__in=d.get('tag')) qs = qs.filter(tag__in=d.get('tag'))
return qs return qs
def default_filter(self, models=None): def default_filter(self):
qs = RelatedSearchQuerySet().models(Exposition, Conference).load_all() qs = RelatedSearchQuerySet().models(*self.models).load_all()
models = models or [Exposition, Conference] for model in self.models:
for model in models: qs = qs.load_all_queryset(model,
qs = qs.load_all_queryset(model, model.enable.all()) model.enable.all()
# не реализовано в hvad <_<
# .only(
# 'canceled', 'name', 'main_title', 'expohit', 'logo',
# 'quality_label', 'services', 'visitors', 'members',
# 'data_begin', 'data_end', 'country__url', 'country__name',
# 'city__url', 'place__name'
# )
)
return qs return qs

@ -44,7 +44,9 @@ def expo_context(request):
'blogs': Article.objects.every_page_blogs(), 'blogs': Article.objects.every_page_blogs(),
'news_list': Article.objects.main_page_news(), 'sng_countries': settings.SNG_COUNTRIES, 'news_list': Article.objects.main_page_news(), 'sng_countries': settings.SNG_COUNTRIES,
'seo_text': add_seo(request), 'announce_subscribe': SubscribeAssideForm(), 'seo_text': add_seo(request), 'announce_subscribe': SubscribeAssideForm(),
'NO_EXTERNAL_JS': getattr(settings, 'NO_EXTERNAL_JS', False)} 'NO_EXTERNAL_JS': getattr(settings, 'NO_EXTERNAL_JS', False),
'NO_BANNERS': getattr(settings, 'NO_BANNERS', False),
}
user = request.user user = request.user
if not user.is_anonymous() and not user.url: if not user.is_anonymous() and not user.url:

@ -63,27 +63,29 @@ This template include basic anf main styles and js files,
"year": "{{ year.text }}", "year": "{{ year.text }}",
}; };
</script> </script>
<script> {% if not NO_BANNERS %}
(function() { <script>
var DOMbannersjsElementInserted = new Event('DOMbannersjsElementInserted'); (function() {
window.DOMbannersjsElementInserted = DOMbannersjsElementInserted; var DOMbannersjsElementInserted = new Event('DOMbannersjsElementInserted');
window.marker_DOMbannersjsElementInserted = window.marker_DOMbannersjsElementInserted || false; window.DOMbannersjsElementInserted = DOMbannersjsElementInserted;
document.addEventListener("DOMbannersjsElementInserted", function() { window.marker_DOMbannersjsElementInserted = window.marker_DOMbannersjsElementInserted || false;
// console.info("DOMbannersjsElementInserted fired"); document.addEventListener("DOMbannersjsElementInserted", function() {
window.marker_DOMbannersjsElementInserted = true // console.info("DOMbannersjsElementInserted fired");
}); window.marker_DOMbannersjsElementInserted = true
});
var bannersjsRequestDone = new Event('bannersjsRequestDone');
window.bannersjsRequestDone = bannersjsRequestDone; var bannersjsRequestDone = new Event('bannersjsRequestDone');
window.marker_bannersjsRequestDone = false; window.bannersjsRequestDone = bannersjsRequestDone;
document.addEventListener("bannersjsRequestDone", function() { window.marker_bannersjsRequestDone = false;
window.marker_bannersjsRequestDone = true; document.addEventListener("bannersjsRequestDone", function() {
}); window.marker_bannersjsRequestDone = true;
});
window.is_popup_banner = false;
})(); window.is_popup_banner = false;
</script> })();
<script type="text/javascript" src="{% static 'client/js/rejs/banners.js' %}" async></script> </script>
<script type="text/javascript" src="{% static 'client/js/rejs/banners.js' %}" async></script>
{% endif %}
{% if request.GET.debug == '1' %} {% if request.GET.debug == '1' %}
<script src="{% static 'client/js/_modules/block.common.js' %}"></script> <script src="{% static 'client/js/_modules/block.common.js' %}"></script>

@ -1,13 +1,16 @@
{% load static %} {% load static %}
<script>
(function() { {% if not NO_BANNERS %}
var DOMtopjsElementInserted = new Event('DOMtopjsElementInserted'); <script>
window.DOMtopjsElementInserted = DOMtopjsElementInserted; (function() {
window.marker_DOMtopjsElementInserted = window.marker_DOMtopjsElementInserted || false; var DOMtopjsElementInserted = new Event('DOMtopjsElementInserted');
document.addEventListener("DOMtopjsElementInserted", function() { window.DOMtopjsElementInserted = DOMtopjsElementInserted;
// console.info("DOMtopjsElementInserted fired"); window.marker_DOMtopjsElementInserted = window.marker_DOMtopjsElementInserted || false;
window.marker_DOMtopjsElementInserted = true document.addEventListener("DOMtopjsElementInserted", function() {
}); // console.info("DOMtopjsElementInserted fired");
})(); window.marker_DOMtopjsElementInserted = true
</script> });
<script type="text/javascript" src="{% static 'client/js/rejs/tops.js' %}" async></script> })();
</script>
<script type="text/javascript" src="{% static 'client/js/rejs/tops.js' %}" async></script>
{% endif %}

@ -17,7 +17,7 @@
{% endif %} {% endif %}
<div class="cli-pict"> <div class="cli-pict">
{% with obj=result.object %} {% with obj=result.object %}
{% include 'client/includes/show_logo.html' %} {% include 'client/includes/show_logo.html' %}
{% endwith %} {% endwith %}
</div> </div>

@ -11,6 +11,7 @@ class ThemeActiveManager(TranslationManager):
manager works only with active themes manager works only with active themes
models where theme defines activity: models where theme defines activity:
- exposition - exposition
- conference
""" """
cache_time = 600 cache_time = 600
def all(self): def all(self):

Loading…
Cancel
Save