简短的问题: 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
问题在于这是一个区分大小写的比较,因此Foo
出现在bar
之前,这不是我想要的。为了避免这个问题,在另一个视图中 - 我列出了所有单词,我使用了一个自定义模型管理器,它添加了一个额外的字段,比如这个
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)'})
并在Word的定义中添加
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
事实上,Django不会基于field lookups接受extra fields。那么,我应该做什么(没有编写自定义SQL)?
奖金问题:我至少看到了我正在做的更多问题。首先,我不确定性能。我假设在定义previous_words
和next_words
时根本不会执行任何查询,并且当我定义previous
和next
时,数据库中的唯一查找将会发生,从而产生查询或多或少
SELECT Word.original, ..., lower(Word.original) AS lower
WHERE lower < `foo`
ORDER BY lower DESC
LIMIT 1
这是对的吗?或者我正在做一些会使数据库放慢太多的事情?我不太了解Django ORM的内部工作原理。
第二个问题是我实际上必须处理不同语言的单词。鉴于我知道每个单词的语言,即使它们具有非ASCII字符,也有一种方法可以按字母顺序排列它们。例如,我希望按此顺序拥有méchant
,moche
,但我得到moche
,méchant
。
答案 0 :(得分:1)
数据库应该能够为你做这样的排序,它应该能够在没有“低级”功能的情况下进行排序。
您需要修复的是数据库整理和编码。
例如,如果您使用的是mysql,则可以使用字符集utf8和collation utf8_general_ci
如果该排序规则对您不起作用,您可以根据自己的需要和数据库尝试其他排序规则。但是在查询中使用额外的字段和函数是一个丑陋的解决方法,会降低应用程序的速度。
mysql和postgresql中还有许多collations选项:
http://dev.mysql.com/doc/refman/5.5/en/charset-mysql.html http://stackoverflow.com/questions/1423378/postgresql-utf8-character-comparison
但这绝对是在数据库级别进行优化的好机会。