Django QuerySet order_by оценка строки - PullRequest
1 голос
/ 30 апреля 2011

Я пытаюсь отсортировать свой QuerySet на основе того, как объекты в QuerySet оцениваются как строки.

Итак, моя модель выглядит примерно так:

class System(models.Model):
  operating_system = models.CharField(...)
  language = models.CharField(...)
  locale = models.CharField(...)

  def __unicode__(self):
    def __clean(orig, new):
      if orig is None or orig == "":
        if new is None or new == "":
          return ""
        else:
          return str(new)
      else:
        if new is None or new == "":
          return str(orig)
        else:
          return str(orig) + " " + str(new)
    name = None
    for attr in System._meta.fields:
      if attr.name != "id":
        name = __clean(name, getattr(self, attr.name))
    for m2mfield in System._meta.many_to_many:
      for object in getattr(self, m2mfield.name).all():
        name = __clean(name, object)  

    if name == "":
      return "Undefined"
    return name

И яЯ хотел бы иметь возможность сделать запрос что-то вроде:

System.objects.filter(...).order_by('__unicode__')

Мне интересно, есть ли способ сделать это без специального менеджера.

Спасибо!

1 Ответ

1 голос
/ 02 мая 2011

В __unicode__ вы в конечном итоге получите одну строку, которая представляет объект System.Вместо того, чтобы вычислять его каждый раз, когда вам это нужно, рассчитайте его один раз и сохраните в модели.

class System(models.Model):
    operating_system = models.CharField(...)
    language = models.CharField(...)
    locale= models.CharField(...)
    name = models.CharField(editable=False, ...)

    def save(self, *args, **kwargs):
        self.name = self._calculate_name()
        super(System, self).save(*args, **kwargs)

    def __unicode__(self):
        return self.name

    def _calculate_name(self):
        # all that string manipulation and relationship stuff

Теперь вы можете легко заказать по этому имени

System.objects.filter(...).order_by('name')

Есть несколько предостереженийк этому подходу, это действительно зависит от использования системы.Кроме того, НЕ беспокойтесь о месте, это мое мнение!


Расширение на предостережениях

Поскольку это поле «денормализовано», оно страдает от того жепроблемы других реляционных данных, которые не нормированы лицом. Денормализация может вводить аномалии обновления (поле или отношение, от которых зависит name, может измениться без изменения на name, если изменение происходит не по методу save() модели System, а по другому маршруту.Это также может замедлить запись (в этом случае, вероятно, на очень небольшое количество), это может увеличить требования к пространству (опять же, не проблема здесь, на мой взгляд), и целый ряд других вещей, о которых Google хотел бы рассказать вам об этом.Я уверен.

Я думаю, все, что вам нужно быть осторожным, это обновлять .name всякий раз, когда это необходимо, поэтому тщательно продумайте, при каких условиях ваш код «очистки» будет давать разные результаты. Если, например,у вас была таблица операционной системы, в которой вы можете изменить описание операционной системы, не касаясь системной таблицы, тогда вы должны понимать, что .name не будет обновляться при сохранении в ОС, для этого потребуется пересчет. Существуют механизмы, которые могут помочь сэто как сигналы и переопределение более save() методов. Вы также можете обновить их в пакетном режимепри необходимости.

Это действительно сильно зависит от вашего варианта использования, который здесь не полностью проиллюстрирован.В SO полно людей, которые могут помочь вам найти лучшее решение, если вы представите свой вариант использования более полно.

...