了解Django GenericForeignKey和GenericRelation [英] Understanding Django GenericForeignKey and GenericRelation
问题描述
我正在建立词汇量,并且具有以下模型:
I'm building vocabulary and have following models:
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
的给定单词的结果(
Same word can be in both EnNoun
and FrNoun
. Is it possible to fetch result for given word for both EnNoun
and FrNoun
, using the least number of queries (there will be more similar classes for language and part of speech, like ItAdverb
)?
如何存储一种语言的翻译,是不是语言和词类更相似的类,例如 ItAdverb
)?到另一个表(不查询20个以上的表)。
How to store translation from one lang to another (querying 20+ tables is not an option).
GenericForeign
键有什么用吗?我一般如何使用它们?
Are GenericForeign
keys of any use? How can I use them in general?
我有以下翻译课程:
@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
)。
GenericForeignKey try to give you a ForeignKey
behavior but instead to be against one type of object, they do it for a set of object types (thats why they are defined with 2 columns, 1 to keep the primary_key
and another to keep the contenty_type
).
GenericRelation
是 GenericForeignKey
的反向关系,因为Django不会自动为 GenericForeignKeys
(与 ForeignKeys
不同),您必须手动设置它们。
GenericRelation
is the reverse relation of a GenericForeignKey
, because Django do not automatically create reverse relations for GenericForeignKeys
(unlike ForeignKeys
) you have to setup them manually.
我对最佳工具不是很熟悉-翻译/词汇人员的做法,但是如果您想使用 GenericRelations
和 GenericForeignKeys
解决问题,一种方法可能是:
I'm not very familiar with the best-practices in translations/vocabulary staffs, but if you want to approach the problem with GenericRelations
and GenericForeignKeys
, one way to do it would be:
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()
我们基本上是在建立一个保持单词-名词关系的模型,以下给出的
We are basically creating a model keeping word-noun relations, this give is the following
# 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
列表,
访问单个名词
实例将进行新查询。
The problem with this approach is that after you get the word_nouns
list,
accessing a single noun
instance will make a new query.
for word_noun in word.nouns.all():
print word_noun.noun #this will make a query
一种略微优化此方法的方法是使用 prefetch_related
,因此如果单个单词
具有3个 word_名词
(假设1个 EnNoun
和2个 FrNoun
)。
One way to slightly optimize this is to use prefetch_related
, so if a single word
has 3 word_nouns
(lets say 1 EnNoun
and 2 FrNoun
).
然后,而不是4个查询-1个用于 word_nouns
,每个名词
3个,我们将其优化为3个查询-1个 word_nouns
和每个 contenty_type
( EnNoun
和 FrNoun
)2 / p>
Then instead of 4 queries - 1 for the word_nouns
and 3 for each noun
, we optimize it to 3 queries - 1 for the word_nouns
and 2 for each contenty_type
(EnNoun
and FrNoun
)
for word_noun in word.nouns.all().prefetch_related('noun'):
print word_noun.noun #this will not make a query
区别在于查询的数量现在取决于不同的 ContentTypes
的数量,而不是相关的 WordNoun
对象的数量。
The difference is that the number of queries will now depends on the number of different ContentTypes
, rather than the number of related WordNoun
objects.
当您有多个时,此缩放比例很好您正在预取的列表中的一个
,但如果每个名词中有1个 contenty_type
中的名词名词,则不会有什么区别 contenty_type`。
This scales nice when you have several Nouns
from one contenty_type
in the list you are prefetching, but will make no difference if you have 1 Noun per
contenty_type`.
我可以想到的另一种方法是使用以下模型结构:
Another approach which I can think of is to use the following model structure:
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()
这篇关于了解Django GenericForeignKey和GenericRelation的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!