开发者

Sort ordering in Django: possible to ignore "The" prefix when sorting?

This seems like the kind of thing Django makes simple, wondering if anyone has any experience with it.

I have a table of bands, some of whom are called 'The Geeks' (for example). I want them to appear alphabe开发者_如何学编程tically under 'G'.

I know I can do some fancy SQL to rewrite them on the fly and sort that way, but does Django offer anything built-in so I can keep my nice Band.objects.all() syntax and still filter on a custom sort?

I know I could change my data to include a has_prefix field or something and store the bandname as 'Geeks, The' or whatever, but I'd rather not touch the data itself if possible.

Any tips?


Here's how I did it on a recent Django project:

from django.db import models

SomeClass(models.Model):
    title = models.CharField()

    @property
    def alphabetical_title(self):
        """
        Returns an alphabetical-friendly string of a title attribute.
        """
        title = self.title

        # A list of flags to check each `title` against.
        starts_with_flags = [
            'the ',
            'an ',
            'a '
        ]

        # Check each flag to see if the title starts with one of it's contents.
        for flag in starts_with_flags:
            if title.lower().startswith(flag):
                # If the title does indeed start with a flag, return the title with
                # the flag appended to the end preceded by a comma.
                return "%s, %s" % (title[len(flag):], title[:len(flag)-1])
            else:
                pass
        # If the property did not return as a result of the previous for loop then just
        # return the title.
        return self.title

Since this is a property and not an actual column in the database I need to retrieve a QuerySet first and then sort it after the fact in a view. Here's how I did that:

from operator import attrgetter
from someapp.models import SomeClass

some_objects = SomeClass.objects.all()
sorted_objects = sorted(some_objects, key=attrgetter('alphabetical_title'), reverse=False)

I'm sure you've long since found a solution but I figured it might help to post it anyways as someone else in the future might run into this same problem.


You can't do it with order_by()

You can

  1. Do some fancy SQL. If you want to keep it nice and short, you should write a custom model manager.
  2. Do sorting at Python-level, not SQL-level
  3. Store "sort title" and "display title" separately.


Using the model and a couple hints from the above (by respondcreate), and an adaptation of this answer, I came up with the following one line approach:

mysortedlist = sorted([x for x in SomeClass.all()],
               key=lambda y: re.sub("^(the|a|an) ","",y.title.lower()) )

This generates a list from the QuerySet and sorts it according to a lambda function that replaces the, a, and an at the beginning of a lowercased version of the title.

0

上一篇:

下一篇:

精彩评论

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

最新问答

问答排行榜