def value_from_datadict(self, data, files, name): sub_data = {} sub_field_regex = re.compile( r'^{}\-(?P<sub_form_index>[0-9]+)\-(?P<sub_field_name>.+)$'.format( re.escape(name) ) ) for key, value in data.iteritems(): match = sub_field_regex.match(key) if match is not None: form_index = int(match.group('sub_form_index')) sub_data.setdefault(form_index, {}) sub_data[form_index][match.group('sub_field_name')] = value sub_data = [sdata for _index, sdata in sorted(sub_data.iteritems(), key=itemgetter(0))] if not isinstance(data, (MultiValueDict, MergeDict)): data = MultiValueDict(data.copy()) deleted_pks = data.getlist('{}-DELETE'.format(name)) # MultiValueDict.getlist() might return a single element instead of a list... if not isinstance(deleted_pks, list): deleted_pks = [deleted_pks, ] sub_data = DataListWithDeletedPKs( sub_data, deleted_pks=list(set(deleted_pks)) ) return sub_data
class QueryStringManager(object): """ QueryStringManager can be used to automatically set filters on listing. We take idea from django.contrib.admin.views.main.ChangeList class, but without all admin functionality (less coupled principle) However, it implements foofield__id__in filters, for example, equivalent to: FooModel.objects.filter(category__id__in=[8,9]) Example of use, with a request like http://foo.com?category__id__in=9&category__id__in=8: >>> qsm = QueryStringManager(request) >>> qsm.get_params() <MultiValueDict: {'category__id__in': [u'9', u'8']}> >>> qsm.get_query_string() u'?category__id__in=9&category__id__in=8' >>> qsm.get_filters() <MultiValueDict: {'category__id__in': [u'9', u'8']}> You can then use it in a view with: def foo_listing(request, ...): qsm = QueryStringManager(request) queryset = FooModel.objects.all() queryset = queryset.filter(qsm.get_filters()) category_choices = Category.objects.filter(parent__isnull=True) render_to_response('foo_listing.html', {'queryset': queryset, 'qsm': qsm, 'category_choices': category_choices} ) And last, in template you can use cmsutils admin filters with: {% load modelfilters %} {% filter_for_model 'fooapp' 'foomodel' 'publish_date' %} {% filter_for_model 'fooapp' 'foomodel' 'category' category_choices %} """ def __init__(self, request, search_fields=[], page_var=PAGE_VAR, ignore_params=[]): self.params = MultiValueDict() self.filters = MultiValueDict() self.excluders = MultiValueDict() self.search_fields = MultiValueDict() self.page=None if request is None: return raw_filters = {} for key, l in request.GET.lists(): if key == page_var: self.page = l elif key.startswith('__') or key in ignore_params: # private arg continue elif key.endswith('_0') or key.endswith('_1'): if key.endswith('_0'): key_new, l_new = self._convert_filter_splitdatetime(request, key, l, '_0', raw_filters) elif key.endswith('_1'): key_new, l_new = self._convert_filter_splitdatetime(request, key, l, '_1', raw_filters) raw_filters[key_new] = l_new else: raw_filters[key] = l good_filters = self.sanitize_filters(raw_filters) for key, l in good_filters.items(): try: key = str(key) except UnicodeEncodeError: key = 'key_%s' % len(l) self._set_into_dict(self.params, key, l) if key in search_fields: self._set_into_dict(self.search_fields, key, l) elif u'not_' in key: self._set_into_dict(self.excluders, key, l) else: self._set_into_dict(self.filters, key, l) def sanitize_filters(self, filters): # hook to searchform return filters def _get_from_dict(self, multidict, key): if key.endswith(IN_LOOKUP): return multidict.getlist(str(key)) else: return multidict.get(str(key)) def _set_into_dict(self, multidict, key, value): if key.endswith(IN_LOOKUP): multidict.setlist(str(key), value) else: multidict[str(key)] = value[0] def _get_multidict_items(self, multidict): for k, l in multidict.lists(): for v in l: yield k, v def _convert_filter_splitdatetime(self, request, key, l, endswith, filters): key_new = key.replace(endswith, '') date = request.GET.get('%s_0' % key_new, '') hour = request.GET.get('%s_1' % key_new, '') if date and hour: value_new = '%s %s' %(date, hour) value_new = value_new.strip() return (key_new, [value_new]) return key, l def get_query_string(self, new_params=None, remove=None): if new_params is None: new_params = MultiValueDict() if remove is None: remove = [] p = self.params.copy() for r in remove: for k in p.keys(): if (k.startswith(r) and r.endswith('__')) or k==r: del p[k] if isinstance(new_params, MultiValueDict): new_params_items = new_params.lists() setter = p.setlist else: new_params_items = new_params.items() setter = p.__setitem__ for k, v in new_params_items: if k in p and v is None: del p[k] elif v is not None: setter(k, v) query_string_blocks = [] for k, l in p.lists(): query_string_blocks.append('&'.join([u'%s=%s' % (k, v) for v in l])) return mark_safe('?' + '&'.join(query_string_blocks).replace(' ', '%20')) def get_params(self): return self.params def get_params_items(self): return self._get_multidict_items(self.params) def get_search_fields(self): return self.search_fields def get_filters(self): filters = {} for key in self.filters.keys(): filters[key] = self._get_from_dict(self.filters, key) return self.sanitize_filters(filters) def get_excluders(self): excluders = {} for key in self.excluders.keys(): filter_key = key.replace('not_', '') excluders[filter_key] = self._get_from_dict(self.excluders, key) return self.sanitize_filters(excluders) def get_filters_items(self): return self._get_multidict_items(self.filters) def get_search_value(self, value): return self.search_fields.get(value, None) def get_page(self): return self.page def search_performed(self): return bool(self.filters) or bool(self.excluders) or bool(self.search_fields)
class QueryStringManager(object): """ QueryStringManager can be used to automatically set filters on listing. We take idea from django.contrib.admin.views.main.ChangeList class, but without all admin functionality (less coupled principle) However, it implements foofield__id__in filters, for example, equivalent to: FooModel.objects.filter(category__id__in=[8,9]) Example of use, with a request like http://foo.com?category__id__in=9&category__id__in=8: >>> qsm = QueryStringManager(request) >>> qsm.get_params() <MultiValueDict: {'category__id__in': [u'9', u'8']}> >>> qsm.get_query_string() u'?category__id__in=9&category__id__in=8' >>> qsm.get_filters() <MultiValueDict: {'category__id__in': [u'9', u'8']}> You can then use it in a view with: def foo_listing(request, ...): qsm = QueryStringManager(request) queryset = FooModel.objects.all() queryset = queryset.filter(qsm.get_filters()) category_choices = Category.objects.filter(parent__isnull=True) render_to_response('foo_listing.html', {'queryset': queryset, 'qsm': qsm, 'category_choices': category_choices} ) And last, in template you can use cmsutils admin filters with: {% load modelfilters %} {% filter_for_model 'fooapp' 'foomodel' 'publish_date' %} {% filter_for_model 'fooapp' 'foomodel' 'category' category_choices %} """ def __init__(self, request, search_fields=[], page_var=PAGE_VAR, ignore_params=[]): self.params = MultiValueDict() self.filters = MultiValueDict() self.excluders = MultiValueDict() self.search_fields = MultiValueDict() self.page = None if request is None: return raw_filters = {} for key, l in request.GET.lists(): if key == page_var: self.page = l elif key.startswith('__') or key in ignore_params: # private arg continue elif key.endswith('_0') or key.endswith('_1'): if key.endswith('_0'): key_new, l_new = self._convert_filter_splitdatetime( request, key, l, '_0', raw_filters) elif key.endswith('_1'): key_new, l_new = self._convert_filter_splitdatetime( request, key, l, '_1', raw_filters) raw_filters[key_new] = l_new else: raw_filters[key] = l for key, l in raw_filters.items(): try: key = str(key) except UnicodeEncodeError: key = 'key_%s' % len(l) self._set_into_dict(self.params, key, l) if key in search_fields: self._set_into_dict(self.search_fields, key, l) elif u'not_' in key: self._set_into_dict(self.excluders, key, l) else: self._set_into_dict(self.filters, key, l) def _get_from_dict(self, multidict, key): if key.endswith(IN_LOOKUP): return multidict.getlist(str(key)) else: return multidict.get(str(key)) def _set_into_dict(self, multidict, key, value): if key.endswith(IN_LOOKUP): multidict.setlist(str(key), value) else: multidict[str(key)] = value[0] def _get_multidict_items(self, multidict): for k, l in multidict.lists(): for v in l: yield k, v def _convert_filter_splitdatetime(self, request, key, l, endswith, filters): key_new = key.replace(endswith, '') date = request.GET.get('%s_0' % key_new, '') hour = request.GET.get('%s_1' % key_new, '') if date and hour: value_new = '%s %s' % (date, hour) value_new = value_new.strip() return (key_new, [value_new]) return key, l def get_query_string(self, new_params=None, remove=None): if new_params is None: new_params = MultiValueDict() if remove is None: remove = [] p = self.params.copy() for r in remove: for k in p.keys(): if (k.startswith(r) and r.endswith('__')) or k == r: del p[k] if isinstance(new_params, MultiValueDict): new_params_items = new_params.lists() setter = p.setlist else: new_params_items = new_params.items() setter = p.__setitem__ for k, v in new_params_items: if k in p and v is None: del p[k] elif v is not None: setter(k, v) query_string_blocks = [] for k, l in p.lists(): query_string_blocks.append('&'.join([u'%s=%s' % (k, v) for v in l])) return mark_safe('?' + '&'.join(query_string_blocks).replace(' ', '%20')) def get_params(self): return self.params def get_params_items(self): return self._get_multidict_items(self.params) def get_search_fields(self): return self.search_fields def get_filters(self): filters = {} for key in self.filters.keys(): filters[key] = self._get_from_dict(self.filters, key) return filters def get_excluders(self): excluders = {} for key in self.excluders.keys(): filter_key = key.replace('not_', '') excluders[filter_key] = self._get_from_dict(self.excluders, key) return excluders def get_filters_items(self): return self._get_multidict_items(self.filters) def get_search_value(self, value): return self.search_fields.get(value, None) def get_page(self): return self.page def search_performed(self): return bool(self.filters) or bool(self.excluders) or bool( self.search_fields)