Django标签和翻译 - 模型设计

时间:2009-03-05 19:09:49

标签: python django django-models localization

假设我有以下Django模型:

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

每个标签都有一个ID号,标签文本和缩写。现在,我希望将这些标签翻译成其他语言。这样做的最佳方式是什么?

在我看来,我有几个选择:

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)

但问题是标签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 个答案:

答案 0 :(得分:3)

根据您的应用程序设计,您可能会考虑的另一个选择是利用Django的国际化功能。他们使用的方法与桌面软件中的方法相当普遍。

我看到编辑的问题是为了添加对Django国际化的引用,所以你知道它,但是Django中的intl特性不仅仅适用于Forms;它触动了很多,只需要对你的应用程序设计进行一些调整。

他们的文档在这里: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的解决方案的启发。

答案 1 :(得分:2)

我会尽可能地保持简单。查找会更快,代码更清晰,如下所示:

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')

答案 2 :(得分:1)

我更倾向于为每种语言添加一个字段而不是每种语言的新模型实例。当您添加新语言时,它确实需要更改架构,但这并不难,您希望多久添加一次语言?与此同时,它将为您提供更好的数据库性能(没有添加的连接或索引),您不必使用翻译内容来破坏查询逻辑;将它全部保存在它所属的模板中。

更好的是,使用可重复使用的应用,例如django-transmetadjango-modeltranslation,这使得这个愚蠢的简单且几乎完全透明。

答案 3 :(得分:0)

虽然我会选择Daniel's solution,但这是我从你的评论中理解的另一种选择:

您可以使用XMLField或JSONField来存储您的语言/翻译对。这将允许引用标签的对象对所有翻译使用单个id。然后,您可以使用自定义管理器方法来调用特定的翻译:

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

或者稍微更清晰且稍微复杂的解决方案与admin一起使用就是将XMLField非规范化为另一个与Label模型具有多对一关系的模型。相同的API,但不是解析XML,它可以查询相关的模型。

对于这两个建议,标签的用户都会指向一个对象。

我不会太担心查询,Django会缓存查询,而你的DBMS也可能会有更好的缓存。