# -*- coding: utf-8 -*- import operator from django import forms from django.conf import settings from django.db.models import Q from price.models import Good class CustomSelect(forms.widgets.Select): """ Custom Select widget that allow to define label for None choice. """ def __init__(self, default_label, **kwargs): self.default_label = default_label super(self.__class__, self).__init__(**kwargs) def render(self, *args, **kwargs): self.choices = list(self.choices) self.choices[0] = (u'', self.default_label) return super(self.__class__, self).render(*args, **kwargs) class SearchGoodsForm(forms.Form): query = forms.CharField(required=False, label='') firm = Good._meta.get_field('firm').formfield(required=False, label='', widget=CustomSelect(default_label='Все фирмы')) def __init__(self, GET, *args, **kwargs): query = kwargs.pop('query', None) if not 'query' in GET: GET = GET.copy() GET['query'] = query super(SearchGoodsForm, self).__init__(GET, *args, **kwargs) def split_query(self, query): """ Extract valid parts from search query. """ return set([x for x in query.split()\ if len(x) >= settings.QUERY_PART_MIN_LENGTH]) def clean_query(self): if 'query' in self.cleaned_data: query = self.cleaned_data['query'] # Empty query is OK! if not query: return query if len(query) > settings.QUERY_SIZE_LIMIT: raise forms.ValidationError(u'Слишком длинный запрос') query = self.cleaned_data['query'] query = self.split_query(query) if not query: raise forms.ValidationError(u'Слишком короткий запрос') elif len(query) > settings.QUERY_PART_NUMBER_LIMIT: raise forms.ValidationError(u'Слишком много подзапросов') return query def query_display(self): """ Return human readable representation of parsed query. """ if hasattr(self, 'cleaned_data') and 'query' in self.cleaned_data: return ' '.join(self.cleaned_data['query']) else: return '' def filter(self, paged_qs): """ Filter QuerySet with parameters from form's fields. """ if self.cleaned_data['query']: filters = [Q(name__icontains=x) for x in self.cleaned_data['query']] paged_qs = paged_qs.filter(reduce(operator.and_, filters)) if self.cleaned_data['firm']: paged_qs = paged_qs.filter(firm=self.cleaned_data['firm']) return paged_qs