【问题标题】:Django raising DatabaseError running a Model.objects.get运行 Model.objects.get 的 Django 引发 DatabaseError
【发布时间】:2012-10-08 22:08:32
【问题描述】:

我正在使用 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)
    ...

我在这个过程中重写了“save”方法来做一些特殊的事情:

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 请求时(我之前无法知道它是否是新对象),我当然会收到 IntegrityError由于重复键错误,这是正确的。

然后,我想用存储在现有行中的信息填充自我数据,这就是我执行以下查询的原因(我没有找到更优雅的方法,如果你有更好的选择的话赞赏):

自我 = 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 有关,但我还没有弄清楚如何避免它。

感谢任何帮助。谢谢。

【问题讨论】:

    标签: django django-models postgresql-9.1 tastypie


    【解决方案1】:

    捕获数据库错误,然后在没有发生任何事情的情况下继续,这对我来说看起来很奇怪。

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

    如果您想在 postgres 中出现此类错误后继续,则需要使用保存点。

    也许Activity.objects.get_or_create(..., defaults=dict(attr=value)) 可以满足您的所有需求。

    【讨论】:

    • 感谢您的回答...get_or_create 方法由于被调用到“save”方法而产生无限循环。
    【解决方案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)
    

    你是说:如果当前对象(self)在数据库中不存在。取一个现有的并分配给它。这不是 self 的工作方式。

    您应该首先检查数据库中是否存在该记录。如果存在,则将其分配给局部变量。如果不存在,则保存,然后将其添加到同一个局部变量中。

    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
    

    【讨论】:

    • “你是说:如果当前对象(self)在数据库中不存在。取一个现有的并分配给它。这不是 self 的工作方式。”......事情是当我收到数据时,它不包括任何 pk 而是包含外键关系的组合键。所以是的,我需要做的是检查它是否已经存在,如果不存在,则创建它......我认为逻辑试图插入,如果失败,然后阅读......但是我认为你的解决方案是有意义的...我搞砸了试图继续使用“自我”。谢谢!
    【解决方案3】:

    您是否尝试过自己管理交易? (请参见下面的示例) 看起来整个保存方法都包装在一个事务中,因此引发错误的查询之后的第一个查询总是会引发异常。

    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
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-06-07
      • 1970-01-01
      • 1970-01-01
      • 2021-09-03
      • 2012-04-22
      • 2021-12-26
      • 1970-01-01
      相关资源
      最近更新 更多