ajax_slickgrid.py 4.43 KB
#-*- coding:utf-8 -*-

from accounts.models import filtering_mode

class SlickGridQuery(object):
    model = None
    sort_field = None
    filter_field_translation = {}
    select_related = []

    lookup_translation = {
        'eq': 'exact',
        'ne': '-exact',
        'bw': 'startswith',
        'bn': '-startswith',
        'ew': 'endswith',
        'en': '-endswith',
        'cn': 'contains',
        'nc': '-contains',
        're': 'regex',
        'nr': '-regex',
        'le': 'lte',
        'ge': 'gte',
    }

    def __init__(self, filter, sort_rules, mask, user):
        self.filter = filter
        self.sort_rules = sort_rules
        self.mask = mask
        self.user = user

    def filtering_mode(self):
        return filtering_mode(self.user)

    def get_queryset(self):
        return self.model.objects.all()

    def get_empty_queryset(self):
        return self.model.objects.none()

    def apply_filter_rule(self, queryset, rule):
        lookup = self.lookup_translation[rule['op']]
        negated = (lookup[0] == '-')
        lookup = lookup.lstrip('-')
        field = self.filter_field_translation.get(rule['field'], rule['field'])
        data = rule['data']
        arg = {(field + '__' + lookup): data}
        if negated:
            queryset = queryset.exclude(**arg)
        else:
            queryset = queryset.filter(**arg).distinct()
        return queryset

    def apply_filter(self):
        queryset = self.get_queryset()
        if self.filter:
            if self.filter['group_op'] == 'AND':
                for rule in self.filter['rules']:
                    queryset = self.apply_filter_rule(queryset, rule)
            elif self.filter['group_op'] == 'OR':
                new_queryset = self.get_empty_queryset()
                for rule in self.filter['rules']:
                    new_queryset |= self.apply_filter_rule(queryset, rule)
                queryset = new_queryset
        return queryset

    def sort_queryset(self, queryset):
        order_list = [self.sort_field]
        return queryset.extra(order_by=order_list)

    def apply_mask(self, queryset):
        pass # abstract

    def filter_from(self, queryset, from_value, upward):
        lookup = '__gte' if upward else '__lte'
        return queryset.filter(**{self.sort_field + lookup: from_value})

    # indeks wiersza w danym sortowaniu, w którym
    # znajdzie się rekord o danym id
    def row_index(self, record_id):
        selected = self.model.objects.get(pk=record_id)
        queryset = self.apply_filter()
        if self.filtering_mode():
            queryset = self.apply_mask(queryset)
        if queryset.count() == 0:
            return 0
        data = getattr(selected, self.sort_field)
        preceding = self.filter_from(
            queryset, from_value=data, upward=False)
        return max(preceding.count() - 1, 0)

    def search_index(self):
        queryset = self.apply_filter()
        count = queryset.count()
        if count > 0 and self.mask == '':
            return 0
        if self.filtering_mode():
            queryset = self.apply_mask(queryset)
        if queryset.count() > 0:
            whole_queryset = queryset
            queryset = self.filter_from(
                queryset, from_value=self.mask, upward=True)
            if queryset.count() == 0:
                queryset = whole_queryset
            queryset = self.sort_queryset(queryset)
            index = self.row_index(queryset[0].id)
        else:
            index = 0
        return index

    def get_sorted_queryset(self):
        queryset = self.apply_filter()
        if self.filtering_mode():
            queryset = self.apply_mask(queryset)
        return self.sort_queryset(queryset)

    def count_pages(self, from_page, to_page, limit):
        start = limit * from_page
        pages = to_page - from_page + 1
        response_rowcount = limit * pages
        return start, response_rowcount

    def response_row(self, record):
        pass # abstract

    def prepare_rows(self, records):
        return [self.response_row(record) for record in records]

    def get_page(self, from_page, to_page, limit):
        queryset = self.get_sorted_queryset()
        if self.select_related:
            queryset = queryset.select_related(self.select_related)
        count = queryset.count()
        start, response_rowcount = self.count_pages(from_page, to_page, limit)
        records = queryset[start:start + response_rowcount]
        return self.prepare_rows(records), count