Джанго: сравнение на дополнительных полях - PullRequest
0 голосов
/ 22 апреля 2011

Короткий вопрос: Есть ли в Django способ найти следующую строку, основываясь на алфавитном порядке некоторого поля, без учета регистра?

Длинный вопрос: У меня есть несколько слов в базе данных и подробный вид для них. Я хотел бы иметь возможность просматривать слова в алфавитном порядке. Поэтому мне нужно узнать идентификатор предыдущего и следующего слова в алфавитном порядке. Сейчас я делаю следующее (оригинал - это поле, в котором хранится название слова):

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 не будет принимать полевых поисков на основе дополнительных полей . Итак, что я должен делать (если не писать собственный 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.

1 Ответ

1 голос
/ 22 апреля 2011

База данных должна быть в состоянии выполнить эту сортировку за вас, и она должна быть в состоянии сделать это без "нижней" функции.

Действительно, что вам нужно исправить, это сопоставление и кодирование базы данных.

Например, если вы используете mysql, вы можете использовать набор символов utf8 и параметры сортировки utf8_general_ci

Если это сравнение не работает для вас, вы можете попробовать другие параметры сортировки в зависимости от ваших потребностей и базы данных.,Но использование дополнительного поля и функции в запросе - уродливый обходной путь, который замедлит работу приложения.

В mysql и postgresql также доступно множество параметров сортировки:

http://dev.mysql.com/doc/refman/5.5/en/charset-mysql.html /1049290/sravnenie-simvolov-v-postgresql-utf8

Но это определенно хороший шанс для оптимизации на уровне БД.

...