[sqlalchemy] Re: orm internal question - querying multiple classes

2019-02-28 Thread Jonathan Vanasco
thanks, Mike!

-- 
SQLAlchemy - 
The Python SQL Toolkit and Object Relational Mapper

http://www.sqlalchemy.org/

To post example code, please provide an MCVE: Minimal, Complete, and Verifiable 
Example.  See  http://stackoverflow.com/help/mcve for a full description.
--- 
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 sqlalchemy+unsubscr...@googlegroups.com.
To post to this group, send email to sqlalchemy@googlegroups.com.
Visit this group at https://groups.google.com/group/sqlalchemy.
For more options, visit https://groups.google.com/d/optout.


Re: [sqlalchemy] Polymorphic Query All regardless of subclass

2019-02-28 Thread Mike Bayer
On Thu, Feb 28, 2019 at 1:34 PM Andrew Martin  wrote:
>
> Hi All,
>
> Trying something out here for an analytics app here, and I'm not sure any of 
> this is a good idea. I'm trying to create a data model that's flexible enough 
> to handle a lot of different types of analysis. From plain CSVs to  time 
> series to survey questions with complex hierarchies. My approach is to have a 
> pretty plain model and query as needed to construct dataframes that will end 
> up in pandas and sci-kit learn.
>
> The basic idea is that there's a dataset that has variables associated with 
> it. Variables have values associated. I want to retain type information on 
> the values. If I'm reading a file and loading it, I want to store an int as 
> an int or a datetime as a datetime and not stuff everything into a string and 
> have to guess what things are based on variable metadata. That's where I'm 
> kind of stuck. I think I have the multi-table inheritance set up correctly to 
> store different types of value. I'm totally unsure how to query without 
> having to know the subclass. I'd like to be able to extract values for pandas 
> processing with something like this:
>
> vals = Values.value.filter_by(variable_id=123456).all()
>
> without having to know per variable which subclass to choose. I.e., I don't 
> want to have to do
> vals = IntValue.value.filter_by(variable_id=123456).all()
>

so "Values.value.filter_by(variable_id=123456).all()" is not
meaningful to me because I don't know what "Values.value" is, is that
a dynamic relationship hence you're getting a Query ?   What SQL do
you see this rendering?


>
> The second part of my question is only relevant if this whole design isn't 
> hosed, which I'm fine if you tell me that it is and I need to go back to the 
> drawing board.
>
> The second part is how to extract an entire dataset by ID in a way that would 
> be comfortable in pandas. If I were doing this in raw SQL, I'd use a CTE to 
> get the variables by dataset id and use a pivot to create the 
> data-frame-shaped table. I'm confounded by how to do this in alchemy, 
> especially with the polymorphic setup.

can you show me that ?


FTR we usually reduce the JOINs by putting all the "value" columns in
one table but otherwise similar approach, see:
https://docs.sqlalchemy.org/en/latest/_modules/examples/vertical/dictlike-polymorphic.html



>
>
> Here are my current model definitions:
>
>
> from sqlalchemy import Column, Index, Integer, Text, DateTime, Float, 
> ForeignKey
> from sqlalchemy.orm import relationship
>
> from .meta import Base
>
>
> class DataSet(Base):
> __tablename__ = 'datasets'
> id = Column(Integer, primary_key=True)
> name = Column(Text, nullable=False)
> description = Column(Text, nullable=True)
>
>
>
> class Variable(Base):
> __tablename__ = 'variables'
> id = Column(Integer, primary_key=True)
> dataset_id = Column(Integer, ForeignKey('datasets.id'), Nullable=False)
> name = Column(Text, nullable=False)
> description = Column(Text, nullable=True)
> group_var_col_id = Column(Integer, ForeignKey('variables.id'), 
> nullable=True)
> group_var_row_id = Column(Integer, ForeignKey('variables.id'), 
> nullable=True)
>
> value_map = Column(Text, nullable=True) #change to JSONB when move from 
> SQLite to Postgres
>
> dataset = relationship('DataSet', backref='variables')
>
>
> class Value(Base):
> __tablename__ = 'values'
> id = Column(Integer, primary_key=True)
> variable_id = Column(Integer, ForeignKey('variables.id'), Nullable=False)
> observation_id = Column(Text, nullable=False)
> value_type = Column(Text, nullable=False)
>
> variable = relationship('Variable', backref='values')
>
> __mapper_args__ = {'polymorphic_on': value_type}
>
>
> class IntValue(Value):
> __tablename__ = 'int_values'
> id = Column(None, ForeignKey('values.id'), primary_key=True)
> value = Column(Integer, nullable=True)
>
> __mapper_args__ = {'polymorphic_identity': 'int'}
>
>
> class StringValue(Value):
> __tablename__ = 'string_values'
> id = Column(None, ForeignKey('values.id'), primary_key=True)
> value = Column(Text, nullable=True)
>
> __mapper_args__ = {'polymorphic_identity': 'string'}
>
>
> class FloatValue(Value):
> __tablename__ = 'float_values'
> id = Column(None, ForeignKey('values.id'), primary_key=True)
> value = Column(Float, nullable=True)
>
> __mapper_args__ = {'polymorphic_identity': 'float'}
>
>
> class DateTimeValue(Value):
> __tablename__ = 'datetime_values'
> id = Column(None, ForeignKey('values.id'), primary_key=True)
> value = Column(DateTime, nullable=True)
>
> __mapper_args__ = {'polymorphic_identity': 'datetime'}
>
> Thanks in advance for any suggestions you might have!
>
> --
> SQLAlchemy -
> The Python SQL Toolkit and Object Relational Mapper
>
> http://www.sqlalchemy.org/
>
> To post example code, please provide an MCVE: Minimal, Complete, and 
> 

Re: [sqlalchemy] orm internal question - querying multiple classes

2019-02-28 Thread Mike Bayer
On Thu, Feb 28, 2019 at 1:32 PM Jonathan Vanasco  wrote:
>
> I couldn't find an answer to this in the docs.
>
> I'm auditing a handful of queries that are in a form similar to this...
>
> query = session.query(Foo, Bar).join(Bar, Foo.id == Bar.foo_id)
>
> I think SqlAlchemy is interpreting this as: select from the leftmost entity 
> from `query` (Foo), joining things to it for the rest of the construct, then 
> populate the rest of the objects in `query` based on their appearance in the 
> row from the join (Bar).  Is that about right?

sure, though you're giving it the ON clause directly so it doesn't
even have to do much, but yes it sees Bar and pulls that from the FROM
list to be the right side of the join.

>
> I'm getting the results I expect and the sql I want, I just want to confirm 
> that I'm using SqlAlchemy correctly.  I want to make sure that I am not 
> invoking things incorrectly, yet getting the right results. that's happened 
> before!
>
>
>
>
>
> --
> SQLAlchemy -
> The Python SQL Toolkit and Object Relational Mapper
>
> http://www.sqlalchemy.org/
>
> To post example code, please provide an MCVE: Minimal, Complete, and 
> Verifiable Example. See http://stackoverflow.com/help/mcve for a full 
> description.
> ---
> 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 sqlalchemy+unsubscr...@googlegroups.com.
> To post to this group, send email to sqlalchemy@googlegroups.com.
> Visit this group at https://groups.google.com/group/sqlalchemy.
> For more options, visit https://groups.google.com/d/optout.

-- 
SQLAlchemy - 
The Python SQL Toolkit and Object Relational Mapper

http://www.sqlalchemy.org/

To post example code, please provide an MCVE: Minimal, Complete, and Verifiable 
Example.  See  http://stackoverflow.com/help/mcve for a full description.
--- 
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 sqlalchemy+unsubscr...@googlegroups.com.
To post to this group, send email to sqlalchemy@googlegroups.com.
Visit this group at https://groups.google.com/group/sqlalchemy.
For more options, visit https://groups.google.com/d/optout.


[sqlalchemy] Polymorphic Query All regardless of subclass

2019-02-28 Thread Andrew Martin
Hi All,

Trying something out here for an analytics app here, and I'm not sure any 
of this is a good idea. I'm trying to create a data model that's flexible 
enough to handle a lot of different types of analysis. From plain CSVs to  
time series to survey questions with complex hierarchies. My approach is to 
have a pretty plain model and query as needed to construct dataframes that 
will end up in pandas and sci-kit learn.

The basic idea is that there's a dataset that has variables associated with 
it. Variables have values associated. I want to retain type information on 
the values. If I'm reading a file and loading it, I want to store an int as 
an int or a datetime as a datetime and not stuff everything into a string 
and have to guess what things are based on variable metadata. That's where 
I'm kind of stuck. I think I have the multi-table inheritance set up 
correctly to store different types of value. I'm totally unsure how to 
query without having to know the subclass. I'd like to be able to extract 
values for pandas processing with something like this:

vals = Values.value.filter_by(variable_id=123456).all()

without having to know per variable which subclass to choose. I.e., I don't 
want to have to do
vals = IntValue.value.filter_by(variable_id=123456).all()


The second part of my question is only relevant if this whole design isn't 
hosed, which I'm fine if you tell me that it is and I need to go back to 
the drawing board.

The second part is how to extract an entire dataset by ID in a way that 
would be comfortable in pandas. If I were doing this in raw SQL, I'd use a 
CTE to get the variables by dataset id and use a pivot to create the 
data-frame-shaped table. I'm confounded by how to do this in alchemy, 
especially with the polymorphic setup.


Here are my current model definitions:


from sqlalchemy import Column, Index, Integer, Text, DateTime, Float, 
ForeignKey
from sqlalchemy.orm import relationship

from .meta import Base


class DataSet(Base):
__tablename__ = 'datasets'
id = Column(Integer, primary_key=True)
name = Column(Text, nullable=False)
description = Column(Text, nullable=True)



class Variable(Base):
__tablename__ = 'variables'
id = Column(Integer, primary_key=True)
dataset_id = Column(Integer, ForeignKey('datasets.id'), Nullable=False)
name = Column(Text, nullable=False)
description = Column(Text, nullable=True)
group_var_col_id = Column(Integer, ForeignKey('variables.id'), nullable=
True)
group_var_row_id = Column(Integer, ForeignKey('variables.id'), nullable=
True)

value_map = Column(Text, nullable=True) #change to JSONB when move from 
SQLite to Postgres

dataset = relationship('DataSet', backref='variables')


class Value(Base):
__tablename__ = 'values'
id = Column(Integer, primary_key=True)
variable_id = Column(Integer, ForeignKey('variables.id'), Nullable=False
)
observation_id = Column(Text, nullable=False)
value_type = Column(Text, nullable=False)

variable = relationship('Variable', backref='values')

__mapper_args__ = {'polymorphic_on': value_type}


class IntValue(Value):
__tablename__ = 'int_values'
id = Column(None, ForeignKey('values.id'), primary_key=True)
value = Column(Integer, nullable=True)

__mapper_args__ = {'polymorphic_identity': 'int'}


class StringValue(Value):
__tablename__ = 'string_values'
id = Column(None, ForeignKey('values.id'), primary_key=True)
value = Column(Text, nullable=True)

__mapper_args__ = {'polymorphic_identity': 'string'}


class FloatValue(Value):
__tablename__ = 'float_values'
id = Column(None, ForeignKey('values.id'), primary_key=True)
value = Column(Float, nullable=True)

__mapper_args__ = {'polymorphic_identity': 'float'}


class DateTimeValue(Value):
__tablename__ = 'datetime_values'
id = Column(None, ForeignKey('values.id'), primary_key=True)
value = Column(DateTime, nullable=True)

__mapper_args__ = {'polymorphic_identity': 'datetime'}

Thanks in advance for any suggestions you might have!

-- 
SQLAlchemy - 
The Python SQL Toolkit and Object Relational Mapper

http://www.sqlalchemy.org/

To post example code, please provide an MCVE: Minimal, Complete, and Verifiable 
Example.  See  http://stackoverflow.com/help/mcve for a full description.
--- 
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 sqlalchemy+unsubscr...@googlegroups.com.
To post to this group, send email to sqlalchemy@googlegroups.com.
Visit this group at https://groups.google.com/group/sqlalchemy.
For more options, visit https://groups.google.com/d/optout.


[sqlalchemy] orm internal question - querying multiple classes

2019-02-28 Thread Jonathan Vanasco
I couldn't find an answer to this in the docs. 

I'm auditing a handful of queries that are in a form similar to this...

query = session.query(Foo, Bar).join(Bar, Foo.id == Bar.foo_id)
  
I think SqlAlchemy is interpreting this as: select from the leftmost entity 
from `query` (Foo), joining things to it for the rest of the construct, 
then populate the rest of the objects in `query` based on their appearance 
in the row from the join (Bar).  Is that about right?

I'm getting the results I expect and the sql I want, I just want to confirm 
that I'm using SqlAlchemy correctly.  I want to make sure that I am not 
invoking things incorrectly, yet getting the right results. that's happened 
before!
   




-- 
SQLAlchemy - 
The Python SQL Toolkit and Object Relational Mapper

http://www.sqlalchemy.org/

To post example code, please provide an MCVE: Minimal, Complete, and Verifiable 
Example.  See  http://stackoverflow.com/help/mcve for a full description.
--- 
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 sqlalchemy+unsubscr...@googlegroups.com.
To post to this group, send email to sqlalchemy@googlegroups.com.
Visit this group at https://groups.google.com/group/sqlalchemy.
For more options, visit https://groups.google.com/d/optout.


Re: [sqlalchemy] Using primary_join with back_populates

2019-02-28 Thread Mike Bayer
On Wed, Feb 27, 2019 at 11:38 PM Pavel Pristupa  wrote:
>
> Yes, just a typo.
> The actual problem is the following:
>
> When I try to add back_populates('user') to User.billing_addresses and 
> User.shipping_addresses relationships, I get the error:
> User.billing_addresses and back-reference Address.user are both of the same 
> direction .  Did you mean to set remote_side on the 
> many-to-one side?


once I correct for the syntactical issues I can't reproduce this
error. Please provide a proper MCVE, thanks!   see below

import sqlalchemy as sa
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import relationship, configure_mappers, Session

Base = declarative_base()


class User(Base):
__tablename__ = 'user'
id = sa.Column(sa.Integer, primary_key=True)
billing_addresses = relationship(
"Address",
primaryjoin="and_(User.id==Address.user_id,
Address.is_billing.is_(True))",
back_populates="user",
uselist=True,
)
shipping_addresses = relationship(
"Address",
primaryjoin="and_(User.id==Address.user_id,
Address.is_billing.is_(False))",
back_populates="user",
uselist=True,
)


class Address(Base):
__tablename__ = 'address'
id = sa.Column(sa.Integer, primary_key=True)
is_billing = sa.Column(
sa.Boolean
)  # Let it be a discriminator for whether it's a billing or shipping
user_id = sa.Column(sa.Integer, sa.ForeignKey("user.id"), nullable=False)
user = relationship(User)

configure_mappers()

e = sa.create_engine("sqlite://", echo=True)
Base.metadata.create_all(e)

s = Session(e)

a1, a2 = Address(), Address()
u1 = User(billing_addresses=[a1], shipping_addresses=[a2])

assert a1.user is u1
assert a2.user is u1

s.add(u1)
s.commit()

output

$ python test.py
2019-02-28 08:19:19,174 INFO sqlalchemy.engine.base.Engine SELECT
CAST('test plain returns' AS VARCHAR(60)) AS anon_1
2019-02-28 08:19:19,174 INFO sqlalchemy.engine.base.Engine ()
2019-02-28 08:19:19,175 INFO sqlalchemy.engine.base.Engine SELECT
CAST('test unicode returns' AS VARCHAR(60)) AS anon_1
2019-02-28 08:19:19,175 INFO sqlalchemy.engine.base.Engine ()
2019-02-28 08:19:19,176 INFO sqlalchemy.engine.base.Engine PRAGMA
table_info("user")
2019-02-28 08:19:19,176 INFO sqlalchemy.engine.base.Engine ()
2019-02-28 08:19:19,176 INFO sqlalchemy.engine.base.Engine PRAGMA
table_info("address")
2019-02-28 08:19:19,177 INFO sqlalchemy.engine.base.Engine ()
2019-02-28 08:19:19,177 INFO sqlalchemy.engine.base.Engine
CREATE TABLE user (
id INTEGER NOT NULL,
PRIMARY KEY (id)
)


2019-02-28 08:19:19,177 INFO sqlalchemy.engine.base.Engine ()
2019-02-28 08:19:19,178 INFO sqlalchemy.engine.base.Engine COMMIT
2019-02-28 08:19:19,178 INFO sqlalchemy.engine.base.Engine
CREATE TABLE address (
id INTEGER NOT NULL,
is_billing BOOLEAN,
user_id INTEGER NOT NULL,
PRIMARY KEY (id),
CHECK (is_billing IN (0, 1)),
FOREIGN KEY(user_id) REFERENCES user (id)
)


2019-02-28 08:19:19,179 INFO sqlalchemy.engine.base.Engine ()
2019-02-28 08:19:19,179 INFO sqlalchemy.engine.base.Engine COMMIT
2019-02-28 08:19:19,180 INFO sqlalchemy.engine.base.Engine BEGIN (implicit)
2019-02-28 08:19:19,181 INFO sqlalchemy.engine.base.Engine INSERT INTO
user DEFAULT VALUES
2019-02-28 08:19:19,181 INFO sqlalchemy.engine.base.Engine ()
2019-02-28 08:19:19,182 INFO sqlalchemy.engine.base.Engine INSERT INTO
address (is_billing, user_id) VALUES (?, ?)
2019-02-28 08:19:19,182 INFO sqlalchemy.engine.base.Engine (None, 1)
2019-02-28 08:19:19,182 INFO sqlalchemy.engine.base.Engine INSERT INTO
address (is_billing, user_id) VALUES (?, ?)
2019-02-28 08:19:19,183 INFO sqlalchemy.engine.base.Engine (None, 1)
2019-02-28 08:19:19,183 INFO sqlalchemy.engine.base.Engine COMMIT




>
> среда, 27 февраля 2019 г., 1:03:40 UTC+7 пользователь Mike Bayer написал:
>>
>> you are missing and_():
>>
>> billing_addresses = relationship('Address',
>> primary_join='and_(User.id==Address.id,
>> Address.is_billing.is_(True))', uselist=True)
>>
>>
>> On Tue, Feb 26, 2019 at 5:44 AM Pavel Pristupa  wrote:
>> >
>> > Hi everybody!
>> >
>> > Is there a way to use primary_join with back_populates in the following 
>> > case?
>> >
>> > I have two entities (sorry, I may be wrong with the exact syntax):
>> >
>> >
>> > class User(Base):
>> >   id = sa.Column(sa.Integer, primary_key=True)
>> >   billing_addresses = relationship('Address', 
>> > primary_join='User.id==Address.id, Address.is_billing.is_(True)', 
>> > uselist=True)
>> >   shipping_addresses = relationship('Address', 
>> > primary_join='User.id==Address.id, Address.is_billing.is_(False)', 
>> > uselist=True)
>> >
>> >
>> > class Address(Base):
>> >   id = sa.Column(sa.Integer, primary_key=True)
>> >   is_billing = sa.Column(sa.Boolean)  # Let it be a discriminator for 
>> > whether it's a billing or shipping
>> >   user_id = sa.Column(sa.Integer, sa.ForeignKey('User.id'), nullable=False)
>> >   user =