了解Django GenericForeignKey和GenericRelation [英] Understanding Django GenericForeignKey and GenericRelation

查看:219
本文介绍了了解Django GenericForeignKey和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.

当您有多个时,此缩放比例很好您正在预取的列表中的一个 contenty_type 中的名词,但如果每个名词中有1个名词,则不会有什么区别 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 percontenty_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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆