|
|
|
|
@ -1,7 +1,15 @@ |
|
|
|
|
# -*- coding: utf-8 -*- |
|
|
|
|
import re |
|
|
|
|
from itertools import chain |
|
|
|
|
from collections import namedtuple |
|
|
|
|
from datetime import datetime |
|
|
|
|
from datetime import timedelta |
|
|
|
|
from datetime import date |
|
|
|
|
from datetime import MAXYEAR, MINYEAR |
|
|
|
|
from dateutil import relativedelta |
|
|
|
|
import calendar |
|
|
|
|
# from calendar import TimeEncoding, month_name |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
try: |
|
|
|
|
from collections import ChainMap |
|
|
|
|
@ -10,12 +18,15 @@ except ImportError: |
|
|
|
|
|
|
|
|
|
from django import forms |
|
|
|
|
from django.utils.translation import get_language, ugettext as _ |
|
|
|
|
from django.utils.translation import string_concat |
|
|
|
|
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, Q, ForeignKey, ManyToManyField |
|
|
|
|
from django.db import connection |
|
|
|
|
from django.core.exceptions import ValidationError |
|
|
|
|
from django.core.cache import cache |
|
|
|
|
from django.conf import settings |
|
|
|
|
|
|
|
|
|
from haystack.query import SearchQuerySet, RelatedSearchQuerySet, SQ |
|
|
|
|
|
|
|
|
|
@ -65,7 +76,6 @@ class WidgetDefaultMixin(object): |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class CountModelMultipleChoiceField(WidgetDefaultMixin, forms.ModelMultipleChoiceField): |
|
|
|
|
# widget = forms.CheckboxSelectMultiple |
|
|
|
|
widget = FilterCheckboxSelectMultiple |
|
|
|
|
def label_from_instance(self, obj): |
|
|
|
|
if obj.get('count', None) is None: |
|
|
|
|
@ -105,6 +115,41 @@ class FilterTypedMultipleChoiceField(WidgetDefaultMixin, forms.TypedMultipleChoi |
|
|
|
|
pass |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class MonthChoiceField(FilterTypedMultipleChoiceField): |
|
|
|
|
year = None |
|
|
|
|
additional_choices = [] |
|
|
|
|
default_month = None |
|
|
|
|
def make_year_choice(self, value): |
|
|
|
|
return (str(value), _(u'{year} год').format(year=value)) |
|
|
|
|
|
|
|
|
|
def valid_value(self, value): |
|
|
|
|
valid = super(MonthChoiceField, self).valid_value(value) |
|
|
|
|
if not valid: |
|
|
|
|
if self.year and (value == self.year or check_year(value) == self.year): |
|
|
|
|
choice = self.make_year_choice(value) |
|
|
|
|
self.additional_choices.append(choice) |
|
|
|
|
self.choices.insert(0, choice) |
|
|
|
|
return True |
|
|
|
|
|
|
|
|
|
value = str(value) |
|
|
|
|
match = year_month_regex.match(value) |
|
|
|
|
month = None |
|
|
|
|
year = self.year or datetime.today().year |
|
|
|
|
if match: |
|
|
|
|
year, month = match.group('year'), match.group('month') |
|
|
|
|
elif value in settings.MONTHES.keys(): |
|
|
|
|
month = value |
|
|
|
|
self.default_month = month |
|
|
|
|
if month in settings.MONTHES.keys(): |
|
|
|
|
choice = (value, string_concat(settings.MONTHES[month]['name'], ' ', year)) |
|
|
|
|
self.additional_choices.append(choice) |
|
|
|
|
self.choices.insert(0, choice) |
|
|
|
|
# print(choice, self.choices) |
|
|
|
|
|
|
|
|
|
return super(MonthChoiceField, self).valid_value(value) |
|
|
|
|
return valid |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
fields_mapping = { |
|
|
|
|
'members': 'members_choice', |
|
|
|
|
'visitors': 'visitors_choice', |
|
|
|
|
@ -118,32 +163,47 @@ values_mapping = { |
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
monthes_abr_to_num = {v.lower(): k for k, v in enumerate(calendar.month_abbr)} |
|
|
|
|
year_month_regex = re.compile(r'^(?P<year>\d{4})(?P<month>\w{3})$') |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def check_year(value): |
|
|
|
|
year = None |
|
|
|
|
try: |
|
|
|
|
year = int(value) |
|
|
|
|
except (ValueError, ): |
|
|
|
|
return |
|
|
|
|
else: |
|
|
|
|
if not MAXYEAR >= year >= MINYEAR: |
|
|
|
|
return |
|
|
|
|
return year |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class FilterForm(forms.Form): |
|
|
|
|
# TYPES = TYPES |
|
|
|
|
# MEMBERS = MEMBERS |
|
|
|
|
# VISITORS = VISITORS |
|
|
|
|
# PRICE = PRICE |
|
|
|
|
_month_choices = None |
|
|
|
|
_month = None |
|
|
|
|
|
|
|
|
|
event_type = FilterTypedMultipleChoiceField( |
|
|
|
|
label=_(u'Тип события'), coerce=int, |
|
|
|
|
choices=TYPES, required=False, widget=FilterCheckboxSelectMultiple()) |
|
|
|
|
theme = CountModelMultipleChoiceField( |
|
|
|
|
label=_(u'Тематики'), required=False, |
|
|
|
|
label=_(u'Тематики'), required=False, cache_choices=True, |
|
|
|
|
queryset=Theme.objects.language().values('pk', 'name')) |
|
|
|
|
tag = CountModelMultipleChoiceField( |
|
|
|
|
label=_(u'Теги'), required=False, |
|
|
|
|
label=_(u'Теги'), required=False, cache_choices=True, |
|
|
|
|
queryset=Tag.objects.language().values('pk', 'name')) |
|
|
|
|
country = CountModelMultipleChoiceField( |
|
|
|
|
label=_(u'Страны'), required=False, |
|
|
|
|
label=_(u'Страны'), required=False, cache_choices=True, |
|
|
|
|
queryset=Country.objects.language().values('pk', 'name')) |
|
|
|
|
city = CountModelMultipleChoiceField( |
|
|
|
|
label=_(u'Города'), required=False, |
|
|
|
|
label=_(u'Города'), required=False, cache_choices=True, |
|
|
|
|
queryset=City.objects.language().values('pk', 'name')) |
|
|
|
|
price = FilterTypedMultipleChoiceField( |
|
|
|
|
label=_(u'Стоимость'), coerce=int, |
|
|
|
|
choices=PRICE, |
|
|
|
|
required=False, widget=FilterCheckboxSelectMultiple(), |
|
|
|
|
help_text=_(u'За 1 м<sub>2</sub> необорудованной площади')) |
|
|
|
|
# help_text=_(u'За 1 м<sub>2</sub> необорудованной площади') |
|
|
|
|
) |
|
|
|
|
members = FilterTypedMultipleChoiceField( |
|
|
|
|
label=_(u'Участники'), coerce=int, |
|
|
|
|
choices=MEMBERS, |
|
|
|
|
@ -152,6 +212,22 @@ class FilterForm(forms.Form): |
|
|
|
|
label=_(u'Посетители'), coerce=int, |
|
|
|
|
choices=VISITORS, |
|
|
|
|
required=False, widget=FilterCheckboxSelectMultiple()) |
|
|
|
|
year = forms.RegexField(r'^(?P<year>\d{4})$', max_length=4, min_length=4, |
|
|
|
|
required=False, widget=forms.HiddenInput()) |
|
|
|
|
default_month = forms.CharField(max_length=3, min_length=3, |
|
|
|
|
required=False, widget=forms.HiddenInput()) |
|
|
|
|
default_year = forms.RegexField(r'^(?P<year>\d{4})$', max_length=4, min_length=4, |
|
|
|
|
required=False, widget=forms.HiddenInput()) |
|
|
|
|
month = MonthChoiceField( |
|
|
|
|
label=_(u'Период'), coerce=str, |
|
|
|
|
choices=monthes_abr_to_num.iteritems(), |
|
|
|
|
required=False, widget=FilterCheckboxSelectMultiple()) |
|
|
|
|
date_from = forms.DateField(required=False, input_formats=('%d.%m.%Y',), |
|
|
|
|
widget=forms.DateInput(attrs={'class': 'date', 'id': 'dateFrom', |
|
|
|
|
'placeholder': _(u'дд.мм.гггг')})) |
|
|
|
|
date_to = forms.DateField(required=False, input_formats=('%d.%m.%Y',), |
|
|
|
|
widget=forms.DateInput(attrs={'class': 'date', 'id': 'dateTo', |
|
|
|
|
'placeholder': _(u'дд.мм.гггг')})) |
|
|
|
|
|
|
|
|
|
def __init__(self, *args, **kwargs): |
|
|
|
|
super(FilterForm, self).__init__(*args, **kwargs) |
|
|
|
|
@ -159,7 +235,86 @@ class FilterForm(forms.Form): |
|
|
|
|
self._models = None |
|
|
|
|
self._lookup_kwargs = None |
|
|
|
|
self._lookup_args = None |
|
|
|
|
self._related_fields = [] |
|
|
|
|
self._local_fields = [] |
|
|
|
|
self.lang = get_language() |
|
|
|
|
self.data = self.data.copy() |
|
|
|
|
self.fill_default_choices_from_cache() |
|
|
|
|
self.fields['month'].choices = self.month_choices() |
|
|
|
|
|
|
|
|
|
def fill_default_choices_from_cache(self): |
|
|
|
|
timeout = timedelta(hours=1).seconds |
|
|
|
|
for field in ['theme', 'tag', 'country', 'city']: |
|
|
|
|
key ='filter_{field}_{lang}'.format(field=field, lang=self.lang) |
|
|
|
|
choices = cache.get(key) |
|
|
|
|
if choices is None: |
|
|
|
|
choices = list(self.fields[field].choices) |
|
|
|
|
cache.set(key, choices, timeout) |
|
|
|
|
else: |
|
|
|
|
self.fields[field].choice_cache = choices |
|
|
|
|
|
|
|
|
|
@classmethod |
|
|
|
|
def month_choices(cls): |
|
|
|
|
month = datetime.today().month |
|
|
|
|
if cls._month != month or cls._month_choices is None: |
|
|
|
|
year = datetime.today().year |
|
|
|
|
depth = 7 # на сколько сколько месяцев вперед делать выборку (включая текущий) |
|
|
|
|
monthes = dict([(v.get('value'), {'abr': k, 'name': v.get('name')}) for k, v in settings.MONTHES.iteritems()]) |
|
|
|
|
choices = [] |
|
|
|
|
for month_num in xrange(month, month + depth): |
|
|
|
|
_year = year |
|
|
|
|
if month_num > 12: |
|
|
|
|
_year = year + 1 |
|
|
|
|
month_num -= 12 |
|
|
|
|
month_values = monthes.get(month_num) |
|
|
|
|
# month_values['name'] = string_concat(month_values['name'], ' ', str(_year)) |
|
|
|
|
choices.append((str(_year) + month_values['abr'], string_concat(month_values['name'], ' ', str(_year)))) |
|
|
|
|
cls._month_choices = choices |
|
|
|
|
cls._month = month |
|
|
|
|
return cls._month_choices |
|
|
|
|
|
|
|
|
|
def clean_year(self, value=None): |
|
|
|
|
year = value or self.cleaned_data.get('year') |
|
|
|
|
year = check_year(year) |
|
|
|
|
self.fields['month'].year = year |
|
|
|
|
return year |
|
|
|
|
|
|
|
|
|
def clean_default_month(self): |
|
|
|
|
v = self.cleaned_data.get('default_month') |
|
|
|
|
if v and v in settings.MONTHES.keys(): |
|
|
|
|
self.fields['month'].default_month = v |
|
|
|
|
return v |
|
|
|
|
return |
|
|
|
|
|
|
|
|
|
def clean_default_year(self): |
|
|
|
|
y = self.cleaned_data.get('default_year') |
|
|
|
|
y = check_year(y) |
|
|
|
|
return y |
|
|
|
|
|
|
|
|
|
def clean_month(self): |
|
|
|
|
values = self.cleaned_data.get('month', []) |
|
|
|
|
field = self.fields['month'] |
|
|
|
|
new_values = [] |
|
|
|
|
for val in values: |
|
|
|
|
if len(val) == 3 and list(filter(lambda x: x[0] == str(field.year or datetime.today().year) + val, field.choices)): |
|
|
|
|
new_values.append(str(field.year or datetime.today().year) + val) |
|
|
|
|
field.choices = filter(lambda x: x[0] != val, field.choices) |
|
|
|
|
else: |
|
|
|
|
new_values.append(val) |
|
|
|
|
if new_values != values: |
|
|
|
|
self.data.setlist('month', new_values) |
|
|
|
|
return new_values |
|
|
|
|
|
|
|
|
|
def _post_clean(self): |
|
|
|
|
# нужно для того, чтобы год зашел в поле month |
|
|
|
|
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 |
|
|
|
|
|
|
|
|
|
def is_valid(self): |
|
|
|
|
# if getattr(self, '_is_valid', None) is None: |
|
|
|
|
@ -215,6 +370,7 @@ class FilterForm(forms.Form): |
|
|
|
|
def filter(self, qs=None): |
|
|
|
|
qs = qs or self.default_filter() |
|
|
|
|
# lookup_kwargs = dict(ChainMap({}, *(lookup_kwargs or self.lookup_kwargs).values())) |
|
|
|
|
qs = self.make_data_begin_filter(qs) |
|
|
|
|
return qs.filter(**self.lookup_kwargs).order_by('data_begin') |
|
|
|
|
|
|
|
|
|
def default_filter(self, load_all=True, _models=None): |
|
|
|
|
@ -227,6 +383,12 @@ 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) |
|
|
|
|
return qs |
|
|
|
|
|
|
|
|
|
def recalculate_choices(self): |
|
|
|
|
for field in ['theme', 'tag', 'city', 'country']: |
|
|
|
|
# field_qs = self.default_filter(load_all=False) |
|
|
|
|
@ -255,12 +417,18 @@ class FilterForm(forms.Form): |
|
|
|
|
qs.query.having.add(ExtraWhere(having, [], OR), AND) |
|
|
|
|
qs = qs.values(*values).order_by(*order_by) |
|
|
|
|
self.fields[field].queryset = qs |
|
|
|
|
# print(self.fields[field].queryset.query) |
|
|
|
|
|
|
|
|
|
# для того чтобы взяло чойсы из новых результатов |
|
|
|
|
self.fields[field].cache_choices = False |
|
|
|
|
self.fields[field].choice_cache = None |
|
|
|
|
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.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'): |
|
|
|
|
@ -271,11 +439,15 @@ class FilterForm(forms.Form): |
|
|
|
|
choices = [] |
|
|
|
|
for _type, label in TYPES: |
|
|
|
|
qs = self.default_filter(load_all=False, _models=[types.get(_type)]) |
|
|
|
|
qs = self.make_data_begin_filter(qs) |
|
|
|
|
count = qs.filter(**self.lookup_kwargs).count() |
|
|
|
|
choices.append((_type, label + ' <i>({count})</i>'.format(count=count))) |
|
|
|
|
self.fields['event_type'].choices = choices |
|
|
|
|
|
|
|
|
|
def make_ids_in_sql_format(self, values): |
|
|
|
|
# stance(values, (list, tuple, set)): |
|
|
|
|
# return tuple(values) if len(values) > 1 else '({})'.format(*values) |
|
|
|
|
# return |
|
|
|
|
return tuple(values) if len(values) > 1 else '({})'.format(*values) |
|
|
|
|
|
|
|
|
|
def make_joins_from_selected(self, field, model): |
|
|
|
|
@ -364,6 +536,7 @@ class FilterForm(forms.Form): |
|
|
|
|
joins.extend(_joins) |
|
|
|
|
where.extend(_where) |
|
|
|
|
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) |
|
|
|
|
|
|
|
|
|
@ -381,8 +554,7 @@ class FilterForm(forms.Form): |
|
|
|
|
choices.append((val.get('value'), val.get('label') + ' <i>({count})</i>'.format(count=count))) |
|
|
|
|
finally: |
|
|
|
|
c.close() |
|
|
|
|
# some bug with these! |
|
|
|
|
# AttributeError: __exit__ |
|
|
|
|
# some bug with these! AttributeError: __exit__ |
|
|
|
|
# with connection.cursor() as c: |
|
|
|
|
return choices |
|
|
|
|
|
|
|
|
|
@ -390,6 +562,183 @@ class FilterForm(forms.Form): |
|
|
|
|
return ''' (`{db_table}`.`is_published` = True) AND (`{db_table}`.`data_begin` >= '{date_today}') '''\ |
|
|
|
|
.format(date_today=datetime.now().strftime('%Y-%m-%d'), **kwargs) |
|
|
|
|
|
|
|
|
|
def get_date_begin_periods(self): |
|
|
|
|
periods = getattr(self, '_periods', None) |
|
|
|
|
if periods is None: |
|
|
|
|
periods = {} |
|
|
|
|
cleaned_year = self.cleaned_data.get('year') |
|
|
|
|
cleaned_year_str = str(cleaned_year) |
|
|
|
|
year = cleaned_year or datetime.today().year |
|
|
|
|
current_month = datetime.today().month |
|
|
|
|
for value in self.cleaned_data['month']: |
|
|
|
|
match = year_month_regex.match(value) |
|
|
|
|
if match: |
|
|
|
|
_year, month = int(match.group('year')), match.group('month') |
|
|
|
|
elif cleaned_year and cleaned_year == self.clean_year(value=value): |
|
|
|
|
periods.setdefault(cleaned_year, []) |
|
|
|
|
continue |
|
|
|
|
else: |
|
|
|
|
_year = year |
|
|
|
|
month = value |
|
|
|
|
month_num = monthes_abr_to_num.get(month) |
|
|
|
|
periods.setdefault(_year, []).append(month_num) |
|
|
|
|
if cleaned_year\ |
|
|
|
|
and not cleaned_year_str in self.cleaned_data.get('month', [])\ |
|
|
|
|
and not periods.get(cleaned_year)\ |
|
|
|
|
and not self.fields['month'].default_month\ |
|
|
|
|
and not self.cleaned_data.get('default_year'): |
|
|
|
|
periods[cleaned_year] = [] |
|
|
|
|
if self.fields['month'].valid_value(cleaned_year): |
|
|
|
|
self.cleaned_data.setdefault('month', []).append(cleaned_year_str) |
|
|
|
|
self.data.update({'month': cleaned_year_str}) |
|
|
|
|
self.data['default_year'] = cleaned_year_str |
|
|
|
|
elif cleaned_year\ |
|
|
|
|
and not cleaned_year_str in self.cleaned_data.get('month', [])\ |
|
|
|
|
and not periods.get(cleaned_year)\ |
|
|
|
|
and not self.fields['month'].default_month\ |
|
|
|
|
and self.cleaned_data.get('default_year'): |
|
|
|
|
self.fields['month'].choices.insert(0, self.fields['month'].make_year_choice(cleaned_year)) |
|
|
|
|
elif cleaned_year and cleaned_year_str in self.cleaned_data.get('month', []) and periods.get(cleaned_year): |
|
|
|
|
periods[cleaned_year] = [] |
|
|
|
|
cleaned = self.data.getlist('month', []) |
|
|
|
|
cleaned.remove(cleaned_year_str) |
|
|
|
|
self.cleaned_data.setdefault('month', []).remove(cleaned_year_str) |
|
|
|
|
self.data.setlist('month', cleaned) |
|
|
|
|
elif cleaned_year and periods.get(cleaned_year) and not self.fields['month'].default_month: |
|
|
|
|
self.fields['month'].valid_value(cleaned_year) |
|
|
|
|
elif cleaned_year and self.fields['month'].default_month\ |
|
|
|
|
and not list(filter(lambda x: x[0] == cleaned_year_str + self.fields['month'].default_month, self.fields['month'].choices)): |
|
|
|
|
self.fields['month'].valid_value(self.fields['month'].default_month) |
|
|
|
|
self._periods = periods |
|
|
|
|
return periods |
|
|
|
|
|
|
|
|
|
def make_date_begin_where(self, where, **kwargs): |
|
|
|
|
_where = [] |
|
|
|
|
# years = {} |
|
|
|
|
# current_month = datetime.today().month |
|
|
|
|
# year = datetime.today().year |
|
|
|
|
# for month in self.cleaned_data['month']: |
|
|
|
|
# month_num = monthes_abr_to_num.get(month) |
|
|
|
|
# _year = year |
|
|
|
|
# if month_num < current_month: |
|
|
|
|
# _year += 1 |
|
|
|
|
# years.setdefault(_year, []).append(month_num) |
|
|
|
|
# kwargs.update(years) |
|
|
|
|
add_years = set() |
|
|
|
|
for year, monthes in self.get_date_begin_periods().iteritems(): |
|
|
|
|
if monthes: |
|
|
|
|
_where.append( |
|
|
|
|
''' (month(`{db_table}`.`data_begin`) in {monthes} and year(`{db_table}`.`data_begin`) = {year}) '''\ |
|
|
|
|
.format(year=year, monthes=self.make_ids_in_sql_format(monthes), **kwargs) |
|
|
|
|
) |
|
|
|
|
else: |
|
|
|
|
add_years.add(year) |
|
|
|
|
if add_years: |
|
|
|
|
_where.append( |
|
|
|
|
''' (year(`{db_table}`.`data_begin`) in {year}) '''\ |
|
|
|
|
.format(year=self.make_ids_in_sql_format(add_years), **kwargs) |
|
|
|
|
) |
|
|
|
|
if len(_where) == 1: |
|
|
|
|
where.extend(_where) |
|
|
|
|
elif len(_where) > 1: |
|
|
|
|
where.append(''' ({}) '''.format(' OR '.join(_where))) |
|
|
|
|
return |
|
|
|
|
|
|
|
|
|
# def get_prev_month(self, date): |
|
|
|
|
# year = date.year |
|
|
|
|
# month = date.month |
|
|
|
|
# day = date.day |
|
|
|
|
# last_day = False |
|
|
|
|
# if day == calendar.monthrange(year, month)[1]: |
|
|
|
|
# last_day = True |
|
|
|
|
# if date.month == 1: |
|
|
|
|
# year -= 1 |
|
|
|
|
# month = 12 |
|
|
|
|
# if last_day: |
|
|
|
|
# day = calendar.monthrange(year, month)[1] |
|
|
|
|
# return date.replace(month=month, year=year, day=day) |
|
|
|
|
|
|
|
|
|
# def get_next_month(self, date): |
|
|
|
|
# year = date.year |
|
|
|
|
# month = date.month |
|
|
|
|
# day = date.day |
|
|
|
|
# last_day = False |
|
|
|
|
# if day == calendar.monthrange(year, month)[1]: |
|
|
|
|
# last_day = True |
|
|
|
|
# if date.month == 12: |
|
|
|
|
# year += 1 |
|
|
|
|
# month = 1 |
|
|
|
|
# if last_day: |
|
|
|
|
# day = calendar.monthrange(year, month)[1] |
|
|
|
|
# return date.replace(month=month, year=year, day=day) |
|
|
|
|
|
|
|
|
|
def get_start_of_period(self, year, periods, month=None): |
|
|
|
|
if month is None: |
|
|
|
|
return year, 1 |
|
|
|
|
self.checked_monthes.setdefault(year, set()).add(month) |
|
|
|
|
if month == 12: |
|
|
|
|
prev_month = month - 1 |
|
|
|
|
prev_year = year |
|
|
|
|
elif month == 1: |
|
|
|
|
prev_month = 12 |
|
|
|
|
prev_year = year - 1 |
|
|
|
|
else: |
|
|
|
|
prev_month = month - 1 |
|
|
|
|
prev_year = year |
|
|
|
|
if prev_month in periods.get(prev_year, []): |
|
|
|
|
return self.get_start_of_period(prev_year, periods, prev_month) |
|
|
|
|
return year, month |
|
|
|
|
|
|
|
|
|
def get_end_of_period(self, year, periods, month=None): |
|
|
|
|
if month is None: |
|
|
|
|
return year, 12 |
|
|
|
|
self.checked_monthes.setdefault(year, set()).add(month) |
|
|
|
|
if month == 12: |
|
|
|
|
next_month = 1 |
|
|
|
|
next_year = year + 1 |
|
|
|
|
elif month == 1: |
|
|
|
|
next_month = month + 1 |
|
|
|
|
next_year = year |
|
|
|
|
else: |
|
|
|
|
next_month = month + 1 |
|
|
|
|
next_year = year |
|
|
|
|
if next_month in periods.get(next_year, []): |
|
|
|
|
return self.get_end_of_period(next_year, periods, next_month) |
|
|
|
|
return year, month |
|
|
|
|
|
|
|
|
|
def make_date_begin_sqs_params(self): |
|
|
|
|
periods = [] |
|
|
|
|
self.checked_monthes = {} |
|
|
|
|
cleaned_periods = self.get_date_begin_periods() |
|
|
|
|
# print(cleaned_periods) |
|
|
|
|
for year, monthes in cleaned_periods.iteritems(): |
|
|
|
|
for month in monthes: |
|
|
|
|
if month in self.checked_monthes.get(year, []): |
|
|
|
|
continue |
|
|
|
|
start_year, start_month = self.get_start_of_period(year, cleaned_periods, month) |
|
|
|
|
end_year, end_month = self.get_end_of_period(year, cleaned_periods, month) |
|
|
|
|
_first_day, _last_day = calendar.monthrange(end_year, end_month) |
|
|
|
|
periods.append(( |
|
|
|
|
date.today().replace(day=1, month=start_month, year=start_year), |
|
|
|
|
date.today().replace(day=_last_day, month=end_month, year=end_year) |
|
|
|
|
)) |
|
|
|
|
else: |
|
|
|
|
start_year, start_month = self.get_start_of_period(year, cleaned_periods) |
|
|
|
|
end_year, end_month = self.get_end_of_period(year, cleaned_periods) |
|
|
|
|
_first_day, _last_day = calendar.monthrange(end_year, end_month) |
|
|
|
|
periods.append(( |
|
|
|
|
date.today().replace(day=1, month=start_month, year=start_year), |
|
|
|
|
date.today().replace(day=_last_day, month=end_month, year=end_year) |
|
|
|
|
)) |
|
|
|
|
|
|
|
|
|
params = None |
|
|
|
|
for start, end in periods: |
|
|
|
|
if params is None: |
|
|
|
|
params = SQ(data_begin__range=(start, end)) |
|
|
|
|
else: |
|
|
|
|
params |= SQ(data_begin__range=(start, end)) |
|
|
|
|
return params |
|
|
|
|
|
|
|
|
|
def make_count_select(self, field): |
|
|
|
|
selects = [] |
|
|
|
|
case = None |
|
|
|
|
@ -452,7 +801,7 @@ class FilterForm(forms.Form): |
|
|
|
|
joins.extend(_joins) |
|
|
|
|
where.extend(_where) |
|
|
|
|
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) |
|
|
|
|
|
|
|
|
|
if len(selects) == 2: |
|
|
|
|
|