-
Всем привет!
есть модель и надо отсортировать результат запроса к ней ее не по значению поля, а по некоторому действию с этим полем (а точне с несколькими полями)
пример:
и код который не работает:class BMM(models.Model):
active = models.BooleanField(default=True)
Name = models.CharField(max_length=32, unique=True)
B = models.ManyToManyField(BBB, through='AAA')
def igr(self):
i = 0
try:
i = int(self.Name)
except:
pass
return i
igr.allow_tags = True
def __unicode__(self):
return (self.Name)
Exception Type: FieldErrorBB = BN.objects.get(active=True,id=bid)
for a in BB.bmm_set.filter(active=True).distinct().order_by('igr'):
BV += ((a,a),
Exception Value: Cannot resolve keyword 'igr' into field. Choices are: B, Name, active, bum, id
как мне правильно написать чтобы сортировка шла по результату igr?
Django 1.0 -
по igr сортировка не будет идти, поскольку это не поле, о чем вам и говорит джанга в описании ошибки. Сделайте order_by('Name')
-
Если эта выборка дальше рендерится, то я в таких случаях пользуюсь dictsort
http://www.djangoproject.com/documentation/templates/#dictsort -
так в том-то и дело что мне нужна сортировка по результату обработки нескольких полей. Name тут в качестве простейшего примера.
нет, не рендерится далее.
хотя если админке будет показываться в отсортированом по этому полю порядке — будет вообще замечательно! -
Сортировка по полю принципиально отличается от сортировки не по полю тем, что первая может происходить внутри базы данных, а вторая, очевидно, нет. Джанговский order_by() — это сортировка именно в базе данных с помощью SQLного оператора "ORDER BY". Поэтому чтобы отсортировать список объектов по чему-то другому, нужно искать другие способы.
Первый — загрузить объекты из базы в программу и отсортировать стандартными питоновскими средствами:
bbm_list = list(BBM.objects.all()) bbm_list.sort(key=lambda o: o.igr)Недостаток этого способа в том, что для получения правильной сортировки надо загружать из базы все объекты, а это часто дорого. Но в простых случаях — хороший способ.
Другой способ — создать в модели полноценное физическое поле, которое будет хранить в себе то, по чему сортировать:
class BMM(models.Model): Name = models.CharField(max_length=32, unique=True) igr = models.IntegerField(db_index=True, editable=False) def save(self, **kwargs): # рассчитываем igr на каждом сохранении try: self.igr = int(self.Name) except ValueError: self.igr = 0 # для сохранения вызываем унаследованный метод super(BBM, self).save(**kwargs)После этого можно будет делать
order_by('igr').Достоинство второго способа в том, что будет работать частичная (постраничная то есть) выборка, потому что база теперь может отсортировать все через свой собственный order by, и выдать наружу уже только нужную часть, а не весь список:
BBM.objects.order_by('igr')[20:40]К слову, именно это и нужно, для того, чтобы работала сортировка в админке.
-
День добрый.
А чем плохо плохо сделать не физическое поле,
а поле в select, по которому потом сортировать в order, типа
its = items.objects.extra( select = { '_opn': "(opday IS NULL)" }, order_by=['_opn'] )
Это видимо лучше чем загружать объекты в память — и постраничная выборка и
выборка связанных объектов останется? -
Можно и так, действительно. Просто не всегда условие такое простое (is null). Бывает, что надо сортировать по какому-нибудь очень переработанному значению, и обработку эту никаким SQL'ом не выразишь: например — выкинуть слово "the" со стоящими рядом знаками препинания. Тогда стоит делать хранимое пересчитываемое поле.



