Reputation: 4445
I have a list of dict objects
data = [
{'id': 1, 'dt':'2002-01-02' },
{'id': 2, 'dt':'2014-01-15' },
{'id': 3, 'dt':'2005-10-20' }
]
and a table in sqlite created using sqlalchemy as follows
engine = create_engine(config.SQLALCHEMY_DATABASE_URI)
metadata = MetaData()
tbl1 = Table('t1', metadata,
Column('the_id', Integer, primary_key=True),
Column('the_dt', Date))
metadata.create_all(bind=engine)
stmt_insert = tbl1.insert().values(the_id=bindparam('id'), the_dt=bindparam('dt', type_=Date)
with engine.connect() as conn:
conn.execute(stmt_insert, data)
This gives me the following error:
sqlalchemy.exc.StatementError: (builtins.TypeError) SQLite Date type only accepts Python date objects as input.
What do I assign to the "type_" parameter to make this binding work ?
Upvotes: 1
Views: 6943
Reputation: 22942
You need to convert your dt
strings to date objects, for instance:
import datetime
for item in data:
item['dt'] = datetime.datetime.strptime(item['dt'], "%Y-%m-%d").date()
If you don't need the ORM part of SQLAlchemy (no class/table mapping). The easiest way is to tell SQLAlchemy that you use String instead of Date, like this:
tbl1 = Table('t1', metadata,
Column('the_id', Integer, primary_key=True),
Column('the_dt', String))
It will work because your date string use ISO 8601 format ("%Y-%m-%d").
But the best practices are:
int
, date
, etc.)The conversion can be done in the constructor of the class which is mapped to the table.
EDIT A kind of "solution"
from sqlalchemy import Table, Column, Integer, MetaData, Date, String
from sqlalchemy import create_engine
from sqlalchemy.sql import select
engine = create_engine('sqlite:///:memory:', echo=True)
metadata = MetaData()
I've created a "fake" table with a String
type instead of a Date
:
fake_tbl1 = Table('t1', metadata,
Column('id', Integer, primary_key=True),
Column('dt', String))
metadata.create_all(bind=engine)
And insert the data as-is:
data = [
{'id': 1, 'dt': '2002-01-02'},
{'id': 2, 'dt': '2014-01-15'},
{'id': 3, 'dt': '2005-10-20'}
]
stmt_insert = fake_tbl1.insert()
with engine.connect() as conn:
conn.execute(stmt_insert, data)
Then I redefine the same table with the required Date
field:
tbl2 = Table('t1', metadata,
Column('id', Integer, primary_key=True),
Column('dt', Date),
extend_existing=True)
Here is a rows selection:
stmt_select = select([tbl2])
with engine.connect() as conn:
result = conn.execute(stmt_select)
for row in result:
print(row)
You'll get:
(1, datetime.date(2002, 1, 2))
(2, datetime.date(2014, 1, 15))
(3, datetime.date(2005, 10, 20))
This works for your simple case, but I won't recommend this for a generic solution.
Upvotes: 2