1

I am trying to insert a record into a oracle db via sqlalchemy, here is my below model:

class Item(Base):
    __tablename__ = 'items'
    id = db.Column(db.Integer, db.Sequence('item_id_seq'), nullable=False, primary_key=True)
    name = db.Column(db.String(128), nullable=True)

    def __init__(self, name):
        self.name = name

I have already created the table in the db by running the db migrate and upgrade. I am trying to insert a simple row in the db table as in :

test_obj = Item(name='item-1')
db.session.add(test_obj)
db.session.commit()

But the insert fails with the error TypeError: unhashable type: 'list'

But if I insert it along with the id (as below) and with the id initialized in the constructor, it inserts successfully.

test_obj = Item(id = 1, name='item-1')
db.session.add(test_obj)
db.session.commit()

class Item(Base):
    ...
    def __init__(self, id, name):
        self.id = id
        self.name = name

Since I have set id with a sequence, it should auto increment and get inserted automatically, but this is not the case here, any help would be appreciated.

2
  • 1
    This might be occuring due to this: github.com/sqlalchemy/sqlalchemy/issues/4335, I am trying to downgrade the version of cx-Oracle Commented Aug 27, 2019 at 22:43
  • I am using Oracle, I have updated the question, I had mentioned it in a flaw. Commented Aug 27, 2019 at 22:53

2 Answers 2

3

USE sqlalchemy 1.3.6 or above Sqlalchemy does not support auto increment for oracle 11g

if you are using "oracle 11g" then use following code:

from sqlalchemy import event
from sqlalchemy.schema import CreateSequence, DDL

db_session = sessionmaker(bind={your database engine})
class Item(Base):
    __tablename__ = 'items'
    id = db.Column(db.Integer, nullable=False, primary_key=True)
    name = db.Column(db.String(128), nullable=True)

    def __init__(self, name):
        self.name = name

def create_trigger_for_items(*args, **kwargs):
    with con.db_session() as session:
        session.execute(CreateSequence(db.Sequence('item_id_seq')))
        session.execute(DDL("""CREATE OR REPLACE TRIGGER ITEM_ID_TRIGGER 
                BEFORE INSERT ON items
                REFERENCING NEW AS NEW
                FOR EACH ROW 
                BEGIN
                :NEW.id := item_id_seq.NEXTVAL;
                END;"""))


event.listen(Item.__table__, "after_create",
             create_trigger_for_items)

if you are using "oracle 12" then use following code:

class Item(Base):
    __tablename__ = 'items'
    id = db.Column(db.Integer, db.Sequence('item_id_seq'), default=db.Sequence('item_id_seq').next_value(), primary_key=True)
    name = db.Column(db.String(128), nullable=True)

    def __init__(self, name):
        self.name = name

if you are using "oracle 12c" then use following code:

class Item(Base):
    __tablename__ = 'items'
    id = db.Column(db.Integer, autoincrement=True, primary_key=True)
    name = db.Column(db.String(128), nullable=True)

    def __init__(self, name):
        self.name = name

then you can use:

test_obj = Item(name='item-1')
db.session.add(test_obj)
db.session.commit()
Sign up to request clarification or add additional context in comments.

Comments

0

Just mark id as the primary_key.

class Item(Base):
    __tablename__ = 'items'
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(128), nullable=True)

def __init__(self, name):
    self.name = name

2 Comments

Thanks, I have tried this, but still doesn't work, I have updated the question along with the primary key field.
It must be something outside of the code you've posted. Can you update your question with some more info? Maybe the complete stack trace.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.