2

我多次重复这种模式:(我认为这不是很常见吗?)

谷歌应用引擎

# Insert if object doesn't exist, Otherwise Update Object
obj = get_or_insert('123', title='Hello World')
obj.title = 'Hello World'
obj.puts()

姜戈

# Insert if object doesn't exist, Otherwise Update Object
obj, created = Model.objects.get_or_create(id='123', 
                   defaults={'title':'Hello World'}
if not created:
    obj.title = 'Hello World'
    obj.save()

如果打电话就好了insert_or_update。不是吗?例如:

# AppEngine
obj = insert_or_update('123', title='Hello World')

# Django
obj = Model.objects.insert_or_update(id='123', defaults={'title': 'Hello World'})

更新

回到 App Engine文档,我找到了关于这个get_or_insert方法做什么的片段。类似于以下内容:

def txn(key_name, **kwds):
    entity = Story.get_by_key_name(key_name, parent=kwds.get('parent'))
    if entity is None:
        entity = Story(key_name=key_name, **kwds)
        entity.put()
    return entity

def get_or_insert(key_name, **kwargs):
    return db.run_in_transaction(txn, key_name, **kwargs)

get_or_insert('some key', title="The Three Little Pigs")

我想知道为什么insert_or_update在应用程序引擎和 django 中都没有创建一个方法。

App Engine 解决方法

@classmethod
def insert_or_update(cls, key_name, parent=None, **kwargs):
    def _tx():
        entity = cls.get_by_key_name(key_name, parent=parent)
        if entity:
            for key in kwargs:
                setattr(entity, key, kwargs[key])
        else:
            entity = cls(key_name=key_name, parent=parent, **kwargs)
        entity.put()
        return entity
    return db.run_in_transaction(_tx)

Django 解决方案

见下文

4

3 回答 3

1

姜戈

update_or_create(来自 Django 官方文档)

update_or_create(defaults=None, **kwargs)

Django 1.7 版本中的新功能。

一种使用给定对象更新对象的便捷方法,kwargs如有必要,创建一个新对象。这defaults是用于更新对象的(字段,值)对的字典。

返回 的元组(object, created),其中object是创建或更新的对象,created是一个布尔值,指定是否创建了新对象。

update_or_create方法尝试根据给定的kwargs. 如果找到匹配项,它会更新defaults字典中传递的字段。

这意味着作为样板代码的快捷方式。例如:

try:
    obj = Person.objects.get(first_name='John', last_name='Lennon')
    for key, value in updated_values.iteritems():
        setattr(obj, key, value)
    obj.save()
except Person.DoesNotExist:
    updated_values.update({'first_name': 'John', 'last_name': 'Lennon'})
    obj = Person(**updated_values)
    obj.save()

随着模型中字段数量的增加,这种模式变得非常笨拙。上面的例子可以这样重写update_or_create()

obj, created = Person.objects.update_or_create(
    first_name='John', last_name='Lennon', defaults=updated_values)

有关如何解析在 kwargs 中传递的名称的详细说明,请参阅get_or_create().

如上所述get_or_create(),如果在数据库级别未强制执行唯一性,此方法容易出现竞争条件,这可能导致同时插入多行。

应用引擎

正如马特之前提到的那样,还没有那么幸运,它可能不是一个常见的用例。也许在 AppEngine 中,这样的用例并不多。

于 2013-12-06T17:45:33.220 回答
0

它可能不像你想象的那么普遍。就个人而言,我发现自己不必经常这样做,当我这样做时,它只比你提出的insert_or_update方法长两三行,这不足以让我为这个功能哭泣或激励我添加它我。虽然我过去使用INSERT … ON DUPLICATE KEY UPDATE过很多 MySQL。

我自己也有过几次这样的经历,就在几周前,我想知道为什么 Django 没有toggle关于 M2M 关系的方法……我最终做了一个:

https://github.com/Matt-Stevens/django/commit/f7c36

编辑

Django 1.7 看起来会具备这种“ UPSERT ”能力,https://github.com/django/django/commit/6272d

于 2013-02-27T18:10:30.753 回答
0

如果我正确理解了这个问题:

obj, created = Model.objects.get_or_create(id='123', 
               defaults={'title':'Hello World'})

以上内容应替换为以下内容:

obj, created = Model.objects.get_or_create(foo='alpha', bar='beta' 
               defaults={'title':'Hello World'})

其中foobar是模型中的字段。这解决了 django 的重复问题。不确定应用引擎。高温高压

于 2013-02-27T17:11:41.870 回答