Adding entry to SQLAlchemy database triggers `sqlite InterfaceError: Error binding parameter 0 - probably unsupported type`

Viewed 195

I'm trying to add an Attempt to the sqlite database using the following SQLAlchemy model file:

from app import db
from datetime import datetime

class User(db.Model):
    id = db.Column(db.Text, primary_key=True)
    name = db.Column(db.Text, nullable=False)
    email = db.Column(db.Text, nullable=False, unique=True)
    profile_pic = db.Column(db.Text, nullable=False)

    def __repr__(self):
        return '<User {}>'.format(self.name)

class Puzzle(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    width = db.Column(db.Integer, nullable=False)
    height = db.Column(db.Integer, nullable=False)
    letters = db.Column(db.String(225), nullable=False)

    def __repr__(self):
        return '<PuzzleNum {}>'.format(self.id)

class Attempt(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    puzzle_id = db.Column(db.Integer, db.ForeignKey('puzzle.id'))
    user_id = db.Column(db.Text, db.ForeignKey('user.id'))
    started = db.Column(db.DateTime, index=True, default=datetime.utcnow)
    finished = db.Column(db.DateTime, index=True)

    def __repr__(self):
        return '<Attempt {}>'.format(self.started)

I use flask shell to execute the following to get the User and Puzzle objects (which indicates that my other loaded tables are working fine):

>>> u = User.query.first()
>>> print(u.name)
Mark
>>> p = Puzzle.query.get(1)
>>> print(p.width)
10

I get the desired User and Puzzle object for my Attempt, but when I run the following it triggers an sqlite InterfaceError:

>>> a = Attempt(puzzle_id=p, user_id=u)
>>> db.session.add(a)
>>> db.session.commit()
Traceback (most recent call last):
  File "a:\shell\weave2\venv\lib\site-packages\sqlalchemy\engine\base.py", line 1276, in _execute_context
    self.dialect.do_execute(
  File "a:\shell\weave2\venv\lib\site-packages\sqlalchemy\engine\default.py", line 608, in do_execute
    cursor.execute(statement, parameters)
sqlite3.InterfaceError: Error binding parameter 0 - probably unsupported type.

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "<console>", line 1, in <module>
  File "a:\shell\weave2\venv\lib\site-packages\sqlalchemy\orm\scoping.py", line 163, in do
    return getattr(self.registry(), name)(*args, **kwargs)
  File "a:\shell\weave2\venv\lib\site-packages\sqlalchemy\orm\session.py", line 1046, in commit
    self.transaction.commit()
  File "a:\shell\weave2\venv\lib\site-packages\sqlalchemy\orm\session.py", line 504, in commit
    self._prepare_impl()
  File "a:\shell\weave2\venv\lib\site-packages\sqlalchemy\orm\session.py", line 483, in _prepare_impl
    self.session.flush()
  File "a:\shell\weave2\venv\lib\site-packages\sqlalchemy\orm\session.py", line 2540, in flush
    self._flush(objects)
  File "a:\shell\weave2\venv\lib\site-packages\sqlalchemy\orm\session.py", line 2682, in _flush
    transaction.rollback(_capture_exception=True)
  File "a:\shell\weave2\venv\lib\site-packages\sqlalchemy\util\langhelpers.py", line 68, in __exit__
    compat.raise_(
  File "a:\shell\weave2\venv\lib\site-packages\sqlalchemy\util\compat.py", line 182, in raise_
    raise exception
  File "a:\shell\weave2\venv\lib\site-packages\sqlalchemy\orm\session.py", line 2642, in _flush
    flush_context.execute()
  File "a:\shell\weave2\venv\lib\site-packages\sqlalchemy\orm\unitofwork.py", line 422, in execute
    rec.execute(self)
  File "a:\shell\weave2\venv\lib\site-packages\sqlalchemy\orm\unitofwork.py", line 586, in execute
    persistence.save_obj(
  File "a:\shell\weave2\venv\lib\site-packages\sqlalchemy\orm\persistence.py", line 239, in save_obj
    _emit_insert_statements(
  File "a:\shell\weave2\venv\lib\site-packages\sqlalchemy\orm\persistence.py", line 1135, in _emit_insert_statements
    result = cached_connections[connection].execute(
  File "a:\shell\weave2\venv\lib\site-packages\sqlalchemy\engine\base.py", line 1011, in execute
    return meth(self, multiparams, params)
  File "a:\shell\weave2\venv\lib\site-packages\sqlalchemy\sql\elements.py", line 298, in _execute_on_connection
    return connection._execute_clauseelement(self, multiparams, params)
  File "a:\shell\weave2\venv\lib\site-packages\sqlalchemy\engine\base.py", line 1124, in _execute_clauseelement
    ret = self._execute_context(
  File "a:\shell\weave2\venv\lib\site-packages\sqlalchemy\engine\base.py", line 1316, in _execute_context
    self._handle_dbapi_exception(
  File "a:\shell\weave2\venv\lib\site-packages\sqlalchemy\engine\base.py", line 1510, in _handle_dbapi_exception
    util.raise_(
  File "a:\shell\weave2\venv\lib\site-packages\sqlalchemy\util\compat.py", line 182, in raise_
    raise exception
  File "a:\shell\weave2\venv\lib\site-packages\sqlalchemy\engine\base.py", line 1276, in _execute_context
    self.dialect.do_execute(
  File "a:\shell\weave2\venv\lib\site-packages\sqlalchemy\engine\default.py", line 608, in do_execute
    cursor.execute(statement, parameters)
sqlalchemy.exc.InterfaceError: <unprintable InterfaceError object>
1 Answers

Your Attempt class has a number of properties includingpuzzle_id and user_id. Both of which are of type Integer:

class Attempt(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    puzzle_id = db.Column(db.Integer, db.ForeignKey('puzzle.id'))
    user_id = db.Column(db.Text, db.ForeignKey('user.id'))
    started = db.Column(db.DateTime, index=True, default=datetime.utcnow)
    finished = db.Column(db.DateTime, index=True)

    def __repr__(self):
        return '<Attempt {}>'.format(self.started)

You query your ORM and retrieve a Puzzle and User object and store them as p and u. If you checked what type p was (eg. on the terminal: type(p)) you would get <PuzzleNum 1> for example (not an Integer)

So this fails:

>>> a = Attempt(puzzle_id=p, user_id=u)
>>> db.session.add(a)
>>> db.session.commit

puzzle_id is expecting an Integer but it's getting a Puzzle. Changing your code to:

>>> a = Attempt(puzzle_id=p.id, user_id=u.id)
>>> db.session.add(a)
>>> db.session.commit

Will access the id attribute on each of the models, which is an Integer and so doesn't break the rules you've set.

Related