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

查看:30
本文介绍了理解 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()

EnNounFrNoun 中可以出现同一个词.是否可以使用最少的查询次数为 EnNounFrNoun 获取给定单词的结果(语言和词性会有更多类似的类,例如ItAdverb)?

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

如何存储从一种语言到另一种语言的翻译(查询 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).

GenericRelationGenericForeignKey 的反向关系,因为 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.

我不太熟悉翻译/词汇工作人员的最佳实践,但是如果您想使用 GenericRelationsGenericForeignKeys 来解决问题,一种方法是这样做会是:

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,所以如果单个 word 有 3 个 word_nouns(假设有 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).

然后,我们将其优化为 3 个查询,而不是 4 个查询 - word_nouns 1 个,每个 名词 3 个,我们将其优化为 3 个查询 - word_nouns 1 个> 和每个 contenty_type (EnNounFrNoun)

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_typeNouns 时,这会很好地扩展,但是如果您有 1 个 Noun percontenty_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天全站免登陆