@ -3,11 +3,11 @@
from itertools import chain
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 . html import format_html
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
@ -19,7 +19,7 @@ from theme.models import Theme, Tag
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)
return u ' {label } ( {count} ) ' . format ( label = smart_text ( obj . name ) , count = obj . count )
@ -69,27 +69,11 @@ class CountModelMultipleChoiceField(forms.ModelMultipleChoiceField):
# ORDER BY NULL
# """
# 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-й рабочий способ (с родным заполением перевода)
## в ходе поиска, был найден и 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 )
extra_tag_expo_count = ''' SELECT COUNT(`exposition_exposition_tag`.`exposition_id`) FROM `exposition_exposition_tag` WHERE (`theme_tag`.`id` = `exposition_exposition_tag`.`tag_id`) '''
extra_tag_conf_count = ''' SELECT COUNT(`conference_conference_tag`.`conference_id`) FROM `conference_conference_tag` WHERE (`theme_tag`.`id` = `conference_conference_tag`.`tag_id`) '''
class FilterForm ( forms . Form ) :
TYPES = EnumChoices (
@ -99,28 +83,82 @@ class FilterForm(forms.Form):
model = forms . TypedMultipleChoiceField ( label = _ ( u ' Тип события ' ) , coerce = int , choices = TYPES , required = False , widget = forms . CheckboxSelectMultiple ( ) )
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 ( ) )
# 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 ) :
val = self . cleaned_data . get ( ' model ' )
models = [ ]
if val :
def __init__ ( self , * args , * * kwargs ) :
super ( FilterForm , self ) . __init__ ( * args , * * kwargs )
self . _is_valid = False
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 :
models . append ( Exposition )
self . _ models. append ( Exposition )
if self . TYPES . CONF in val :
models . append ( Conference )
else :
models = [ Conference , Exposition ]
return models
self . _models . append ( Conference )
return self . _models or [ Exposition , Conference ]
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 ) :
qs = self . default_filter ( self . get_models ( ) )
qs = self . default_filter ( )
d = self . cleaned_data
if 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 ' ) )
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 ( ) )
def default_filter ( self ) :
qs = RelatedSearchQuerySet ( ) . models ( * self . models ) . load_all ( )
for model in self . models :
qs = qs . load_all_queryset ( model ,
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