Pracuję na bazie danych PostgreSQL przez sqlalchemy. Muszę pracować z datami BC z postgresql "date" typ kolumny (obsługuje daty BC http://www.postgresql.org/docs/9.2/static/datatype-datetime.html). Ale chociaż mogę wstawić daty BC w postaci łańcucha znaków (na przykład "2000-01-01 BC"), nie mogę ich odzyskać. Próba uzyskania daty BC z bazy danych podnosi Błąd wartości: rok jest poza zakresem. Na początku myślałem, że powodem jest to, że sqlalchemy w swoim typie Date używa python datetime.date modułu, który nie obsługuje dat BC, ale nie jestem do końca pewien. Próbowałem znaleźć sposób na mapowanie typu "date" w bazie danych na niestandardową klasę Pythona (aby obejść użycie modułu datetime.date), ale nie udało mi się jeszcze (znalazłem sposoby na dodanie logiki do różnych kroków przetwarzania w sqlalchemy, np. result_processor lub bind_expression z column_expression, ale nie udało mi się sprawić, żeby działało).sqlalchemy BC daty z postgresql
Oto przykład odwzorowania problemu.
from sqlalchemy import create_engine, Column, Integer, String, Date
from sqlalchemy.orm import sessionmaker
from sqlalchemy.ext.declarative import declarative_base
engine = create_engine('postgresql://database:[email protected]:5432/sqlalchemy_test', echo=True)
Base = declarative_base()
class User(Base):
__tablename__ = 'users'
id = Column(Integer, primary_key=True)
name = Column(String)
date = Column(Date)
def __repr__(self):
return "<User(name='%s', date='%s')>" % (self.name, self.date)
Base.metadata.create_all(engine)
Session = sessionmaker(bind=engine)
session = Session()
# remove objects from previous launches
session.query(User).delete()
import datetime
a_date = datetime.date.today()
# Insert valid date in datetime.date format, it works.
ed_user = User(name='ed', date=a_date)
# Insert BC date in string format, it works.
al_user = User(name='al', date='1950-12-16 BC')
session.add_all([ed_user, al_user])
session.commit()
# Insert data via raw sql, it works
conn = engine.connect()
conn.execute('INSERT INTO users (name, date) VALUES (%s, %s)', ("Lu", "0090-04-25 BC"))
# Check that all 3 objects are present
user_names = session.query(User.name).all()
print user_names
# Check entry with AD date, it works.
user = session.query(User).filter_by(name='ed').first()
print '-- user vith valid date: ', user, user.date
# But when trying to fetch date fields in any way, it raises Value error
# Trying to fetch model, it raises Value error
users = session.query(User).all()
print users
# Trying to fetch only field, it raises Value error
user_dates = session.query(User.date).all()
print user_dates
# Even trying to fetch dates in raw sql raises Value error
a = conn.execute('SELECT * FROM users')
print [c for c in a]
i wyjście z cienia:
2014-06-19 16:06:20,466 INFO sqlalchemy.engine.base.Engine select version()
2014-06-19 16:06:20,466 INFO sqlalchemy.engine.base.Engine {}
2014-06-19 16:06:20,468 INFO sqlalchemy.engine.base.Engine select current_schema()
2014-06-19 16:06:20,468 INFO sqlalchemy.engine.base.Engine {}
2014-06-19 16:06:20,470 INFO sqlalchemy.engine.base.Engine SELECT CAST('test plain returns' AS VARCHAR(60)) AS anon_1
2014-06-19 16:06:20,470 INFO sqlalchemy.engine.base.Engine {}
2014-06-19 16:06:20,471 INFO sqlalchemy.engine.base.Engine SELECT CAST('test unicode returns' AS VARCHAR(60)) AS anon_1
2014-06-19 16:06:20,471 INFO sqlalchemy.engine.base.Engine {}
2014-06-19 16:06:20,473 INFO sqlalchemy.engine.base.Engine show standard_conforming_strings
2014-06-19 16:06:20,473 INFO sqlalchemy.engine.base.Engine {}
2014-06-19 16:06:20,475 INFO sqlalchemy.engine.base.Engine select relname from pg_class c join pg_namespace n on n.oid=c.relnamespace where n.nspname=current_schema() and relname=%(name)s
2014-06-19 16:06:20,475 INFO sqlalchemy.engine.base.Engine {'name': u'users'}
2014-06-19 16:06:20,477 INFO sqlalchemy.engine.base.Engine BEGIN (implicit)
2014-06-19 16:06:20,478 INFO sqlalchemy.engine.base.Engine DELETE FROM users
2014-06-19 16:06:20,478 INFO sqlalchemy.engine.base.Engine {}
2014-06-19 16:06:20,480 INFO sqlalchemy.engine.base.Engine INSERT INTO users (name, date) VALUES (%(name)s, %(date)s) RETURNING users.id
2014-06-19 16:06:20,481 INFO sqlalchemy.engine.base.Engine {'date': datetime.date(2014, 6, 19), 'name': 'ed'}
2014-06-19 16:06:20,482 INFO sqlalchemy.engine.base.Engine INSERT INTO users (name, date) VALUES (%(name)s, %(date)s) RETURNING users.id
2014-06-19 16:06:20,482 INFO sqlalchemy.engine.base.Engine {'date': '1950-12-16 BC', 'name': 'al'}
2014-06-19 16:06:20,483 INFO sqlalchemy.engine.base.Engine COMMIT
2014-06-19 16:06:20,494 INFO sqlalchemy.engine.base.Engine INSERT INTO users (name, date) VALUES (%s, %s)
2014-06-19 16:06:20,494 INFO sqlalchemy.engine.base.Engine ('Lu', '0090-04-25 BC')
2014-06-19 16:06:20,495 INFO sqlalchemy.engine.base.Engine COMMIT
2014-06-19 16:06:20,517 INFO sqlalchemy.engine.base.Engine BEGIN (implicit)
2014-06-19 16:06:20,517 INFO sqlalchemy.engine.base.Engine SELECT users.name AS users_name
FROM users
2014-06-19 16:06:20,517 INFO sqlalchemy.engine.base.Engine {}
-- user names: [(u'ed',), (u'al',), (u'Lu',)]
2014-06-19 16:06:20,520 INFO sqlalchemy.engine.base.Engine SELECT users.id AS users_id, users.name AS users_name, users.date AS users_date
FROM users
WHERE users.name = %(name_1)s
LIMIT %(param_1)s
2014-06-19 16:06:20,520 INFO sqlalchemy.engine.base.Engine {'name_1': 'ed', 'param_1': 1}
-- user with valid date: <User(name='ed', date='2014-06-19')> 2014-06-19
2014-06-19 16:06:20,523 INFO sqlalchemy.engine.base.Engine SELECT users.id AS users_id, users.name AS users_name, users.date AS users_date
FROM users
2014-06-19 16:06:20,523 INFO sqlalchemy.engine.base.Engine {}
Traceback (most recent call last):
File "test_script.py", line 49, in <module>
users = session.query(User).all()
File "/home/pavel/.virtualenvs/common/local/lib/python2.7/site-packages/sqlalchemy/orm/query.py", line 2292, in all
return list(self)
File "/home/pavel/.virtualenvs/common/local/lib/python2.7/site-packages/sqlalchemy/orm/loading.py", line 65, in instances
fetch = cursor.fetchall()
File "/home/pavel/.virtualenvs/common/local/lib/python2.7/site-packages/sqlalchemy/engine/result.py", line 788, in fetchall
self.cursor, self.context)
File "/home/pavel/.virtualenvs/common/local/lib/python2.7/site-packages/sqlalchemy/engine/base.py", line 1111, in _handle_dbapi_exception
util.reraise(*exc_info)
File "/home/pavel/.virtualenvs/common/local/lib/python2.7/site-packages/sqlalchemy/engine/result.py", line 782, in fetchall
l = self.process_rows(self._fetchall_impl())
File "/home/pavel/.virtualenvs/common/local/lib/python2.7/site-packages/sqlalchemy/engine/result.py", line 749, in _fetchall_impl
return self.cursor.fetchall()
ValueError: year is out of range
Używam PostgreSQL 9.1.11, SQLAlchemy 0.9.4, Python 2.7
Moje pytanie brzmi: czy jest jakiś sposób, aby współpracować z BC datuje kolumnę typu "date" w postgresql poprzez sqlalchemy (przynajmniej pobiera ją jako ciąg, ale w pewnym sensie odwzorowuje ją na jakiś moduł, który może pracować z datami BC, takimi jak FlexiDate lub astropy.time)?