如何在Django中使用update_or_create()和F()创建新记录?

时间:2018-08-26 07:17:43

标签: django django-models

假设我们有一个包含以下字段的钱包表:id,user_id,total,frozen,active,update_time。

每个用户在此表中只有一条记录,并且将一直更新。

例如

{
    id: 1,
    user_id: 100,
    total: 50.5,
    freeze: 0,
    active: 50.5,
    update_time: 2018-07-17 16:43:41,
}

当用户获得5美元时,我该如何使用 update_or_create()方法来更新总字段,冻结字段和活动字段取决于它们的原始值?

income = 5.0
Wallet.objects.update_or_create(
    user_id=obj.user.id,
    defaults={
        'update_time': datetime.now(),
        'active': F('active') + income,
        'total': F('total') + income,
    }
)

我尝试了F(),效果很好!

{
    id: 1,
    user_id: 100,
    total: 55.5,
    freeze: 0,
    active: 55.5,
    update_time: 2018-08-26 07:12:15,
}

但是,如果用户在钱包表中没有记录,这意味着这是他/她第一次赚钱,那么出问题了:

Failed to insert expression "Col(wallet, Wallet.total) + Value(5.0)" on Wallet.total. F() expressions can only be used to update, not to insert.

如果我真的想使用 update_or_create(),该如何解决?

需要您的帮助,谢谢!

2 个答案:

答案 0 :(得分:2)

您不能根据需要使用 F() 功能。您可以做的是,检查对象是否存在并执行操作。

income = 5.0
if Wallet.objects.filter(user_id=obj.user.id).exists():
    Wallet.objects.update_or_create(
        user_id=obj.user.id,
        defaults={
            'update_time': datetime.now(),
            'active': F('active') + income,
            'total': F('total') + income,
        }
    )
else:
    Wallet.objects.create(user_id=obj.user.id, **{'update_time': datetime.now(),
                                                  'active': income,
                                                  'total': income,
                                                  })

答案 1 :(得分:-1)

@JPG提出的解决方案受竞争条件的影响。根据使用情况,您可以尝试如下操作:

obj, created = ProductRedirectStats.objects.get_or_create(
        date=date.today(), product_id=product_id, defaults={"redirects": 1}
    )

if not created:
    ProductRedirectStats.objects.filter(date=date.today(), product_id=product_id).update(redirects=F("redirects") + 1)