2013-11-04 21 views
10

私は「多対多の一般的な関係」を作成する必要があると思います。Djangoの多対多の一般的な関係

私は2つの参加者の種類があります。これらの参加者は、2種類の異なる1つの以上の報酬持つことができます

class MemberParticipant(AbstractParticipant): 
    class Meta: 
     app_label = 'participants' 


class FriendParticipant(AbstractParticipant): 
    """ 
    Abstract participant common information shared for all rewards. 
    """ 
    pass 

を(報酬モデルは、他のアプリからです):

class SingleVoucherReward(AbstractReward): 
    """ 
    Single-use coupons are coupon codes that can only be used once 
    """ 
    pass 

class MultiVoucherReward(AbstractReward): 
    """ 
    A multi-use coupon code is a coupon code that can be used unlimited times. 
    """ 

だから今私が必要これらすべてをリンクする。これは私が関係(以下を参照)を創り出すことを考えていたからです。以下

提案リンクモデル:

class ParticipantReward(models.Model): 


    participant_content_type = models.ForeignKey(ContentType, editable=False, 
                 related_name='%(app_label)s_%(class)s_as_participant', 
                 ) 
    participant_object_id = models.PositiveIntegerField() 
    participant = generic.GenericForeignKey('participant_content_type', 'participant_object_id') 


    reward_content_type = models.ForeignKey(ContentType, editable=False, 
                 related_name='%(app_label)s_%(class)s_as_reward', 
                 ) 
    reward_object_id = models.PositiveIntegerField() 
    reward = generic.GenericForeignKey('reward_content_type', 'reward_object_id') 

注:私は、Djangoの1.6

+0

私は個人的に、ORMで得られた特別な機能のためにGenericForeignKeyではなくForeignKeyを使用することを好みます。 – schillingt

+2

@schillingtご返信ありがとうございます。報酬はSingleVoucherRewardまたはMultiVoucherRewardのいずれかになり、参加者はMemberParticipantまたはFriendParticipantになります。これは、私が標準的なFKのために行った場合、私は4つのFKを必要とし、そのうちの2つは常に空白であることを意味するでしょう。これは私には悪いデータベース設計を叫ぶので、GenericForeignKeyがより理にかなっていると思いますが、私は提案にはオープンしています。私はあなたのコメントに興味があります "追加機能が得られました"あなたはGenericForeignKeyを使って何を失うのですか? – GrantU

+0

これらのフィールドは、フィルタで使用することも、除外することもできません。 [docs](https://docs.djangoproject.com/en/dev/ref/contrib/contenttypes/#django.contrib.contenttypes.generic.GenericForeignKey)のこのセクションの最後に記載されています。 – schillingt

答えて

11

あなたのアプローチを使用していますが、正確に、それはあなたの既存のテーブルを与え行うには正しい方法です。何も正式なものはありませんが(this discussion、2007年にコア開発者が関わっていて、どこにも行かなかったようです)、これは同じアプローチ(サードパーティのライブラリで提供しています) hereは類似していますが、関係の片側のみが一般的です。

私はこの機能がDjangoのトランクにはなかったと言いたいのは、まれな要件ですが、既存のツールを使って実装するのはかなり簡単だということです。また、カスタム "スルー"テーブルが必要な可能性は非常に高いので、ほとんどのエンドユーザー実装ではカスタムコードを少しでも使用する予定です。

だけ他の潜在的に簡単な方法は、それらの間の多対多の関係で、基本参加者と報酬モデルがあり、その後、

最終的にはメンバー/友達などとして、これらのモデルを、あなたがよ拡張するmulti-table inheritanceを使用することです一般的な関係の複雑さと、オブジェクトのデータを2つのモデルに分散させることの複雑さを比較するだけです。

+0

ありがとう返信Gregのために、あなたがリンクしているサードパーティのライブラリは非常に面白く見えました。 – GrantU

7

遅くとも返信しましたが、一般的なm2mリレーションシップを実装する方法を探しているときにこの会話が見つかり、2セントが将来のGoogle社員に役立つと感じました。

グレッグ氏は、あなたが選んだアプローチが良い方法だと言います。

しかし、リバースリレーションやプリフェッチなどの機能を使用する場合は、汎用ツールを「既存のツールを使用して実装するのが簡単」とは限りません。

サードパーティのアプリdjango-genericm2mは素晴らしいですが、私の意見では、いくつかの欠点があります( 'through'オブジェクトはすべてデフォルトで同じデータベーステーブルにあり、 'add'/'メソッドを削除する - したがって一括追加/削除)。

これは、多対多リレーションシップの「django way」を実装するために必要なもので、私はちょっとdjangoの内部について少し学びたいので、最近django-gm2mをリリースしました。これはdjangoに組み込まれているGenericForeignKeyとManyToManyFieldに非常によく似たAPIを持っています(プリフェッチ、モデルによる...)、削除動作のカスタマイズを追加します。今のところ欠けているのは、適切なdjango管理インターフェースだけです。