Django的.线程安全更新或创建.

Nik*_*nyh 13 python django

我们知道,该更新 - 是线程安全的操作.这意味着,当你这样做时:

  SomeModel.objects.filter(id=1).update(some_field=100)
Run Code Online (Sandbox Code Playgroud)

代替:

sm = SomeModel.objects.get(id=1)
sm.some_field=100
sm.save()
Run Code Online (Sandbox Code Playgroud)

您的应用程序是相对线程安全的,操作SomeModel.objects.filter(id=1).update(some_field=100)不会重写其他模型字段中的数据.

我的问题是..如果有任何办法可以做

  SomeModel.objects.filter(id=1).update(some_field=100)
Run Code Online (Sandbox Code Playgroud)

但是如果不存在对象的创建?

Nik*_*Nik 5

from django.db import IntegrityError

def update_or_create(model, filter_kwargs, update_kwargs)
    if not model.objects.filter(**filter_kwargs).update(**update_kwargs):
        kwargs = filter_kwargs.copy()
        kwargs.update(update_kwargs)
        try:
            model.objects.create(**kwargs)
        except IntegrityError:
            if not model.objects.filter(**filter_kwargs).update(**update_kwargs):
                raise  # re-raise IntegrityError
Run Code Online (Sandbox Code Playgroud)

我认为,问题中提供的代码不是很有说服力:谁想为模型设置id?让我们假设我们需要这个,我们有同步操作:

def thread1():
    update_or_create(SomeModel, {'some_unique_field':1}, {'some_field': 1})

def thread2():
    update_or_create(SomeModel, {'some_unique_field':1}, {'some_field': 2})
Run Code Online (Sandbox Code Playgroud)

使用update_or_create函数,取决于哪个线程首先出现,对象将被创建和更新,没有异常.这将是线程安全的,但显然没什么用处:取决于竞争条件值SomeModek.objects.get(some__unique_field=1).some_field可能是1或2.

Django提供了F对象,因此我们可以升级代码:

from django.db.models import F

def thread1():
    update_or_create(SomeModel, 
                     {'some_unique_field':1}, 
                     {'some_field': F('some_field') + 1})

def thread2():
    update_or_create(SomeModel, 
                     {'some_unique_field':1},
                     {'some_field': F('some_field') + 2})
Run Code Online (Sandbox Code Playgroud)

  • 在 django 1.7+ 中,您可以使用 QuerySet 的 update_or_create 方法。请参阅https://docs.djangoproject.com/en/1.8/ref/models/querysets/#django.db.models.query.QuerySet.update_or_create (2认同)