2

私は Django 1.4、postgres 9.1.x、および Tastypie 0.9.11 を使用して API を作成しています。

次のモデルを定義しました。

class Activity(models.Model):
    company = models.ForeignKey(Company)
    opportunity = models.ForeignKey(Opportunity)
    name = models.CharField(max_length=200)
    ...

このプロセス中にいくつかの特別なことを行うために、「保存」メソッドを上書きしています。

def save(self, *args, **kwargs):
    saveResult = None
    try: 
        saveResult = super(Activity, self).save(*args, **kwargs)
    except IntegrityError, e:
        logger.error('IntegrityError %s' % e.message)

    if(not self.pk):
        try:
            self = Activity.objects.get(company_id=self.company.id,opportunity_id=self.opportunity.id)
        except ObjectDoesNotExist, e:
            pass
        except DatabaseError, e:
            logger.error('DatabaseError %s' % e.message)

    if(self.pk and not self.notified):
        send_notification(...)
        self.notified = 1
        self.save()

    return saveResult

以下に、私が行っている POST リクエストの例を示します。

curl --dump-header - -H "Content-Type: application/json" -X POST -d '{"company": {"id":10},"opportunity": {"id":39}}'  http://127.0.0.1:8001/api/v1/activity/ 

プロセスは新しいオブジェクトに対してはうまく機能していますが、既存の行に対して POST リクエストを実行すると (それが新しいかどうかを以前に知る方法がありません)、もちろん、正しい重複キー エラーです。

次に、既存の行に格納されている情報を自己データに入力したいので、次のクエリを実行します (よりエレガントな方法が見つかりませんでした。より良いオプションがあれば、感謝します):

self = Activity.objects.get(company_id=self.company.id,opportunity_id=self.opportunity.id)

問題は、その「get」行が DatabaseError をスローし、「現在のトランザクションは中止されました。コマンドはトランザクションブロックの終わりまで無視されました」というメッセージがスローされ、既存のオブジェクトの取得が回避されるため、プロセスが停止していることです。

これらは、画面に表示されるメッセージです。

2012-10-18T04:57:27+00:00 app[web.1]: .............Saving new activity.............
2012-10-18T04:57:27+00:00 app[web.1]: Company: 10, video test | Opportunity: 39 | Activity: , created: None, None, 1, 
2012-10-18T04:57:27+00:00 app[web.1]: IntegrityError duplicate key value violates unique constraint "db_activity_company_id_1276b66f55cae366_uniq"
2012-10-18T04:57:27+00:00 app[web.1]: DETAIL:  Key (company_id, opportunity_id)=(10, 39) already exists.
2012-10-18T04:57:27+00:00 app[web.1]: DatabaseError current transaction is aborted, commands ignored until end of transaction block

ところで:MySqlでまったく同じことを試してみましたが、うまくいきました。

したがって、「get」メソッドがエラーを生成する理由がわかりません。以前に発生した IntegrateError に関連している可能性があると思いますが、それを回避する方法がわかりません。

どんな助けでも大歓迎です。ありがとうございました。

4

3 に答える 3

2

ここの論理がわかりません。この行でコードを見てください

 if(not self.pk):
    try:
        self = Activity.objects.get(company_id=self.company.id,opportunity_id=self.opportunity.id)
    except ObjectDoesNotExist, e:
        pass
    except DatabaseError, e:
        logger.error('DatabaseError %s' % e.message)

あなたが言っているのは、現在のオブジェクト(自己)がデータベースに存在しない場合です。既存のものを取り、それに割り当てます。それは自己がどのように働いているかではありません。

最初に、レコードがDBに存在するかどうかを確認する必要があります。存在する場合は、ローカル変数に割り当てます。存在しない場合は、保存してから同じローカル変数に追加します。

def save(self, *args, **kwargs):

    try:
        saveResult = Activity.objects.get(company_id=self.company.id,opportunity_id=self.opportunity.id)
    except ObjectDoesNotExist, e:
        #Object does not exist. Add it
        saveResult = super(Activity, self).save(*args, **kwargs)

    if not saveResult.notified:
        send_notification(...)
        saveResult.notified = 1
        saveResult.save()

    return saveResult
于 2012-10-18T13:03:22.690 に答える
0

DBエラーをキャッチして、何も起こらなかった場合に続行することは、私には奇妙に見えます。

current transaction is aborted, commands ignored until end of transaction block

postgres でこのようなエラーが発生した後に続行する場合は、セーブポイントを使用する必要があります。

多分Activity.objects.get_or_create(..., defaults=dict(attr=value))あなたが必要とするすべてをします。

于 2012-10-18T12:42:40.057 に答える
0

自分でトランザクションを管理しようとしましたか? (以下の例を参照してください) save メソッド全体が 1 つのトランザクション内にラップされているように見えます。そのため、エラーが発生したクエリの後の最初のクエリでは常に例外が発生します。

def save(self, *args, **kwargs):
    with transaction.commit_manually:
        saveResult = None
        sid = transaction.savepoint()
        try: 
            saveResult = super(Activity, self).save(*args, **kwargs)
            transaction.savepoint_commit(sid)
        except IntegrityError, e:
            logger.error('IntegrityError %s' % e.message)
            transaction.savepoint_rollback(sid)
        transaction.commit()

    if(not self.pk):
        try:
            self = Activity.objects.get(company_id=self.company.id,opportunity_id=self.opportunity.id)
        except ObjectDoesNotExist, e:
            pass
        except DatabaseError, e:
            logger.error('DatabaseError %s' % e.message)

    if(self.pk and not self.notified):
        send_notification(...)
        self.notified = 1
        self.save()

    return saveResult
于 2012-10-18T21:59:08.413 に答える