我建立词汇并拥有以下模型:
class Word(Model):
name = CharField(max_length=75)
class EnNoun(Model):
word = OneToOneField(Word)
class FrNoun(Model):
word = ForeignKey(Word)
gender = CharField()
同一个字可以同时包含EnNoun
和FrNoun
。
是否可以使用最少数量的查询来获取EnNoun
和FrNoun
的给定单词的结果(对于语言和词性,将会有更多类似的类,如ItAdverb
) ?
如何将翻译从一个lang存储到另一个lang(查询20多个表不是一个选项)。
GenericForeign
键是否有用?
我一般如何使用它们?
谢谢。
更新:
有以下翻译课程:
@python_2_unicode_compatible
class Translation(Model):
from_content_type = ForeignKey(ContentType, related_name='from_word_content_type')
from_object_id = UUIDField(default=uuid.uuid4)
from_word = GenericForeignKey('from_content_type', 'from_object_id')
to_content_type = ForeignKey(ContentType, related_name='to_word_content_type')
to_object_id = UUIDField(default=uuid.uuid4)
to_word = GenericForeignKey('to_content_type', 'to_object_id')
但它不起作用: 字段' to_word'不生成自动反向关系,因此不能用于反向查询。如果是GenericForeignKey,请考虑添加GenericRelation。
答案 0 :(得分:2)
GenericForeignKey试图给你一个ForeignKey
行为,但是它反对一种类型的对象,它们是为一组对象类型做的(这就是为什么它们用2列定义,1为了保持{{} 1}}和另一个保留primery_key
)。
contenty_type
是GenericRelation
的反向关系,因为Django不会自动为GenericForeignKey
创建反向关系(与GenericForeignKeys
不同),您必须手动设置它们。< / p>
我对翻译/词汇工作人员的最佳实践不是很熟悉,但如果你想用ForeignKeys
和GenericRelations
解决问题,一种方法是:< / p>
GenericForeignKeys
我们基本上创建了一个保持单词 - 名词关系的模型, 这个是以下
class Word(Model):
name = CharField(max_length=75)
nouns = GenericRelation('WordNoun', content_type_field='noun_ct', object_id_field='noun_id')
class WordNoun(Model):
word = ForeignKey(Word)
noun_ct = ForeignKey(ContentType,
on_delete=models.CASCADE,
#this is optional
limit_choices_to = {"model__in": ('EnNoun', 'FrNoun')}
)
noun_id = PositiveIntegerField()
noun = GenericForeignKey('noun_ct', 'noun_id')
class EnNoun(Model):
word = OneToOneField(Word)
class FrNoun(Model):
word = ForeignKey(Word)
gender = CharField()
这种方法的问题在于,在获得# Having some word
word = Word.objects.get(pk=1)
# With 1 query you can get a list with
# all WordNoun objects for this word.
word_nouns = word.nouns.all()
列表后,
访问单个word_nouns
实例将进行新查询。
noun
稍微优化一下的一种方法是使用for word_noun in word.nouns.all():
print word_noun.noun #this will make a query
,因此如果一个prefetch_related
有3 word
(假设1 word_nouns
和2 EnNoun
)。
然后,而不是4个查询 - FrNoun
为1,每个word_nouns
为3,我们将其优化为3个查询 - noun
为1,每个{{1}为2个}(word_nouns
和contenty_type
)
EnNoun
不同之处在于查询数量现在取决于不同FrNoun
的数量,而不是相关for word_noun in word.nouns.all().prefetch_related('noun'):
print word_noun.noun #this will not make a query
个对象的数量。
如果您预取的列表中有一个ContentTypes
有多个WordNoun
,那么这会很好,但如果您有1个Nouns
contenty_type`则没有任何区别。
我能想到的另一种方法是使用以下模型结构:
contenty_type
答案 1 :(得分:0)
可以向同一模型添加多个GenericForeignKey
。这将允许您在具有通用类型的对象之间创建“链接”。后面我举一个例子。我修改了您的示例,以创建我认为更有用的东西。表Translation
在法语和英语单词之间创建链接。单词存储在类EnVerb
,FrVerb
,EnNoun
和FrNoun
中。如果没有GenericForeignKey
,则必须创建两个转换模型:TranslationVerb
和TranslationNoun
。但是在下面的代码中,我展示了适用于动词和名词的通用翻译模型。我希望这是有道理的!
从技术上讲,您忘记添加GenericRelation
字段。另外,他们必须在相关对象的content_type
字段中指定字段object_id
和GenericRelation
的新名称。
from django.db import models
from django.contrib.contenttypes.fields import GenericRelation
from django.contrib.contenttypes.fields import GenericForeignKey
from django.contrib.contenttypes.models import ContentType
Translation(models.Model):
fr_content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE, related_name="fr_content_type")
fr_object_id = models.PositiveIntegerField()
fr_word = GenericForeignKey('fr_content_type', 'fr_object_id')
en_content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE, related_name="en_content_type")
en_object_id = models.PositiveIntegerField()
en_word = GenericForeignKey('en_content_type', 'en_object_id')
class FrVerb(models.Model):
name = models.CharField(max_length=75)
translation = GenericRelation(Translation, content_type_field='fr_content_type', object_id_field='fr_object_id')
class FrNoun(models.Model):
name = models.CharField(max_length=75)
gender = models.CharField(max_length=75)
translation = GenericRelation(Translation, content_type_field='fr_content_type', object_id_field='fr_object_id')
class EnVerb(models.Model):
name = models.CharField(max_length=75)
translation = GenericRelation(Translation, content_type_field='en_content_type', object_id_field='en_object_id')
class EnNoun(models.Model):
name = models.CharField(max_length=75)
translation = GenericRelation(Translation, content_type_field='en_content_type', object_id_field='en_object_id')
您可以使用它在模型之间创建通用翻译:
from polls.models import *
EnNoun(name='tree').save()
FrNoun(name='arbre').save()
EnVerb(name='be').save()
FrVerb(name='etre').save()
trans1 = Translation(fr_word=FrNoun.objects.first(), en_word=EnNoun.objects.first())
trans2 = Translation(fr_word=FrVerb.objects.first(), en_word=EnVerb.objects.first())
现在trans1
用于链接“树”和“ arbre”,trans2
用于链接“ be”和“être”,而这些对象属于不同的模型!