Django этикетки и переводы - дизайн модели - PullRequest
2 голосов
/ 05 марта 2009

Допустим, у меня есть следующая модель 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')

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

labels = StandardLabel.objects.filter(language=1)
labels = dict((x.pk, x) for x in 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 не помогает.

Ответы [ 4 ]

3 голосов
/ 05 марта 2009

Другой вариант, который вы можете рассмотреть, в зависимости от дизайна вашего приложения, конечно, это использовать возможности интернационализации 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-подходящим решением, которое работает для вашего домена.

2 голосов
/ 05 марта 2009

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

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')
1 голос
/ 06 марта 2009

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

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

0 голосов
/ 06 марта 2009

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

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

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

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

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

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

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