2016-10-20 47 views
0

我建立的詞彙,並有以下型號:瞭解Django的GenericForeignKey和GenericRelation

class Word(Model): 
name = CharField(max_length=75) 

class EnNoun(Model): 
word = OneToOneField(Word) 

class FrNoun(Model): 
word = ForeignKey(Word) 
gender = CharField() 

同一個詞可以在兩個EnNounFrNoun。 是否可以使用最少的查詢次數(對於語言和詞類將會有更多類似的類,如ItAdverb),爲給定詞提取結果EnNounFrNoun

如何從一個lang存儲翻譯到另一個(查詢20+表不是一個選項)。

GenericForeign鑰匙有什麼用? 我如何一般使用它們?

謝謝。

UPDATE

有如下翻譯類:

@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。

回答

1

GenericForeignKey嘗試給你一個ForeignKey的行爲,但是反對一種類型的對象,他們這樣做的一組對象類型(這就是爲什麼他們定義了2列,1保持primery_key和另一個保持contenty_type)。

GenericRelationGenericForeignKey的反向關係,因爲Django的不自動爲GenericForeignKeys(不像ForeignKeys)手動必須設置他們創造的反向關係。

我不是很熟悉的翻譯/詞彙人員的最佳實踐,但如果你想用GenericRelationsGenericForeignKeys來解決這個問題,一個辦法做到這一點是:

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

然後,而不是4項的查詢 - 1爲word_nouns和3對每個noun,我們把它優化至3項的查詢 - 1爲word_nouns和2每個contenty_typeEnNounFrNoun

for word_noun in word.nouns.all().prefetch_related('noun'): 
    print word_noun.noun #this will not make a query 

的差現在查詢的數量將取決於不同的ContentTypes的數量,而不是相關的WordNoun對象的數量。

這秤不錯,當你從你的預取列表中的一個contenty_type有幾個Nouns,但沒有什麼區別,如果你有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() 
+0

確定。謝謝。我認爲在這種情況下GenericForeignKey效率不高。但我現在在做翻譯表。我認爲這是事實。查看更新 –

+0

當你收到這個'to_word'錯誤?似乎你正在嘗試做某種過濾?如果你只爲'from_word'和'to_word'屬性使用'Word'類,那麼你可以安全地使用普通的'ForeignKey'而不是'GenericForeignKey'。 – Todor

+0

我用get_or_create。如何對通用密鑰進行預過濾? –

相關問題