Вопрос

Допустим, у меня есть следующая модель Django:

class StandardLabel(models.Model):
    id = models.AutoField(primary_key=True)
    label = models.CharField(max_length=255)
    abbreviation = models.CharField(max_length=255)

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

На мой взгляд, у меня есть несколько вариантов:

1:Добавьте переводы в качестве полей в модели:

class StandardLabel(models.Model):
    id = models.AutoField(primary_key=True)
    label_english = models.CharField(max_length=255)
    abbreviation_english = models.CharField(max_length=255)
    label_spanish = models.CharField(max_length=255)
    abbreviation_spanish = models.CharField(max_length=255)

Очевидно, что это не идеально - для добавления языков требуется редактирование модели, правильное название поля зависит от языка.

2:Добавьте язык в качестве внешнего ключа:

class StandardLabel(models.Model):
    id = models.AutoField(primary_key=True)
    label = models.CharField(max_length=255)
    abbreviation = models.CharField(max_length=255)
    language = models.ForeignKey('languages.Language')

Это намного лучше, теперь я могу запросить все метки с определенным языком и поместить их в dict:

labels = StandardLabel.objects.filter(language=1)
labels = dict((x.pk, x) for x in labels)

Но проблема здесь в том, что labels dict должен быть таблицей подстановки, вот так:

x = OtherObjectWithAReferenceToTheseLabels.object.get(pk=3)
thelabel = labels[x.labelIdNumber].label

Который не работает, если для каждой метки есть строка, возможно, с несколькими языками для одной метки.Чтобы решить эту проблему, мне нужно другое поле:

class StandardLabel(models.Model):
    id = models.AutoField(primary_key=True)
    group_id = models.IntegerField(db_index=True)
    label = models.CharField(max_length=255)
    abbreviation = models.CharField(max_length=255)
    language = models.ForeignKey('languages.Language')
    class Meta:
        unique_together=(("group_id", "language"),)
#and I need to group them differently:
labels = StandardLabel.objects.filter(language=1)
labels = dict((x.group_id, x) for x in labels)

3:Перенесите текст метки в новую модель:

class StandardLabel(models.Model):
    id = models.AutoField(primary_key=True)
    text = models.ManyToManyField('LabelText')

class LabelText(models.Model):
    id = models.AutoField(primary_key=True)
    label = models.CharField(max_length=255)
    abbreviation = models.CharField(max_length=255)
    language = models.ForeignKey('languages.Language')

labels = StandardLabel.objects.filter(text__language=1)
labels = dict((x.pk, x) for x in labels)

Но тогда это не работает и вызывает попадание в базу данных каждый раз, когда я ссылаюсь на текст метки:

x = OtherObjectWithAReferenceToTheseLabels.object.get(pk=3)
thelabel = labels[x.labelIdNumber].text.get(language=1)

Я реализовал вариант 2, но я нахожу его очень уродливым - мне не нравится поле group_id, и я не могу придумать ничего лучшего для его названия.Кроме того, StandardLabel в том виде, в каком я его использую, является абстрактной моделью, которую я подклассирую, чтобы получить разные наборы меток для разных полей.

Я полагаю, что если бы вариант 3 / не попал / в базу данных, это то, что я бы выбрал.Я считаю, что настоящая проблема заключается в том, что фильтр text__language=1 не кэширует LabelText экземпляры, и поэтому база данных попадает, когда я text.get(language=1)

Что вы думаете по этому поводу?Кто-нибудь может порекомендовать более чистое решение?

Редактировать:Просто чтобы было понятно, это не метки форм, поэтому система интернационализации Django не помогает.

Это было полезно?

Решение

Я бы предпочел добавить поле для каждого языка, чем новый экземпляр модели для каждого языка. Это требует изменения схемы, когда вы добавляете новый язык, но это не сложно, и как часто вы ожидаете добавить языки? В то же время, это даст вам лучшую производительность базы данных (без добавления соединений или индексов), и вам не придется портить логику запросов с помощью перевода; держите все это в шаблонах, где оно принадлежит.

Еще лучше, используйте приложение многократного использования, например django-transmeta или django-modeltranslation , что делает эту глупость простой и почти полностью прозрачной.

Другие советы

Другой вариант, который вы могли бы рассмотреть, в зависимости от дизайна вашего приложения, конечно, заключается в использовании функций интернационализации Django.Подход, который они используют, довольно схож с подходом, используемым в настольном программном обеспечении.

Я вижу, что вопрос был отредактирован, чтобы добавить ссылку на интернационализацию Django, так что вы знаете об этом, но функции intl в Django применимы не только к формам;это затрагивает довольно много вопросов и требует лишь нескольких доработок в дизайне вашего приложения.

Их документы здесь: http://docs.djangoproject.com/en/dev/topics/i18n/#topics-i18n

Идея заключается в том, что вы определяете свою модель так, как если бы существовал только один язык.Другими словами, вообще не делайте ссылок на язык и используйте в модели только, скажем, английский.

Итак:

class StandardLabel(models.Model):
    abbreviation = models.CharField(max_length=255)
    label = models.CharField(max_length=255)

Я знаю, это выглядит так, будто вы полностью отказались от языковой проблемы, но на самом деле вы только что перенесли ее.Вместо того чтобы использовать язык в вашей модели данных, вы перенесли его в представление.

Функции интернационализации django позволяют создавать файлы перевода текста и предоставляют ряд функций для извлечения текста из системы в файлы.На самом деле это весьма полезно, потому что позволяет вам отправлять простые файлы вашему переводчику, что облегчает его работу.Добавить новый язык так же просто, как перевести файл на новый язык.

Файлы перевода определяют метку из базы данных и перевод для этого языка.Существуют функции для динамической обработки языкового перевода во время выполнения для моделей, представлений администратора, javascript и шаблонов.

Например, в шаблоне вы могли бы сделать что-то вроде:

<b>Hello {% trans "Here's the string in english" %}</b>

Или в коде просмотра вы могли бы сделать:

# See docs on setting language, or getting Django to auto-set language
s = StandardLabel.objects.get(id=1)
lang_specific_label = ugettext(s.label)

Конечно, если ваше приложение предназначено исключительно для ввода новых языков on the fly, тогда этот подход может не сработать для вас.Тем не менее, взгляните на проект интернационализации, поскольку вы можете либо использовать его "как есть", либо вдохновиться подходящим для django решением, которое работает для вашего домена.

Я хотел бы сделать вещи максимально простыми. Поиск будет быстрее и очиститель кода с чем-то вроде этого:

class StandardLabel(models.Model):
    abbreviation = models.CharField(max_length=255)
    label = models.CharField(max_length=255)
    language = models.CharField(max_length=2)
    # or, alternately, specify language as a foreign key:
    #language = models.ForeignKey(Language)

    class Meta:
        unique_together = ('language', 'abbreviation')

Затем запрос на основе аббревиатуры и языка:

l = StandardLabel.objects.get(language='en', abbreviation='suite')

Хотя я хотел бы использовать решение Дэниела , здесь это альтернатива из того, что я понял из ваших комментариев:

Вы можете использовать XMLField или JSONField для сохранить ваш язык / перевод пары. Это позволит вашим объектам, ссылающимся на ваши метки, использовать один id для всех переводов. И тогда у вас может быть собственный метод менеджера для вызова определенного перевода:

Label.objects.get_by_language('ru', **kwargs)

Или более чистое и немного более сложное решение, которое хорошо работает с admin , заключается в денормализации XMLField в другую модель, имеющую отношение многие-к-одному с Label модель. Тот же API, но вместо анализа XML он может запрашивать связанные модели.

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

Я бы не стал слишком беспокоиться о запросах, Django кэширует запросы, и ваша СУБД, вероятно, также будет иметь там лучшее кэширование.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top