簡體   English   中英

如何使用新主鍵克隆 SQLAlchemy object

[英]How to clone a SQLAlchemy object with new primary key

我想克隆一個 SQLAlchemy object:

我試過:

product_obj = products.all()[0] #here products is service name

product_obj.product_uid = 'soemthing' #here product_uid is the pk of product model

products.save(product_obj)

但它只是更新舊的 object。

這是products.save function 的代碼:

class Service(object):

        __model__ = None

       def save(self, model):
            self._isinstance(model)
            db.session.add(model)
            db.session.commit()
            return model

這應該工作:

product_obj = products.all()[0]

db.session.expunge(product_obj)  # expunge the object from session
make_transient(product_obj)  # http://docs.sqlalchemy.org/en/rel_1_1/orm/session_api.html#sqlalchemy.orm.session.make_transient

product_obj.product_uid = 'something'
db.session.add(product_obj)

對於sqlalchemy 1.3,我最終使用了輔助函數。

  1. 它將輸入模型中的所有非主鍵列復制到新模型實例。
  2. 它允許您直接將數據作為關鍵字參數傳遞。
  3. 它保持原始模型對象不變。
def clone_model(model, **kwargs):
    """Clone an arbitrary sqlalchemy model object without its primary key values."""
    # Ensure the model’s data is loaded before copying.
    model.id

    table = model.__table__
    non_pk_columns = [k for k in table.columns.keys() if k not in table.primary_key]
    data = {c: getattr(model, c) for c in non_pk_columns}
    data.update(kwargs)

    clone = model.__class__(**data)
    db.session.add(clone)
    db.session.commit()
    return clone

使用此功能,您可以使用以下方法解決上述問題:

product_obj = products.all()[0]  # Get the product from somewhere.
cloned_product_obj = clone_model(product_obj, product_uid='something')

根據您的用例,您可能希望從此函數中刪除對db.session.commit()的調用。


這個答案基於https://stackoverflow.com/a/13752442/769486 (如何獲取模型的列?)以及如何獲取SQLAlchemy對象的主鍵名稱? (如何獲得模型的主鍵?)。

一種可能的方法是使用dictalchemy

new_instance = InstanceModel(**old_instance.asdict())
try this out 
@classmethod
def clone(cls,tempversion,**kwargs):
    attributestoremove=["tempversion","id"]
    relationshipAttributes = cls.get_relationshipAttributes()
    kwargs = { key:(None if value=='nan' else value)  for key,value in kwargs.items() if hasattr(cls, key) and key not in relationshipAttributes and\
    key not in attributestoremove}
    kwargs["tempversion"]=tempversion
    record = cls(**kwargs)
    db.session.add(record)
    db.session.commit()
    return record
    try:
        db.session.commit()
    except IntegrityError:
        db.session.rollback()
        record = None
    return record

此方法將克隆任何 sqlalchemy db 對象。 將它添加到模型的類中。 請注意新對象的 id 將在提交期間創建(見評論):

    def clone(self):
            d = dict(self.__dict__)
            d.pop("id") # get rid of id
            d.pop("_sa_instance_state") # get rid of SQLAlchemy special attr
            copy = self.__class__(**d)
            db.session.add(copy)
            # db.session.commit() if you need the id immediately
            return copy

我把這個 function 放在一起克隆對象。 它不分配主鍵,但它會將現有的主鍵設置為None並且一旦刷新到數據庫,它們就會由自動增強(如果設置)分配。

from sqlalchemy.orm.session import make_transient
from sqlalchemy import inspect

def clone_sql_object(obj, session):

    # remove the object from the session (set its state to detached)
    session.expunge(obj)

    # make it transient (set its state to transient)
    make_transient(obj)

    # now set all primary keys to None so there are no conflicts later
    for pk in inspect(obj).mapper.primary_key:
        setattr(obj, pk.name, None)

    return obj

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM