1. zzz0329@ya.ru

    07.09.2008 14:31

    Всем привет!
    есть модель и надо отсортировать результат запроса к ней ее не по значению поля, а по некоторому действию с этим полем (а точне с несколькими полями)

    пример:
    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)
    и код который не работает:
        BB = BN.objects.get(active=True,id=bid)
    for a in BB.bmm_set.filter(active=True).distinct().order_by('igr'):
    BV += ((a,a),
    Exception Type: FieldError
    Exception Value: Cannot resolve keyword 'igr' into field. Choices are: B, Name, active, bum, id

    как мне правильно написать чтобы сортировка шла по результату igr?

    Django 1.0
  2. Dyadya Zed

    07.09.2008 15:04

    по igr сортировка не будет идти, поскольку это не поле, о чем вам и говорит джанга в описании ошибки. Сделайте order_by('Name')
  3. Если эта выборка дальше рендерится, то я в таких случаях пользуюсь dictsort
    http://www.djangoproject.com/documentation/templates/#dictsort
  4. zzz0329

    08.09.2008 01:52

    так в том-то и дело что мне нужна сортировка по результату обработки нескольких полей. Name тут в качестве простейшего примера.

    нет, не рендерится далее.
    хотя если админке будет показываться в отсортированом по этому полю порядке — будет вообще замечательно!
  5. Иван Сагалаев

    08.09.2008 11:34

    Сортировка по полю принципиально отличается от сортировки не по полю тем, что первая может происходить внутри базы данных, а вторая, очевидно, нет. Джанговский 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]
    

    К слову, именно это и нужно, для того, чтобы работала сортировка в админке.

  6. d!mkazavr

    28.09.2008 13:08

    День добрый.

    А чем плохо плохо сделать не физическое поле,
    а поле в select, по которому потом сортировать в order, типа

    its = items.objects.extra( select = { '_opn': "(opday IS NULL)" }, order_by=['_opn'] )

    Это видимо лучше чем загружать объекты в память — и постраничная выборка и
    выборка связанных объектов останется?
  7. Иван Сагалаев

    28.09.2008 14:01

    Можно и так, действительно. Просто не всегда условие такое простое (is null). Бывает, что надо сортировать по какому-нибудь очень переработанному значению, и обработку эту никаким SQL'ом не выразишь: например — выкинуть слово "the" со стоящими рядом знаками препинания. Тогда стоит делать хранимое пересчитываемое поле.

bbcode