Skip to main content
 首页 » 编程设计

python之AppEngine(或者可能在 Django 中)是否有称为 insert_or_update 的快捷方法为什么不

2025年05月04日22bonelee

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

谷歌应用引擎

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

Django

# 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'}) 

更新

返回应用引擎 documentation ,我找到了关于这个 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") 

我想知道为什么没有在 App Engine 和 Django 中创建 insert_or_update 方法。

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 解决方案

See Below

请您参考如下方法:

Django

update_or_create (来自Django官方文档)

update_or_create(defaults=None, **kwargs) 

Django 1.7 版本中的新功能。

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

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

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() ,此方法容易出现竞争条件,如果未在数据库级别强制执行唯一性,则可能导致同时插入多行。

应用引擎

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