6

私はユーザーに以下のようなモデルを共有させています:

class Share( models.Model ):
    sharer = models.ForeignKey(User, verbose_name=_("Sharer"), related_name='sharer')
    receiver = models.ForeignKey(User, verbose_name=_("Receiver"), related_name='receiver')

    class Meta:
        unique_together = ( ("sharer", "receiver"), ("receiver", "sharer") )

shareer(S)とreceiver(R)の単一のオブジェクトを保存したい(順序はRSまたはSRに関係ありません)。ただし、unique_togetherを超えると、これは実行されません。RSがデータベースにあり、SRを保存すると、これに対する検証が得られないとします。このために、Shareモデルのカスタム固有の検証を作成しました。

    def validate_unique(
        self, *args, **kwargs):
            super(Share, self).validate_unique(*args, **kwargs)
            if self.__class__.objects.filter( Q(sharer=self.receiver, receiver=self.sharer) ).exists():
                raise ValidationError(
                    {
                        NON_FIELD_ERRORS:
                        ('Share with same sharer and receiver already exists.',)
                    }
                )

    def save(self, *args, **kwargs):
        # custom unique validate
        self.validate_unique()
        super(Share, self).save(*args, **kwargs)

この方法は、通常の使用では正常に機能します。

問題: 共有と受信者の要求を取得し、共有オブジェクト(SRまたはRS)を保存してから、ほぼ同時に応答(共有オブジェクト)を送信するマッチングアルゴリズムがあります。クエリ(データベースレベルなし)で重複をチェックしているので時間がかかるので、最後に2つのオブジェクトSRとRSがあります。

共有者Sと受信者RIの場合、SRまたはRSのいずれかで単一の共有オブジェクトしか保存できないという解決策が必要です。それ以外の場合は検証エラー(databseのIntegrityErrorなど)が発生します。

Django = 1.4、Database = Postgresql

4

1 に答える 1

4

おそらくpostgresqlでこれを解決できindexes on expressionsますが、別の方法があります:

class Share( models.Model ):
    sharer = models.ForeignKey(User)
    receiver = models.ForeignKey(User), related_name='receiver')
    key = models.CharField(max_length=64, unique=True)

    def save(self, *args, **kwargs):
        self.key = "{}.{}".format(*sorted([self.sharer_id, self.receiver_id]))
        super(Share, self).save(*args, **kwargs)

ただし、メソッドで値を変更すると、明らかに機能しませんQuerySet.updatedjango-denormを見ることもできます。トリガーでこれを解決します。

于 2013-03-05T13:43:10.290 に答える