How to do an upsert with SqlAlchemy?

前端 未结 7 1518
别跟我提以往
别跟我提以往 2020-12-08 01:37

I have a record that I want to exist in the database if it is not there, and if it is there already (primary key exists) I want the fields to be updated to the current state

7条回答
  •  北海茫月
    2020-12-08 02:24

    This allows access to the underlying models based on string names

    def get_class_by_tablename(tablename):
      """Return class reference mapped to table.
      https://stackoverflow.com/questions/11668355/sqlalchemy-get-model-from-table-name-this-may-imply-appending-some-function-to
      :param tablename: String with name of table.
      :return: Class reference or None.
      """
      for c in Base._decl_class_registry.values():
        if hasattr(c, '__tablename__') and c.__tablename__ == tablename:
          return c
    
    
    sqla_tbl = get_class_by_tablename(table_name)
    
    def handle_upsert(record_dict, table):
        """
        handles updates when there are primary key conflicts
    
        """
        try:
            self.active_session().add(table(**record_dict))
        except:
            # Here we'll assume the error is caused by an integrity error
            # We do this because the error classes are passed from the
            # underlying package (pyodbc / sqllite) SQLAlchemy doesn't mask
            # them with it's own code - this should be updated to have
            # explicit error handling for each new db engine
    
            # add explicit error handling for each db engine 
            active_session.rollback()
            # Query for conflic class, use update method to change values based on dict
            c_tbl_primary_keys = [i.name for i in table.__table__.primary_key] # List of primary key col names
            c_tbl_cols = dict(sqla_tbl.__table__.columns) # String:Col Object crosswalk
    
            c_query_dict = {k:record_dict[k] for k in c_tbl_primary_keys if k in record_dict} # sub-dict from data of primary key:values
            c_oo_query_dict = {c_tbl_cols[k]:v for (k,v) in c_query_dict.items()} # col-object:query value for primary key cols
    
            c_target_record = session.query(sqla_tbl).filter(*[k==v for (k,v) in oo_query_dict.items()]).first()
    
            # apply new data values to the existing record
            for k, v in record_dict.items()
                setattr(c_target_record, k, v)
    

提交回复
热议问题