2011-05-19 53 views
2

這看起來像Django使事情變得簡單,想知道是否有人有任何經驗。在Django中排序:在排序時可能忽略「前綴」?

我有一張樂隊表,其中一些人被稱爲'The Geeks'(例如)。我希望它們在'G'下按字母順序顯示。

我知道我可以做一些花哨的SQL來重寫它們,並且按照這種方式排序,但是Django提供了什麼內置的功能,所以我可以保留我的漂亮的Band.objects.all()語法,並且仍然對自定義排序進行篩選?

我知道我可以更改我的數據以包含has_prefix字段或其他內容,並將該名稱存儲爲「Geeks,The」或其他內容,但如果可能,我寧願不要觸摸數據本身。

任何提示?

回答

2

你不能order_by()

您可以

  1. Do some fancy SQL做到這一點。如果你想保持它的好和短,你應該寫一個自定義模型管理器。
  2. 在Python級別而不是SQL級別排序
  3. 分別存儲「排序標題」和「顯示標題」。
+0

我剛剛發生的一件事 - 我可以在模型對象上放置一個函數,它返回'Band','樣式名稱,並對其進行排序? – 2011-05-19 11:58:22

+1

'order_by'在數據庫級別執行,您的數據庫對python函數一無所知。但是,當然,你可以在python級別對列表進行排序(我的答案爲#2)。 – DrTyrsa 2011-05-19 12:01:34

+0

對於上面的選項3,最好將正確排序的序列號存儲在「排序標題」字段中,而不是用字順序的變化再次重複整個標題。很少使用空間。 – Ubuntourist 2012-09-06 21:22:17

3

以下是我做這件事是最近的Django項目:

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 

由於這是一個屬性,而不是在數據庫中實際的專欄中,我需要先檢索查詢集,然後之後對其進行排序在一個視圖中的事實。這是我怎麼做的:

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) 

我敢肯定,你早就找到了一個解決方案,但我想它可能有助於它張貼反正有人在未來其他可能會遇到同樣的問題。

1

利用該模型,並從上面的一對夫婦的提示(由respondcreate),以及this answer適應,我想出了下面一行的做法:

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

這會產生從查詢集和列表根據lambda函數對它進行排序,該lambda函數替換標題小寫版本的開頭的a和a。