我正在建立词汇表,并具有以下模型:
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
)?如何存储从一种语言到另一种语言的翻译(查询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')
但这不起作用:
Field 'to_word' does not generate an automatic reverse relation and therefore cannot be used for reverse querying. If it is a GenericForeignKey, consider adding a GenericRelation.
最佳答案
GenericForeignKey尝试为您提供ForeignKey
行为,但是却针对一种对象类型,而是针对一组对象类型执行此操作(这就是为什么要用2列定义它们的原因,其中1列保留primary_key
,另一列保留contenty_type
)。GenericRelation
是GenericForeignKey
的反向关系,因为Django不会自动为GenericForeignKeys
创建反向关系(与ForeignKeys
不同),您必须手动设置它们。
我对翻译/词汇人员的最佳做法不是很熟悉,但是如果您想使用GenericRelations
和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
,因此,如果单个word
具有3 word_nouns
(假设1 EnNoun
和2 FrNoun
)。然后,我们将其优化为3个查询-3个查询-1个
word_nouns
和2个每个noun
(word_nouns
和contenty_type
),而不是4个查询-EnNoun
1个,每个FrNoun
3个。for word_noun in word.nouns.all().prefetch_related('noun'):
print word_noun.noun #this will not make a query
区别在于查询的数量现在将取决于不同
ContentTypes
的数量,而不是相关的WordNoun
对象的数量。当您要预取的列表中的一个
Nouns
中有多个contenty_type
时,此缩放比例很好,但是如果您有1个Noun per
contenty_type`,则没有什么区别。我可以想到的另一种方法是使用以下模型结构:
class Word(Model):
name = CharField(max_length=75)
class WordNoun(Model):
LANG_CHOICES = (
('en', 'English'),
('fr', 'French'),
)
word = ForeignKey(Word)
lang = models.CharField(max_length=2, choices=LANG_CHOICES)
gender = CharField(max_length=2, blank=True, default='')
#Now accessing all word_nouns would as easy as:
word_nouns = word.wordnoun_set.all()