Think I solved it, thanks anyway!
Den tisdag 28 juli 2015 kl. 10:59:02 UTC+2 skrev Victor Tingström:
>
> A follow-up question: If I remove the platform from fund, how do I update
> the entries in ts_types?
>
> Den måndag 27 juli 2015 kl. 17:26:40 UTC+2 skrev Michael Bayer:
>>
>>
>>
>> On 7/27/15 10:56 AM, Victor Tingström wrote:
>>
>> Hey guys! First off, thank you for the library. Now to the problem, I'm
>> currently trying to implement a simple timeseries database using
>> `SQLAlchemy`. And so far I've seen the need for the following classes;
>> First off is the `Platform` class (which is the highest in the hierarchy)
>>
>>
>> OK, it's (mostly) runnable code, so I can just cut and paste (and cut out
>> numpy, ecch !) and run, great.
>>
>> First thing, localize to where it is actually breaking, use constraints:
>>
>> class TimeseriesTypeORM(Base):
>> __tablename__ = 'timeseriestypes'
>>
>> platform_id = Column(Integer, ForeignKey('platforms.platform_id'),
>> nullable=False)
>> # ...
>>
>> now we see the problem:
>>
>> <stacktrace>
>> sqlalchemy.exc.IntegrityError: (sqlite3.IntegrityError) NOT NULL
>> constraint failed: timeseriestypes.platform_id [SQL: u'INSERT INTO
>> timeseriestypes (platform_id, fund_id, ts_type_name) VALUES (?, ?, ?)']
>> [parameters: (None, 1, 'spot')]
>>
>>
>> so why is that. I'm looking around, and I don't see any relationships to
>> TimeseriesTypeORM linked to Platform, so that would be why.
>>
>> Platform is only linked to FundORM, and that goes to TimeseriesTypeORM.
>> So you either need to add another relationship, or use flush events to
>> double up the timeseriestypes.platform_id value. The latter might be
>> tricky because it might not fire off at the right time, so lets use
>> relationship which makes sure everything is done in the right order.
>> Let's use an append event to make the association automatic also:
>>
>> class FundORM(Base):
>> __tablename__ = 'funds'
>>
>> fund_id = Column(Integer, primary_key=True)
>> platform_id = Column(Integer, ForeignKey('platforms.platform_id'))
>> fund_name = Column(String, unique=True)
>>
>> ts_types = relationship('TimeseriesTypeORM', backref='fund')
>>
>> def __init__(self, fund_name):
>> self.fund_name = fund_name
>>
>> def __repr__(self):
>> return "<Fund name('%s'), Platform ID('%s')>" % (
>> self.fund_name, self.platform_id)
>>
>>
>> @event.listens_for(FundORM.ts_types, "append")
>> def append_ts_type(target, value, initiator):
>> if target.platform is None:
>> raise ValueError("FundORM has no PlatformORM assigned!")
>> value.platform = target.platform
>>
>>
>> class TimeseriesTypeORM(Base):
>> __tablename__ = 'timeseriestypes'
>>
>> platform_id = Column(Integer, ForeignKey('platforms.platform_id'))
>> fund_id = Column(Integer, ForeignKey('funds.fund_id'))
>> ts_type_id = Column(Integer, primary_key=True)
>> ts_type_name = Column(String)
>>
>> timeseries = relationship('TimeseriesORM', backref='ts_type')
>>
>> platform = relationship("PlatformORM")
>>
>> def __init__(self, ts_type_name=None):
>> self.ts_type_name = ts_type_name
>>
>> def __repr__(self):
>> return "<Type('%s'), Fund ID('%s'), Platform ID('%s')>" % (
>> self.ts_type_name, self.fund_id, self.platform_id)
>>
>>
>> now we run the same code and we get:
>>
>> SELECT timeseriestypes.platform_id AS timeseriestypes_platform_id,
>> timeseriestypes.fund_id AS timeseriestypes_fund_id,
>> timeseriestypes.ts_type_id AS timeseriestypes_ts_type_id,
>> timeseriestypes.ts_type_name AS timeseriestypes_ts_type_name
>> FROM timeseriestypes
>> WHERE timeseriestypes.ts_type_id = ?
>> 2015-07-27 11:22:35,956 INFO sqlalchemy.engine.base.Engine (1,)
>> <Type('spot'), Fund ID('1'), Platform ID('1')>
>>
>>
>>
>> see attached.
>>
>>
>>
>>
>>
>>
>>
>>
>> import numpy as np
>> import pandas as pd
>> import datetime
>> from sqlalchemy import create_engine, Column, Integer, String, Float,
>> ForeignKey, TIMESTAMP
>> from sqlalchemy.ext.declarative import declarative_base
>> from sqlalchemy.orm import sessionmaker, relation, backref
>>
>> engine = create_engine('sqlite:///:memory:', echo=False)
>> Base = declarative_base()
>> Session = sessionmaker(bind=engine)
>> session = Session()
>>
>> class PlatformORM(Base):
>> __tablename__ = 'platforms'
>>
>> platform_id = Column(Integer, primary_key=True)
>> platform_name = Column(String, unique=True)
>>
>> subfunds = relationship('FundORM', backref='platform')
>>
>> def __init__(self, platform_name):
>> self.platform_name = platform_name
>>
>> def __repr__(self):
>> return "<Platform(name = '%s')>" % self.platform_name
>>
>>
>> Next, comes the `FundORM` class, which is linked to the `PlatformORM`
>> class. Such that an instance of `PlatformORM` can have several subfunds.
>>
>> class FundORM(Base):
>> __tablename__ = 'funds'
>>
>> fund_id = Column(Integer, primary_key=True)
>> platform_id = Column(Integer, ForeignKey('platforms.platform_id'))
>> fund_name = Column(String, unique=True)
>>
>> ts_types = relationship('TimeseriesTypeORM', backref='fund')
>>
>> def __init__(self, fund_name):
>> self.fund_name = fund_name
>>
>> def __repr__(self):
>> return "<Fund name('%s'), Platform ID('%s')>" %
>> (self.fund_name, self.platform_id)
>>
>> Using only these two classes it's easy to link them. However, I now
>> wish to add another class called `TimeseriesTypeORM`, which is linked to
>> `FundORM` and describes the different types of timeseries that `FundORM`
>> has - it could for example be returns or spot price. This is defined such as
>>
>> class TimeseriesTypeORM(Base):
>> __tablename__ = 'timeseriestypes'
>>
>> platform_id = Column(Integer, ForeignKey('platforms.platform_id'))
>> fund_id = Column(Integer, ForeignKey('funds.fund_id'))
>> ts_type_id = Column(Integer, primary_key=True)
>> ts_type_name = Column(String)
>>
>> timeseries = relationship('TimeseriesORM', backref='ts_type')
>>
>> def __init__(self, ts_type_name=None):
>> self.ts_type_name = ts_type_name
>>
>> def __repr__(self):
>> return "<Type('%s'), Fund ID('%s'), Platform ID('%s')>" %
>> (self.ts_type_name, self.fund_id, self.platform_id)
>>
>> Furthermore, I'd like to create another class called `TimeseriesORM`,
>> which is linked to `TimeseriesTypeORM`, containing the actual data of the
>> timeseries. The class is defined as
>>
>> class TimeseriesORM(Base):
>> __tablename__ = 'timeseries'
>>
>> platform_id = Column(Integer, ForeignKey('platforms.platform_id'))
>> fund_id = Column(Integer, ForeignKey('funds.fund_id'))
>> ts_type_id = Column(Integer,
>> ForeignKey('timeseriestypes.ts_type_id'))
>> ts_id = Column(Integer, primary_key=True)
>>
>> date = Column(TIMESTAMP)
>> value = Column(Float)
>>
>> def __init__(self, date=None, value=None):
>> self.date = date
>> self.value = value
>>
>> def __repr__(self):
>> return "<Date('%s'), Fund ID('%s')>" % (self.date,
>> self.fund_id)
>>
>> As an example, assume that we have a platform called `ABC`, and that
>> `ABC` has a fund called `DBE`, where `DBE` in turn has data for spot prices
>> which is to be added. Creating the platform, fund and timeseries type then
>> yields
>>
>> platform = PlatformORM('ABC')
>> fund = FundORM('DBE')
>> platform.subfunds += [fund]
>>
>> ts_type = TimeseriesTypeORM('spot')
>> fund.ts_types += [ts_type]
>>
>> session.add_all([platform, fund, ts_type])
>> session.commit()
>>
>> I can run the above code just fine. However, if I try to view
>> `ts_type`, It'll show
>>
>> <Type('spot'), Fund ID('1'), Platform ID('None')>,
>>
>> where `Platform ID` should be 1. However, printing `ts_type.fund` will
>> show me the correct platform ID. I really can't figure out where I'm going
>> wrong - but a guess is somewhere in the relation for `FundORM`. Do you guys
>> have any ideas? It's kinda important to have the `platform_id` and
>> `fund_id` as keys in `TimeseriesORM`. Thanks! // Victor
>>
>> --
>> You received this message because you are subscribed to the Google Groups
>> "sqlalchemy" group.
>> To unsubscribe from this group and stop receiving emails from it, send an
>> email to [email protected].
>> To post to this group, send email to [email protected].
>> Visit this group at http://groups.google.com/group/sqlalchemy.
>> For more options, visit https://groups.google.com/d/optout.
>>
>>
>>
--
You received this message because you are subscribed to the Google Groups
"sqlalchemy" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
To post to this group, send email to [email protected].
Visit this group at http://groups.google.com/group/sqlalchemy.
For more options, visit https://groups.google.com/d/optout.