abetkin
3/11/2014 - 4:08 PM

QSimpleFilter.py

#coding: utf-8
import re
import inspect
import operator

from django.db.models import Q, query

import rest_framework

class QSimpleFilter(rest_framework.filters.BaseFilterBackend):
    '''
    Специальные методы определяются по регэкспу. Они должны возвращать Q.
    Фильтры объединяются через AND или OR в зависимости от флага combine.
    '''
    method_regexps = [r'^filter_by_(.*)']
    combine = 'AND'
    
    def special_methods(self):
        'Должны возвращать Q объекты'
        for regexp in self.method_regexps:
            for attr in dir(self):
                item = getattr(self, attr)
                match = re.search(regexp, attr)
                if not match:
                    continue
                if inspect.ismethod(item):
                    yield (match.group(1), item)

    def filter_queryset(self, request, queryset, view):
        GET = dict(request.GET.items())
        q_filters = [method(queryset, GET.get(param))
            for param, method in self.special_methods()
            if param in GET]
        if q_filters:
            assert self.combine in ('AND', 'OR')
            operation = operator.and_ if self.combine == 'AND' \
                        else operator.or_
            try:
                queryset = queryset.filter(reduce(operation, q_filters))
            except:
                queryset = query.EmptyQuerySet()
        return queryset