2011-04-22 152 views
0

简短问题:在Django中,是否有一种方法可以基于字段的字母顺序来查找下一行,并且不区分大小写?Django:额外领域的比较

长问题:我在数据库中有一些单词,以及它们的详细视图。我希望能够按字母顺序浏览单词。所以我需要按字母顺序找出上一个和下一个单词的ID。现在我要做的就是以下(原是存储字的名称的字段):

class Word(models.Model): 
    original = models.CharField(max_length=50) 
    ... 

    def neighbours(self): 
     """ 
     Returns the words adjacent to a given word, in alphabetical order 
     """ 
     previous_words = Word.objects.filter(
      original__lt=self.original).order_by('-original') 
     next_words = Word.objects.filter(
      original__gt=self.original).order_by('original') 
     previous = previous_words[0] if len(previous_words) else None 
     next = next_words[0] if len(next_words) else None 
     return previous, next 

的问题是,这样做一个区分大小写的比较,所以Foobar前出现,这是不我想要的是。为了避免这个问题,在另一种观点 - 在这里我列出所有的话,我都利用它增加了一个额外的字段的自定义模型管理器中,这样

class CaseInsensitiveManager(models.Manager): 

    def get_query_set(self): 
     """ 
     Also adds an extra 'lower' field which is useful for ordering 
     """ 
     return super(CaseInsensitiveManager, self).get_query_set().extra(
      select={'lower': 'lower(original)'}) 

,并在词的定义我添加

objects = models.Manager() 
alpha = CaseInsensitiveManager() 

这样,我可以做的查询,如

Word.alpha.all().order_by('lower') 

,并得到所有单词按字母顺序不分的情况。但我不能

class Word(models.Model): 
    original = models.CharField(max_length=50) 
    ... 

    objects = models.Manager() 
    alpha = CaseInsensitiveManager() 

    def neighbours(self): 
     previous_words = Word.objects.filter(
      lower__lt=self.lower()).order_by('-lower') 
     next_words = Word.objects.filter(
      lower__gt=self.lower()).order_by('lower') 
     previous = previous_words[0] if len(previous_words) else None 
     next = next_words[0] if len(next_words) else None 
     return previous, next 

事实上基于extra fields Django将不会接受field lookups。那么,我应该做什么(缺少编写自定义SQL)呢?

奖金问题:我看到至少在我正在做的更多的问题。首先,我不确定表现。我认为根本没有查询时,我定义previous_wordsnext_words,当我定义previousnext在数据库中的唯一查找会发生被执行,产生查询这或多或少

SELECT Word.original, ..., lower(Word.original) AS lower 
WHERE lower < `foo` 
ORDER BY lower DESC 
LIMIT 1 

这是正确的?或者我正在做的事情会减慢数据库太多?我对Django ORM的内部工作知之甚少。

第二个问题是我实际上必须应付不同语言的文字。鉴于我知道每个单词的语言,是否有办法让它们按字母顺序排列,即使它们具有非ASCII字符。例如,我希望按此顺序有méchantmoche,但我得到moche,méchant

回答

1

数据库应该能够为您做这种排序,并且它应该能够在没有“低级”功能的情况下进行排序。

真正需要解决的是数据库整理和编码。

例如,如果你正在使用MySQL,你可以使用的字符集UTF8和整理utf8_general_ci

如果排序规则不会为你工作,你可以尝试其它归类根据您的需求和数据库。但是在查询中使用额外的字段和函数是一个丑陋的解决方法,它会降低应用程序的速度。

有在MySQL和PostgreSQL提供过许多归类选择:

http://dev.mysql.com/doc/refman/5.5/en/charset-mysql.html http://stackoverflow.com/questions/1423378/postgresql-utf8-character-comparison

但是这绝对是一个很好的机会在db级别进行优化。

+0

谢谢!我在原型阶段使用SQLite,但我想我将不得不立即选择MySQL。 – Andrea 2011-04-22 17:04:35

+0

当然(当然,sql lite也有一些整理选项:http://stackoverflow.com/questions/1188749/how-to-change-the-collat​​ion-of-sqlite3-database-to-sort-case -insensitively – 2011-04-22 17:09:15