开发者

Django QuerySet order_by string evaluation

I'm trying to sort my QuerySet based on how the objects in the QuerySet are evaluated as Strings.

So my model looks something like this:

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

And, I'd like to be able to make a query something like:

System.objects.filter(...)开发者_开发知识库.order_by('__unicode__')

I'm wondering if there's a way to do this without a custom manager.

Thanks!


In __unicode__ you eventually end up with a single string that represents a System object. Instead of calculating it every time you need it, calculate it once and save it onto the model.

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

Now you can order by this name easily

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

There are some caveats to this approach, it really depends on the usage of System. Also, do NOT worry about the space, that's my opinion!


Expanding on caveats

Since this field is 'denormalized', it suffers from the same problems other relational data that isn't normalized face. Denormalization can introduce update anomalies (a field or relation that name depends on can change without a change to name if the change happens through some other route than the System model's save() method. It can also slow down writes (in this case probably by a very small amount), it can increase space requirements (again not a problem here in my opinion), and a whole wack of other stuff that Google would love to tell you about I'm sure.

I think all you have to be careful about is updating .name whenever it should be, so consider carefully under what conditions your 'cleaning' code will produce different results. If, for example, you had an OS table where you can change the description of an OS without touching the System table, then you have to realize your .name will not be updated by a save to OS, it will require recalculation. There are mechanisms to help with this like signals and overriding more save() methods. You could also batch update them as necessary.

It really depends heavily on your use case, which is not fully illustrated here. SO is full of people that could help you narrow down the best solution if you present your use case more completely.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜