короче хотелось какой-то такой интерфейс чтоб не размазывать код по вс

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
#короче хотелось какой-то такой интерфейс чтоб не размазывать код по всему проекту
class TechnicOrderSet(OrderSet):
order_fields = {
'views': OrderByField('views'),
'name': OrderByField('name'),
}
default_ordering = ('name', 'desc')
class OrderSet(object):
order_fields = {}
default_ordering = ()
def __init__(self, request, queryset):
self.request, self.queryset = request, queryset
self.order_key, self.order_type = self.get_current_ordering()
#здесь генерятся данные для шаблонов
def __iter__(self):
for key, field in self.order_fields.items():
classes = []
new_order_type = 'asc'
if self.order_key == key:
classes.append('sorted %sending' % self.order_type)
new_order_type = {'asc': 'desc', 'desc': 'asc'}[self.order_type]
yield {
"text": _('by %s') % field.verbose_name,
"url": self.get_query_string(key, new_order_type),
"classes": ' '.join(classes),
}
# из запроса вынимается текущая сортировка
def get_current_ordering(self):
ordering = self.request.GET.get('ordering')
if ordering:
order_type = ('asc', 'desc')[ordering.startswith('-')]
order_key = ordering.lstrip('-')
if order_key in self.order_fields:
return order_key, order_type
return self.default_ordering or (None, None)
# ну это понятно
@property
def ordered_queryset(self):
if not getattr(self, '_qs', None):
if self.order_key:
self._qs = self.order_fields[self.order_key].order(
self.queryset, self.order_type)
else:
self._qs = self.queryset.all()
return self._qs
#составляется адрес для конкретной ссылки сортировки
def get_query_string(self, key, order_type):
query_dict = self.request.GET.copy()
if 'ordering' in query_dict:
del query_dict['ordering']
if 'page' in query_dict:
del query_dict['page']
if not (key, order_type) == self.default_ordering:
query_dict['ordering'] = encode_ordering(key, order_type)
if len(query_dict.keys()):
query_string = '?%s' % query_dict.urlencode()
else:
query_string = ''
return '%s%s' % (self.request.path, query_string)
#класс для сортировки по среднему значению поля
class AvgOrderField(object):
def __init__(self, field, annotate_name=None, verbose_name=None):
self.field = field
if annotate_name:
self.annotate_name = annotate_name
else:
self.annotate_name = 'avg_%s' % field.split('__')[-1]
self.verbose_name = verbose_name
if not verbose_name:
self.verbose_name = self.annotate_name.replace('_', ' ')
def order(self, queryset, order_type):
return queryset.annotate(**{self.annotate_name: Avg(self.field)}).order_by(
encode_ordering(self.annotate_name, order_type)
)
class OrderByField(object):
def __init__(self, field, verbose_name=None):
self.field = field
self.verbose_name = verbose_name
if not verbose_name:
self.verbose_name = field
def order(self, queryset, order_type):
return queryset.order_by(encode_ordering(self.field, order_type))
def encode_ordering(order_field, order_type):
return '%s%s' % ('-' if order_type == 'desc' else '', order_field)