|
|
|
|
@ -4,12 +4,12 @@ from itertools import chain |
|
|
|
|
|
|
|
|
|
from django import forms |
|
|
|
|
from django.utils.translation import ugettext as _ |
|
|
|
|
from django.utils.encoding import force_text |
|
|
|
|
from django.utils.encoding import smart_text, force_text |
|
|
|
|
from django.utils.html import format_html |
|
|
|
|
from django.utils.safestring import mark_safe |
|
|
|
|
from django.db.models import Count, Sum |
|
|
|
|
|
|
|
|
|
from haystack.query import SearchQuerySet |
|
|
|
|
from haystack.query import SearchQuerySet, RelatedSearchQuerySet |
|
|
|
|
|
|
|
|
|
from functions.model_utils import EnumChoices |
|
|
|
|
from exposition.models import Exposition |
|
|
|
|
@ -17,57 +17,94 @@ from conference.models import Conference |
|
|
|
|
from theme.models import Theme, Tag |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class CheckboxSelectMultiple(forms.CheckboxSelectMultiple): |
|
|
|
|
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) |
|
|
|
|
output = ['<ul>'] |
|
|
|
|
# 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)): |
|
|
|
|
# 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 = format_html(u' for="{0}"', 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 = force_text(option_label) |
|
|
|
|
count = 763 |
|
|
|
|
output.append(format_html(u'<li><label{0}>{1} {2} ({count})</label></li>', |
|
|
|
|
label_for, rendered_cb, option_label, |
|
|
|
|
count=count)) |
|
|
|
|
output.append('</ul>') |
|
|
|
|
return mark_safe('\n'.join(output)) |
|
|
|
|
class CountModelMultipleChoiceField(forms.ModelMultipleChoiceField): |
|
|
|
|
def label_from_instance(self, obj): |
|
|
|
|
return u'{0} ({count})'.format(smart_text(obj.name), count=obj.e_count + obj.c_count) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class FilterForm(forms.Form): |
|
|
|
|
# class Meta: |
|
|
|
|
# widgets = { |
|
|
|
|
# 'model': forms.CheckboxSelectMultiple(), |
|
|
|
|
# 'theme': forms.CheckboxSelectMultiple(), |
|
|
|
|
# 'tag': forms.CheckboxSelectMultiple(), |
|
|
|
|
# } |
|
|
|
|
|
|
|
|
|
### Делаем выборку по темам, сразу заполняя перевод и кол-во событиый |
|
|
|
|
## 1-й рабочий способ (без заполнения перевода) |
|
|
|
|
# """ |
|
|
|
|
# SELECT |
|
|
|
|
# `theme_theme`.`id`, |
|
|
|
|
# ( |
|
|
|
|
# SELECT COUNT(`exposition_exposition_theme`.`exposition_id`) |
|
|
|
|
# FROM `exposition_exposition_theme` |
|
|
|
|
# WHERE (`theme_theme`.`id` = `exposition_exposition_theme`.`theme_id`) |
|
|
|
|
# ) AS `e_count`, |
|
|
|
|
# ( |
|
|
|
|
# SELECT COUNT(`conference_conference_theme`.`conference_id`) |
|
|
|
|
# FROM `conference_conference_theme` |
|
|
|
|
# WHERE (`theme_theme`.`id` = `conference_conference_theme`.`theme_id`) |
|
|
|
|
# ) AS `c_count`, |
|
|
|
|
# `theme_theme_translation`.`name` as `name` |
|
|
|
|
# FROM |
|
|
|
|
# `theme_theme` |
|
|
|
|
# GROUP BY `theme_theme`.`id` |
|
|
|
|
# ORDER BY NULL |
|
|
|
|
# """ |
|
|
|
|
|
|
|
|
|
## 2-й рабочий способ (с заполнением перевода) |
|
|
|
|
## аттрибут перевода 'name' присвоен на 'name_t', чтобы не ругалось на неправильно заполненый перевод |
|
|
|
|
# theme_sql = \ |
|
|
|
|
# """ |
|
|
|
|
# SELECT |
|
|
|
|
# `theme_theme_translation`.`name` AS `name_t`, |
|
|
|
|
# `theme_theme_translation`.`master_id` AS `id`, |
|
|
|
|
# ( |
|
|
|
|
# SELECT COUNT(`exposition_exposition_theme`.`exposition_id`) |
|
|
|
|
# FROM `exposition_exposition_theme` |
|
|
|
|
# WHERE (`theme_theme_translation`.`master_id` = `exposition_exposition_theme`.`theme_id`) |
|
|
|
|
# ) AS `e_count`, |
|
|
|
|
# ( |
|
|
|
|
# SELECT COUNT(`conference_conference_theme`.`conference_id`) |
|
|
|
|
# FROM `conference_conference_theme` |
|
|
|
|
# WHERE (`theme_theme_translation`.`master_id` = `conference_conference_theme`.`theme_id`) |
|
|
|
|
# ) AS `c_count` |
|
|
|
|
# FROM |
|
|
|
|
# `theme_theme_translation` |
|
|
|
|
# WHERE (`theme_theme_translation`.`language_code` = 'ru') |
|
|
|
|
# GROUP BY `theme_theme_translation`.`name` |
|
|
|
|
# ORDER BY NULL |
|
|
|
|
# """ |
|
|
|
|
# qs = Theme.objects.raw(theme_sql) |
|
|
|
|
|
|
|
|
|
## 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 |
|
|
|
|
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): |
|
|
|
|
TYPES = EnumChoices( |
|
|
|
|
EXPO=(1, _(u'Выставки')), |
|
|
|
|
CONF=(2, _(_(u'Конференции'))), |
|
|
|
|
) |
|
|
|
|
|
|
|
|
|
model = forms.TypedMultipleChoiceField(label=_(u'Тип события'), coerce=int, choices=TYPES, required=False, widget=CheckboxSelectMultiple()) |
|
|
|
|
theme = forms.ModelMultipleChoiceField(label=_(u'Тематики'), |
|
|
|
|
queryset=Theme.active.all()\ |
|
|
|
|
.annotate(e_count=Count('exposition_themes'), c_count=Count('conference_themes')), |
|
|
|
|
required=False, widget=CheckboxSelectMultiple()) |
|
|
|
|
tag = forms.ModelMultipleChoiceField(label=_(u'Теги'), |
|
|
|
|
queryset=Tag.active.all()\ |
|
|
|
|
.annotate(e_count=Count('exposition_themes'), c_count=Count('conference_themes')), |
|
|
|
|
required=False, widget=CheckboxSelectMultiple()) |
|
|
|
|
model = forms.TypedMultipleChoiceField(label=_(u'Тип события'), coerce=int, choices=TYPES, required=False, widget=forms.CheckboxSelectMultiple()) |
|
|
|
|
theme = CountModelMultipleChoiceField(label=_(u'Тематики'), |
|
|
|
|
queryset=themes, |
|
|
|
|
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): |
|
|
|
|
@ -83,10 +120,17 @@ class FilterForm(forms.Form): |
|
|
|
|
return models |
|
|
|
|
|
|
|
|
|
def filter(self): |
|
|
|
|
qs = SearchQuerySet().models(*self.get_models()).all() |
|
|
|
|
qs = self.default_filter(self.get_models()) |
|
|
|
|
d = self.cleaned_data |
|
|
|
|
if d.get('theme'): |
|
|
|
|
qs = qs.filter(theme__in=d.get('theme')) |
|
|
|
|
if d.get('tag'): |
|
|
|
|
qs = qs.filter(tag__in=d.get('tag')) |
|
|
|
|
return qs |
|
|
|
|
|
|
|
|
|
def default_filter(self, models=None): |
|
|
|
|
qs = RelatedSearchQuerySet().models(Exposition, Conference).load_all() |
|
|
|
|
models = models or [Exposition, Conference] |
|
|
|
|
for model in models: |
|
|
|
|
qs = qs.load_all_queryset(model, model.enable.all()) |
|
|
|
|
return qs |
|
|
|
|
|