views:

334

answers:

5

I may have a classic problem, but I didn't find any snippet allowing me to do it.

I want to sort this model by its fullname.

class ProductType(models.Model):
    parent   = models.ForeignKey('self', related_name='child_set')
    name     = models.CharField(max_length=128)

    def get_fullname(self):
        if self.parent is None:
            return self.name
        return u'%s - %s' % (unicode(self.parent), self.name)
    fullname = property(get_fullname)
  1. I tried sorting by "parent", got infinite loop error. "parent__id" did not sort well.

  2. I could not understand how to use annotate() for concatenating string fields.

  3. I added a custom manager with sorted(), but it returns a list object and prevents my forms.ModelChoiceField to work.

Here's the sort

def all(self):
    return sorted(super(ProductTypeManager, self), key=lambda o: o.fullname)

What else is there in the djangonic jungle ? Thanks for your help.

A: 

This might work:

ProductType.objects.alL().order_by('parent__name', 'name')
Daniel Roseman
It behaves strangely, like order_by('parent__id') did.
emel
What does "behaves strangely" mean, precisely? Could you update your question with the specific thing it does wrong?
S.Lott
I meant, it does not sort well : http://pastebin.com/m3af438acIt is known to be inconsistent : http://code.djangoproject.com/ticket/7101#comment:1
emel
+1  A: 

I would probably create a denomalised field and order on that. Depending on your preferences you might wnat to override .save(), or use a signal to poplate the denormalised field.

class ProductType(models.Model):
    parent   = models.ForeignKey('self', related_name='child_set')
    name     = models.CharField(max_length=128)
    full_name     = models.CharField(max_length=128*4)

    def save(self, *args, **kwargs):
        if not full_name:
            self.full_name = self.get_fullname()
        super(ProductType, self).save(*args, **kwargs)


    def get_fullname(self):
        if self.parent is None:
            return self.name
        return u'%s - %s' % (unicode(self.parent), self.name)

Then do a normal order by full_name

uswaretech
A: 

agreed :

ProductType.objects.alL().order_by('parent__name', 'name')

http://docs.djangoproject.com/en/dev/ref/models/querysets/#order-by-fields

phmr
What does "agreed" mean in this answer? Could you fix it so that it's clear what you're agreeing with?
S.Lott
S.Lott, "could" is past tense. Can you please fix your comment?
slypete
A: 

I would definitely explore the route you mentioned as 1) above:

ProductType.objects.order_by('parent__name', 'name')

Why is it erroring with an infinite loop? Is your example data referencing itself?

Emil Stenström
It is a Django exception : http://code.djangoproject.com/browser/django/trunk/django/db/models/sql/query.py?rev=11274#L1012It is quickly explained here:http://code.djangoproject.com/ticket/7101#comment:1
emel
+1  A: 

Or, if what you're trying to do is to generate a tree structure, have a look at django-mptt. It also allows for ordering on a manually set order.

Emil Stenström