From 26be9611ce8af6e7c4eb783586bb58591139b98f Mon Sep 17 00:00:00 2001 From: Andrey Date: Fri, 3 Mar 2017 16:59:24 +0300 Subject: [PATCH] docs: fully rewrote filters --- project/docs/filters.py | 139 +++++++++++++++---------------- project/docs/views/aktrabot.py | 7 +- project/docs/views/aktsverki.py | 5 +- project/docs/views/base_views.py | 12 +-- project/docs/views/dover.py | 5 +- project/docs/views/faktura.py | 8 +- project/docs/views/invoice.py | 7 +- project/docs/views/nakladn.py | 5 +- project/docs/views/platejka.py | 5 +- 9 files changed, 84 insertions(+), 109 deletions(-) diff --git a/project/docs/filters.py b/project/docs/filters.py index 478e174..a46c3e6 100644 --- a/project/docs/filters.py +++ b/project/docs/filters.py @@ -5,7 +5,7 @@ import django_filters from project.customer.models import Client -from .models import Invoice, Platejka +from .models import Invoice from . import consts @@ -134,77 +134,68 @@ platej_type_choices = ( ) -class _BaseFilterSet(django_filters.FilterSet): - """Базовый класс фильтров. - Классы фильтров строить через build_filterset_class ! +class BaseDocsFilterSet(django_filters.FilterSet): + """Базовый класс всех фильтров документов. + Работает и без Meta. """ - class Meta: - model = None - - def __init__(self, user, *args, **kwargs): - super(_BaseFilterSet, self).__init__(*args, **kwargs) - self.form.label_suffix = '' - - -def build_filterset_class(model, user, need_fields=None): - """Строит и возвращает класс с набором фильтров для фильтрации документов.""" - attrs = {} - fields = [] - - for f in need_fields: - if f == 'doc_date': - doc_date = CustomDateRangeFilter(label=u'По времени создания', options=doc_date_choices, - widget=django_filters.widgets.LinkWidget) - attrs['doc_date'] = doc_date - fields.append('doc_date') - - elif f == 'client': - client = django_filters.ModelChoiceFilter(label=u'По контрагенту', queryset=Client.objects.get_all(user.profile), - empty_label=u'все контрагенты') - attrs['client'] = client - fields.append('client') - - elif f == 'invoice': - invoice = django_filters.ModelChoiceFilter(label=u'По счёту', queryset=Invoice.objects.get_all(user.profile), - empty_label=u'все счета') - attrs['invoice'] = invoice - fields.append('invoice') - - elif f == 'closed_status': - closed_status = django_filters.ChoiceFilter(label=u'По закрывающим документам', choices=closed_status_choices, - widget=django_filters.widgets.LinkWidget) - attrs['closed_status'] = closed_status - fields.append('closed_status') - - elif f == 'paid_status': - paid_status = django_filters.ChoiceFilter(label=u'По оплате', choices=paid_status_choices, - widget=django_filters.widgets.LinkWidget) - attrs['paid_status'] = paid_status - fields.append('paid_status') - - elif f == 'signed_status': - signed_status = django_filters.ChoiceFilter(label=u'По приёмке', choices=signed_status_choices, - widget=django_filters.widgets.LinkWidget) - attrs['signed_status'] = signed_status - fields.append('signed_status') - - elif f == 'total_saldo': - total_saldo = CustomChoiceFilter(label=u'По сальдо', options=total_saldo_choices, - widget=django_filters.widgets.LinkWidget) - attrs['total_saldo'] = total_saldo - fields.append('total_saldo') - - elif f == 'platej_type': - platej_type = django_filters.ChoiceFilter(label=u'По типу', choices=platej_type_choices, - widget=django_filters.widgets.LinkWidget) - attrs['platej_type'] = platej_type - fields.append('platej_type') - - else: - raise NotImplementedError(u'Unknown field: "%s".' % f) - - model_name = model.__name__.lower() - klass = type(model_name+'FilterSet', (_BaseFilterSet,), attrs) - klass.Meta.model = model - klass.Meta.fields = fields# + _BaseFilterSet.Meta.fields - return klass + + def __init__(self, request, *args, **kwargs): + super(BaseDocsFilterSet, self).__init__(*args, **kwargs) + + self.request = request + + if 'client' in self.filters: + self.filters['client'].extra['queryset'] = Client.objects.get_all(self.request.user.profile) + + if 'invoice' in self.filters: + self.filters['invoice'].extra['queryset'] = Invoice.objects.get_all(self.request.user.profile) + + # сбросить у полей формы атрибут help_text + for field in self.form.fields.itervalues(): + field.help_text = None + + +class InvoiceFilterSet(BaseDocsFilterSet): + paid_status = django_filters.ChoiceFilter(label=u'По оплате', choices=paid_status_choices, widget=django_filters.widgets.LinkWidget) + closed_status = django_filters.ChoiceFilter(label=u'По закрывающим документам', choices=closed_status_choices, widget=django_filters.widgets.LinkWidget) + client = django_filters.ModelChoiceFilter(label=u'По контрагенту', queryset=None, empty_label=u'все контрагенты') + doc_date = CustomDateRangeFilter(label=u'По времени создания', options=doc_date_choices, widget=django_filters.widgets.LinkWidget) + + +class AktRabotFilterSet(BaseDocsFilterSet): + signed_status = django_filters.ChoiceFilter(label=u'По приёмке', choices=signed_status_choices, widget=django_filters.widgets.LinkWidget) + client = django_filters.ModelChoiceFilter(label=u'По контрагенту', queryset=None, empty_label=u'все контрагенты') + invoice = django_filters.ModelChoiceFilter(label=u'По счёту', queryset=None, empty_label=u'все счета') + doc_date = CustomDateRangeFilter(label=u'По времени создания', options=doc_date_choices, widget=django_filters.widgets.LinkWidget) + + +class NakladnFilterSet(BaseDocsFilterSet): + signed_status = django_filters.ChoiceFilter(label=u'По приёмке', choices=signed_status_choices, widget=django_filters.widgets.LinkWidget) + client = django_filters.ModelChoiceFilter(label=u'По контрагенту', queryset=None, empty_label=u'все контрагенты') + invoice = django_filters.ModelChoiceFilter(label=u'По счёту', queryset=None, empty_label=u'все счета') + doc_date = CustomDateRangeFilter(label=u'По времени создания', options=doc_date_choices, widget=django_filters.widgets.LinkWidget) + + +class FakturaFilterSet(BaseDocsFilterSet): + signed_status = django_filters.ChoiceFilter(label=u'По приёмке', choices=signed_status_choices, widget=django_filters.widgets.LinkWidget) + client = django_filters.ModelChoiceFilter(label=u'По контрагенту', queryset=None, empty_label=u'все контрагенты') + invoice = django_filters.ModelChoiceFilter(label=u'По счёту', queryset=None, empty_label=u'все счета') + doc_date = CustomDateRangeFilter(label=u'По времени создания', options=doc_date_choices, widget=django_filters.widgets.LinkWidget) + + +class AktSverkiFilterSet(BaseDocsFilterSet): + signed_status = django_filters.ChoiceFilter(label=u'По приёмке', choices=signed_status_choices, widget=django_filters.widgets.LinkWidget) + client = django_filters.ModelChoiceFilter(label=u'По контрагенту', queryset=None, empty_label=u'все контрагенты') + total_saldo = CustomChoiceFilter(label=u'По сальдо', options=total_saldo_choices, widget=django_filters.widgets.LinkWidget) + doc_date = CustomDateRangeFilter(label=u'По времени создания', options=doc_date_choices, widget=django_filters.widgets.LinkWidget) + + +class DoverFilterSet(BaseDocsFilterSet): + client = django_filters.ModelChoiceFilter(label=u'По контрагенту', queryset=None, empty_label=u'все контрагенты') + doc_date = CustomDateRangeFilter(label=u'По времени создания', options=doc_date_choices, widget=django_filters.widgets.LinkWidget) + + +class PlatejkaFilterSet(BaseDocsFilterSet): + platej_type = django_filters.ChoiceFilter(label=u'По типу', choices=platej_type_choices, widget=django_filters.widgets.LinkWidget) + client = django_filters.ModelChoiceFilter(label=u'По контрагенту', queryset=None, empty_label=u'все контрагенты') + doc_date = CustomDateRangeFilter(label=u'По времени создания', options=doc_date_choices, widget=django_filters.widgets.LinkWidget) diff --git a/project/docs/views/aktrabot.py b/project/docs/views/aktrabot.py index 5f5adb9..83f4582 100644 --- a/project/docs/views/aktrabot.py +++ b/project/docs/views/aktrabot.py @@ -3,7 +3,8 @@ from decimal import Decimal from ..models import AktRabot, AktRabotItem from ..forms import AktRabotForm, AktRabotItemForm -from .. import consts, utils +from ..filters import AktRabotFilterSet +from .. import utils from .base_views import BaseItemsViews from .mixins import AddByInvoiceMethodMixin @@ -19,9 +20,7 @@ class AktRabotViews(BaseItemsViews, AddByInvoiceMethodMixin): ITEM_FORM_CLASS = AktRabotItemForm # форма табличной части документа ITEM_FORM_PREFIX = 'aktrabot_items' # префикс формы табличной части - # поля, по которым можно фильтровать список документов - # должны поддерживаться в docs.filters.build_filterset_class ! - FILTER_FIELDS = ('signed_status', 'client', 'invoice', 'doc_date',) + FILTERSET_CLASS = AktRabotFilterSet # фильтры # по какому полю суммировать табличную часть документа при показе списком LIST_SUM_FIELD = 'aktrabot_items__total_price' diff --git a/project/docs/views/aktsverki.py b/project/docs/views/aktsverki.py index 94c2f30..e1edc2d 100644 --- a/project/docs/views/aktsverki.py +++ b/project/docs/views/aktsverki.py @@ -5,6 +5,7 @@ from project.customer.forms import ClientsListForm from ..models import AktSverki, AktSverkiItem from ..forms import AktSverkiForm, AktSverkiItemForm +from ..filters import AktSverkiFilterSet from .base_views import BaseItemsViews @@ -22,9 +23,7 @@ class AktSverkiViews(BaseItemsViews): # поля, по которым можно сортировать список документов ORDER_FIELDS = ('doc_date', 'doc_num', 'client__name',) - # поля, по которым можно фильтровать список документов - # должны поддерживаться в docs.filters.build_filterset_class ! - FILTER_FIELDS = ('signed_status', 'client', 'total_saldo', 'doc_date',) + FILTERSET_CLASS = AktSverkiFilterSet # фильтры # префикс именованных урлов этого типа документов, для передачи в шаблон URL_PREFIX = 'docs_aktsverki_' diff --git a/project/docs/views/base_views.py b/project/docs/views/base_views.py index 6bceefc..f5e4108 100644 --- a/project/docs/views/base_views.py +++ b/project/docs/views/base_views.py @@ -67,9 +67,7 @@ class BaseViews(object): # поля, по которым можно сортировать список документов ORDER_FIELDS = ('doc_date', 'doc_num', 'client__name', 'doc_sum',) - # поля, по которым можно фильтровать список документов - # должны поддерживаться в docs.filters.build_filterset_class ! - FILTER_FIELDS = ('client', 'doc_date',) + FILTERSET_CLASS = None # фильтры # префикс именованных урлов документов данного типа, для передачи в шаблон URL_PREFIX = '' @@ -133,6 +131,7 @@ class BaseViews(object): assert self.FORM_CLASS is not None, (u"%s.FORM_CLASS can't be None!" % self.__class__.__name__) assert self.EMAIL_FORM_CLASS is not None, (u"%s.EMAIL_FORM_CLASS can't be None!" % self.__class__.__name__) assert (isinstance(self.ORDER_FIELDS, tuple) or isinstance(self.ORDER_FIELDS, list)), (u"%s.ORDER_FIELDS should be of tuple or list type!" % self.__class__.__name__) + assert self.FILTERSET_CLASS is not None, (u"%s.FILTERSET_CLASS can't be None!" % self.__class__.__name__) def set_redirects(self): """Куда редиректить после операции.""" @@ -162,14 +161,9 @@ class BaseViews(object): qs = qs.order_by('%s%s' % ((order_type == 'desc' and '-' or ''), order_field,)) return qs - def get_filters_class(self): - """Возвращает класс с набором фильтров.""" - return filters.build_filterset_class(self.MODEL, self.request.user, self.FILTER_FIELDS) - def get_filters(self, qs): """Возвращает объект с набором фильтров.""" - klass = self.get_filters_class() - return klass(self.request.user, self.request.GET, qs) + return self.FILTERSET_CLASS(self.request, data=self.request.GET, queryset=qs) def get_obj(self, id, only_form_fields=False): """Объект документа или ошибка 404, если его нет в базе. diff --git a/project/docs/views/dover.py b/project/docs/views/dover.py index 7288535..77d7177 100644 --- a/project/docs/views/dover.py +++ b/project/docs/views/dover.py @@ -5,6 +5,7 @@ from project.customer.forms import ClientsListForm from ..models import Dover, DoverItem from ..forms import DoverForm, DoverItemForm +from ..filters import DoverFilterSet from .base_views import BaseItemsViews @@ -22,9 +23,7 @@ class DoverViews(BaseItemsViews): # поля, по которым можно сортировать список документов ORDER_FIELDS = ('doc_num', 'doc_date', 'doc_expire_date', 'dover_name', 'client__name',) - # поля, по которым можно фильтровать список документов - # должны поддерживаться в docs.filters.build_filterset_class ! - FILTER_FIELDS = ('client', 'doc_date',) + FILTERSET_CLASS = DoverFilterSet # фильтры # префикс именованных урлов этого типа документов, для передачи в шаблон URL_PREFIX = 'docs_dover_' diff --git a/project/docs/views/faktura.py b/project/docs/views/faktura.py index 8faab5b..2abce85 100644 --- a/project/docs/views/faktura.py +++ b/project/docs/views/faktura.py @@ -2,12 +2,10 @@ from decimal import Decimal from django.utils.text import wrap -from django.utils.decorators import method_decorator -from django.views.decorators.csrf import csrf_protect -from django.forms.models import inlineformset_factory from ..models import Faktura, FakturaItem from ..forms import FakturaForm, FakturaItemForm +from ..filters import FakturaFilterSet from .. import utils from .base_views import BaseItemsViews @@ -24,9 +22,7 @@ class FakturaViews(BaseItemsViews, AddByInvoiceMethodMixin): ITEM_FORM_CLASS = FakturaItemForm # форма табличной части документа ITEM_FORM_PREFIX = 'faktura_items' # префикс формы табличной части - # поля, по которым можно фильтровать список документов - # должны поддерживаться в docs.filters.build_filterset_class ! - FILTER_FIELDS = ('signed_status', 'client', 'invoice', 'doc_date',) + FILTERSET_CLASS = FakturaFilterSet # фильтры # по какому полю суммировать табличную часть документа при показе списком LIST_SUM_FIELD = 'faktura_items__total_price' diff --git a/project/docs/views/invoice.py b/project/docs/views/invoice.py index c83d335..8773df4 100644 --- a/project/docs/views/invoice.py +++ b/project/docs/views/invoice.py @@ -5,7 +5,8 @@ from project.customer.forms import ClientsListForm from ..models import Invoice, InvoiceItem from ..forms import InvoiceForm, InvoiceItemForm -from .. import consts, utils, filters +from ..filters import InvoiceFilterSet +from .. import utils from .base_views import BaseItemsViews @@ -22,9 +23,7 @@ class InvoiceViews(BaseItemsViews): ORDER_FIELDS = ('doc_date', 'doc_num', 'client__name', 'doc_sum', 'paid_status', 'closed_status') - # поля, по которым можно фильтровать список документов - # должны поддерживаться в docs.filters.build_filterset_class ! - FILTER_FIELDS = ('paid_status', 'closed_status', 'client', 'doc_date',) + FILTERSET_CLASS = InvoiceFilterSet # фильтры # по какому полю суммировать табличную часть документа при показе списком LIST_SUM_FIELD = 'invoice_items__total_price' diff --git a/project/docs/views/nakladn.py b/project/docs/views/nakladn.py index 27045cd..b0c89c3 100644 --- a/project/docs/views/nakladn.py +++ b/project/docs/views/nakladn.py @@ -5,6 +5,7 @@ from django.utils.text import wrap from ..models import Nakladn, NakladnItem from ..forms import NakladnForm, NakladnItemForm +from ..filters import NakladnFilterSet from .. import utils from .base_views import BaseItemsViews @@ -21,9 +22,7 @@ class NakladnViews(BaseItemsViews, AddByInvoiceMethodMixin): ITEM_FORM_CLASS = NakladnItemForm # форма табличной части документа ITEM_FORM_PREFIX = 'nakladn_items' # префикс формы табличной части - # поля, по которым можно фильтровать список документов - # должны поддерживаться в docs.filters.build_filterset_class ! - FILTER_FIELDS = ('signed_status', 'client', 'invoice', 'doc_date',) + FILTERSET_CLASS = NakladnFilterSet # фильтры # по какому полю суммировать табличную часть документа при показе списком LIST_SUM_FIELD = 'nakladn_items__total_price' diff --git a/project/docs/views/platejka.py b/project/docs/views/platejka.py index bdf0846..7d09451 100644 --- a/project/docs/views/platejka.py +++ b/project/docs/views/platejka.py @@ -1,6 +1,7 @@ # -*- coding: utf-8 -*- from ..models import Platejka from ..forms import PlatejkaForm +from ..filters import PlatejkaFilterSet from .base_views import BaseViews @@ -14,9 +15,7 @@ class PlatejkaViews(BaseViews): # поля, по которым можно сортировать список документов ORDER_FIELDS = ('doc_date', 'doc_num', 'doc_info', 'doc_total',) - # поля, по которым можно фильтровать список документов - # должны поддерживаться в docs.filters.build_filterset_class ! - FILTER_FIELDS = ('platej_type', 'client', 'doc_date',) + FILTERSET_CLASS = PlatejkaFilterSet # фильтры # префикс именованных урлов этого типа документов, для передачи в шаблон URL_PREFIX = 'docs_platejka_'