【发布时间】:2011-04-22 13:56:04
【问题描述】:
小问题: 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)'})
我在词的定义中添加
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 不会接受基于extra fields 的field lookups。那么,我该怎么办(没有编写自定义 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。
【问题讨论】:
标签: python django django-orm