Re: [sqlalchemy] stucco_evolution 0.4 released

2012-04-20 Thread Michael Bayer

On Apr 20, 2012, at 6:52 PM, Jeff Dairiki wrote:

> On Fri, Apr 20, 2012 at 03:44:55PM -0400, Michael Bayer wrote:
>> 
>> The one thing that's needed as far as Alembic is concerned is the
>> ability to control the name of the actual "migration" table per
>> environment, this is a short feature add that's been sitting as an
>> enhancement request for some time now.
> 
> Since you mention it, I posted patches to
> 
>  
> https://bitbucket.org/zzzeek/alembic/issue/34/make-version-table-name-configurable
> 
> awhile ago and was awaiting feedback on them (until I forgot about them.)
> The patches in addition to supporting a configurable version table name
> also support two-column version tables which can be shared between Alembic
> environments.
> 
> (If you want to veto the two-column version table idea, I can whittle
> it down to just the configurable-version-table-name part pretty easily.)

I really have to get used to bitbucket and the need to press the "follow" 
button on these issues, since I was totally unaware of this !

looking now (and checking other issues for missed activity)




> 
> Cheers,
> Jeff
> 
> -- 
> You received this message because you are subscribed to the Google Groups 
> "sqlalchemy" group.
> To post to this group, send email to sqlalchemy@googlegroups.com.
> To unsubscribe from this group, send email to 
> sqlalchemy+unsubscr...@googlegroups.com.
> For more options, visit this group at 
> http://groups.google.com/group/sqlalchemy?hl=en.
> 

-- 
You received this message because you are subscribed to the Google Groups 
"sqlalchemy" group.
To post to this group, send email to sqlalchemy@googlegroups.com.
To unsubscribe from this group, send email to 
sqlalchemy+unsubscr...@googlegroups.com.
For more options, visit this group at 
http://groups.google.com/group/sqlalchemy?hl=en.



Re: [sqlalchemy] stucco_evolution 0.4 released

2012-04-20 Thread Jeff Dairiki
On Fri, Apr 20, 2012 at 03:44:55PM -0400, Michael Bayer wrote:
> 
> The one thing that's needed as far as Alembic is concerned is the
> ability to control the name of the actual "migration" table per
> environment, this is a short feature add that's been sitting as an
> enhancement request for some time now.

Since you mention it, I posted patches to

  
https://bitbucket.org/zzzeek/alembic/issue/34/make-version-table-name-configurable

awhile ago and was awaiting feedback on them (until I forgot about them.)
The patches in addition to supporting a configurable version table name
also support two-column version tables which can be shared between Alembic
environments.

(If you want to veto the two-column version table idea, I can whittle
it down to just the configurable-version-table-name part pretty easily.)

Cheers,
Jeff

-- 
You received this message because you are subscribed to the Google Groups 
"sqlalchemy" group.
To post to this group, send email to sqlalchemy@googlegroups.com.
To unsubscribe from this group, send email to 
sqlalchemy+unsubscr...@googlegroups.com.
For more options, visit this group at 
http://groups.google.com/group/sqlalchemy?hl=en.



Re: [sqlalchemy] Re: associationproxy for one-to-many

2012-04-20 Thread Eric Lemoine
On Fri, Apr 20, 2012 at 9:28 PM, Michael Bayer  wrote:
>
> On Apr 20, 2012, at 8:45 AM, Eric Lemoine wrote:
>
>> On Mon, Apr 16, 2012 at 10:49 PM, Eric Lemoine
>>  wrote:
>>> Hi
>>>
>>> I'd like to use an associationproxy for a simple many-to-one relationship:
>>>
>>> class Child(Base):
>>>     __tablename__ = 'child'
>>>     id = Column(Integer, primary_key=True)
>>>     name = Column(Unicode)
>>>
>>> class Parent(Base):
>>>     __tablename__ = 'parent'
>>>     id = Column(Integer, primary_key=True)
>>>     child_id = Column(Integer, ForeignKey('child.id')
>>>     child_ = relationship(Child)
>>>     child = association_proxy('child_', 'name', creator=)
>>>
>>> Now 'child' is a read-only, dictionary-like table. I never want to insert
>>> new rows in this table.
>>>
>>> So I actually pass the following "creator" to the association_proxy
>>> constructor:
>>>
>>> def creator(name):
>>>     return Session.query(Child).filter_by(name=name).first()
>
>>>
>>> That does the job for "create". But I cannot find a solution for "update".
>>> On update I'd like to replace the current Child object in the Parent object
>>> by a new Child object read from the 'child' table.
>>>
>>> Using a specific setter (in a getset_factory) does not work for me, as the
>>> setter receives the Child object (and the value), not the Parent object –
>>> I'd need a ref to the Parent object to be able to change its Child object in
>>> child_.
>>>
>>> Maybe I'm doing it all wrong and using an associationproxy is not the way to
>>> go for that case.
>
> the associationproxy is good for collections but in this case I'm not sure 
> what you're getting versus a regular @property or @hybrid_property.

Yeah I was wondering too. And I actually did not know about the
existence of hybrid_property.

>
> I will note that I think I do a use case a little bit similar to this, where 
> Parent.children is a dictionary keyed on name.  But instead of sticking 
> Session.query() into creator, I use a recipe similar to the unique object 
> recipe: http://www.sqlalchemy.org/trac/wiki/UsageRecipes/UniqueObject .

This is also very good to know (and study).


>
> If the associationproxy is doing it's job, modifying "Parent.child", as a 
> string, should be updating Parent._child.name with the new value.     If you 
> wanted to replace that with "just swap this other Child in", you could do 
> that in a before_flush() event, not unlike the insert versions recipe: 
> http://www.sqlalchemy.org/trac/wiki/UsageRecipes/VersionedRows
>
> but just sticking with @property or hybrid might be more straightforward 
> here, if it works.

Yeah.


Thanks a lot Mike! This gives me interesting paths to research.



-- 
Eric Lemoine

Camptocamp France SAS
Savoie Technolac, BP 352
73377 Le Bourget du Lac, Cedex

Tel : 00 33 4 79 44 44 96
Mail : eric.lemo...@camptocamp.com
http://www.camptocamp.com

-- 
You received this message because you are subscribed to the Google Groups 
"sqlalchemy" group.
To post to this group, send email to sqlalchemy@googlegroups.com.
To unsubscribe from this group, send email to 
sqlalchemy+unsubscr...@googlegroups.com.
For more options, visit this group at 
http://groups.google.com/group/sqlalchemy?hl=en.



Re: [sqlalchemy] stucco_evolution 0.4 released

2012-04-20 Thread Michael Bayer

On Apr 20, 2012, at 4:52 AM, Wichert Akkerman wrote:

> 
> That suggests that every package would have its own migration tool, which is 
> not very practical from a sysadmin point of view. I am an upgrading an 
> application I want to be able to run all necessary migrations for all 
> components of an application in one run. I do not want to be required to 
> figure out which packages an application was running and then migrate them 
> all separately. So I definitely see a need for an upgrade framework that can 
> deal with multiple packages.

in my view every package which deals with it's own schema objects would at 
least have to maintain it's own migration files - not it's own migration 
"tool", but assuming an Alembic setup, each would have at least a rudimentary 
Alembic environment and individual migration files.You could then run each 
migration environment individually, or write a short coordination script within 
the main application that calls upon all of them.  Assuming the packages either 
have no schema dependencies on each other, or dependencies without cycles, the 
correct "order" of which set of scripts to be run could just be hardcoded 
within the main application.   i think when one writes an application M that 
makes use of libraries A, B, and C, it's not unreasonable that M would have to 
include some top-level configuration for A, B, and C, that is, adding each one 
to a list of packages in which to locate an alembic environment and run 
upgrades.   Or there would be some other usage contract between A, B, C and M 
that allows for publishing of "migration" handles.

What I don't see is that application M has within it migration scripts specific 
to A, B and C.   A, B and C should maintain the knowledge of their own schemas 
and how they need to be upgraded for new versions of A, B and C I would think.

The one thing that's needed as far as Alembic is concerned is the ability to 
control the name of the actual "migration" table per environment, this is a 
short feature add that's been sitting as an enhancement request for some time 
now.


-- 
You received this message because you are subscribed to the Google Groups 
"sqlalchemy" group.
To post to this group, send email to sqlalchemy@googlegroups.com.
To unsubscribe from this group, send email to 
sqlalchemy+unsubscr...@googlegroups.com.
For more options, visit this group at 
http://groups.google.com/group/sqlalchemy?hl=en.



Re: [sqlalchemy] join + joined inheritance

2012-04-20 Thread Michael Bayer

On Apr 20, 2012, at 9:32 AM, Julien Cigar wrote:

> Hello,
> 
> I'm using joined load inheritance in one of my project, and I have the 
> following query:
> 
> q = Content.query.outerjoin((File, File.content_id == Content.id), File.mime, 
> Mime.major)
> 
> SQLAlchemy generates a subquery for the outer join.
> Any idea how to ask SQLAlchemy to generate a shorter FROM clause (no 
> subquery) ?
> 
> This is what I get:
> 
> FROM content LEFT OUTER JOIN (SELECT content.id AS content_id, content.added 
> AS content_added, content.updated AS content_updated, content.title AS 
> content_title, content.description AS content_description, content.effective 
> AS content_effective, content.expiration AS content_expiration, 
> content.exclude_nav AS content_exclude_nav, content.weight AS content_weight, 
> content.customized AS content_customized, content.content_type_id AS 
> content_content_type_id, content.icon_content_id AS content_icon_content_id, 
> content.container_id AS content_container_id, content.owner_id AS 
> content_owner_id, content.polymorphic_loading AS content_polymorphic_loading, 
> content.state_id AS content_state_id, data.content_id AS data_content_id, 
> data.mime_id AS data_mime_id, data.original_name AS data_original_name, 
> data.file_size AS data_file_size
>FROM content JOIN data ON content.id = data.content_id) AS anon_1 ON 
> anon_1.data_content_id = content.id LEFT OUTER JOIN mime ON mime.id = 
> anon_1.data_mime_id LEFT OUTER JOIN mime_major ON mime_major.id = 
> mime.major_id
> 
> This is what I want:
> 
> FROM content LEFT OUTER JOIN data ON content.id = data.content_id LEFT OUTER 
> JOIN mime ON mime.id = anon_1.data_mime_id LEFT OUTER JOIN mime_major ON 
> mime_major.id = mime.major_id
> 
> My mappers looks like:
> 
> orm.mapper(Content, table['content'],
>  polymorphic_on = table['content'].c.content_type_id,
>  ...)
> 
> orm.mapper(File, table['data'], inherits = Content,
>  polymorphic_identity = _get_type_id('file'),
>  ...)

right this is the behavior of when you join to a joined inh structure.   It 
represents essentially "A JOIN B", and not every database backend can 
seamlessly handle the idea of "C JOIN (A JOIN B)", though most can these days 
except for SQLite.  There's some other nasty scoping problems on the SQLA 
expression side which come into play, however, and changing the mechanics of 
query.join()/outerjoin() to try to "optimize" this is not something likely to 
ever happen, as far as I can see (I've looked into seeing how it could be done).

In particular here, File is already a composite of Content, so joining from 
Content-> File is pretty awkward.

in this particular case, you can probably get what you want just by loading 
Content with the "with_polymorphic" option that will outer join to the related 
"file" table:

query(Content).with_polymorphic([File]).outerjoin(File.mime, Mime.major)

Otherwise, if you want to create a join among the components of a joined 
inheritance structure while maintaining explicit control over those components, 
you use the Table objects directly, that is File.__table__, and such.  There's 
a detailed description of this at 
http://docs.sqlalchemy.org/en/latest/orm/inheritance.html#basic-control-of-which-tables-are-queried
 and 
http://docs.sqlalchemy.org/en/latest/orm/inheritance.html#advanced-control-of-which-tables-are-queried
 .

-- 
You received this message because you are subscribed to the Google Groups 
"sqlalchemy" group.
To post to this group, send email to sqlalchemy@googlegroups.com.
To unsubscribe from this group, send email to 
sqlalchemy+unsubscr...@googlegroups.com.
For more options, visit this group at 
http://groups.google.com/group/sqlalchemy?hl=en.



Re: [sqlalchemy] Re: automating inheritance

2012-04-20 Thread Michael Bayer

On Apr 20, 2012, at 8:51 AM, lars van gemerden wrote:

> Ok, thank you, that helps, but now i cannot inherit from Engineer, as in:
> 
> class BaseMixin(object):
> 
> discriminator = Column(String(50))
> 
> @declared_attr
> def __tablename__(cls):
> return cls.__name__
> @declared_attr
> def id(cls):
> return Column(Integer, primary_key = True)
> @declared_attr
> def __mapper_args__(cls):
> if not has_inherited_table(cls):
> return {'polymorphic_on': 'discriminator'}
> else:
> return {'polymorphic_identity': cls.__name__}
> 
> 
> class InheritMixin(BaseMixin):
> @declared_attr
> def id(cls):
> super_id = super(InheritMixin, cls).id
> return Column(Integer, ForeignKey(super_id), primary_key = True)
> 
> class Person(BaseMixin, Base):
> name = Column(String(50))
>
> class Engineer(InheritMixin, Person):
> job = Column(String(50))
> 
> class MasterEngineer(InheritMixin, Engineer):
> specialty = Column(String(50))
> 
> Gives an MRO() error and if i would reverse the baseclasses (like class 
> Engineer(Person, InheritMixin):  ... ), the inheriting classes pick up the 
> wrong id.
> 
> Do you see any solution for this? 

yeah I suppose if you're building out joined inheritance more than one level 
then this becomes awkward.   I never use joined inh more than one level because 
it has too much of an impact on queries.

the metaclass as you mention is always the last resort when the various 
declarative trickery reaches its limit.   I'm not thrilled about the metaclass 
approach because it quickly gets confusing and shouldn't be necessary.   though 
in this case without some extra mechanism on declarative, such as a 
__pre_declare__() method of some kind, it might be the only approach.

-- 
You received this message because you are subscribed to the Google Groups 
"sqlalchemy" group.
To post to this group, send email to sqlalchemy@googlegroups.com.
To unsubscribe from this group, send email to 
sqlalchemy+unsubscr...@googlegroups.com.
For more options, visit this group at 
http://groups.google.com/group/sqlalchemy?hl=en.



Re: [sqlalchemy] Re: associationproxy for one-to-many

2012-04-20 Thread Michael Bayer

On Apr 20, 2012, at 8:45 AM, Eric Lemoine wrote:

> On Mon, Apr 16, 2012 at 10:49 PM, Eric Lemoine
>  wrote:
>> Hi
>> 
>> I'd like to use an associationproxy for a simple many-to-one relationship:
>> 
>> class Child(Base):
>> __tablename__ = 'child'
>> id = Column(Integer, primary_key=True)
>> name = Column(Unicode)
>> 
>> class Parent(Base):
>> __tablename__ = 'parent'
>> id = Column(Integer, primary_key=True)
>> child_id = Column(Integer, ForeignKey('child.id')
>> child_ = relationship(Child)
>> child = association_proxy('child_', 'name', creator=)
>> 
>> Now 'child' is a read-only, dictionary-like table. I never want to insert
>> new rows in this table.
>> 
>> So I actually pass the following "creator" to the association_proxy
>> constructor:
>> 
>> def creator(name):
>> return Session.query(Child).filter_by(name=name).first()

>> 
>> That does the job for "create". But I cannot find a solution for "update".
>> On update I'd like to replace the current Child object in the Parent object
>> by a new Child object read from the 'child' table.
>> 
>> Using a specific setter (in a getset_factory) does not work for me, as the
>> setter receives the Child object (and the value), not the Parent object –
>> I'd need a ref to the Parent object to be able to change its Child object in
>> child_.
>> 
>> Maybe I'm doing it all wrong and using an associationproxy is not the way to
>> go for that case.

the associationproxy is good for collections but in this case I'm not sure what 
you're getting versus a regular @property or @hybrid_property.   

I will note that I think I do a use case a little bit similar to this, where 
Parent.children is a dictionary keyed on name.  But instead of sticking 
Session.query() into creator, I use a recipe similar to the unique object 
recipe: http://www.sqlalchemy.org/trac/wiki/UsageRecipes/UniqueObject .

If the associationproxy is doing it's job, modifying "Parent.child", as a 
string, should be updating Parent._child.name with the new value. If you 
wanted to replace that with "just swap this other Child in", you could do that 
in a before_flush() event, not unlike the insert versions recipe: 
http://www.sqlalchemy.org/trac/wiki/UsageRecipes/VersionedRows

but just sticking with @property or hybrid might be more straightforward here, 
if it works.

-- 
You received this message because you are subscribed to the Google Groups 
"sqlalchemy" group.
To post to this group, send email to sqlalchemy@googlegroups.com.
To unsubscribe from this group, send email to 
sqlalchemy+unsubscr...@googlegroups.com.
For more options, visit this group at 
http://groups.google.com/group/sqlalchemy?hl=en.



multi-package schemas (was Re: [sqlalchemy] stucco_evolution 0.4 released)

2012-04-20 Thread Chris Withers

On 19/04/2012 18:43, Michael Bayer wrote:

but with the possibility of dependencies between those tables. If I
understand correctly, if we were dealing with sets of tables that didn't
have any dependency, you wouldn't need a distributed migration tool,
each package would handle migrations for its own set of tables
independently, is that right ?


This is what I came up with for mortar_rdb: each package defined a 
"source" of tables and each application collected the sources it was 
using into a "config". Each "source" has its own schema. I haven't hit a 
situation where I needed the topological sort yet, I suspect if I did 
I'd just punt and make the owner of the config (ie: the application) 
specify the upgrade order manually...



I think what I need to see here are, what exactly are these packages,


Authentication, authorization and "membership" are the obvious ones; all 
three have several interchangeable solutions and I can certainly 
conceive packages for each interoperating with a few select foreign 
keys, username being the most obvious...


Admittedly, I haven't hit this in the "real world" yet.

I'm very keen to move mortar_rdb onto Alebic, and will be doing so as 
soon as I hit the need in the real world...


Chris

--
Simplistix - Content Management, Batch Processing & Python Consulting
- http://www.simplistix.co.uk

--
You received this message because you are subscribed to the Google Groups 
"sqlalchemy" group.
To post to this group, send email to sqlalchemy@googlegroups.com.
To unsubscribe from this group, send email to 
sqlalchemy+unsubscr...@googlegroups.com.
For more options, visit this group at 
http://groups.google.com/group/sqlalchemy?hl=en.



[sqlalchemy] join + joined inheritance

2012-04-20 Thread Julien Cigar

Hello,

I'm using joined load inheritance in one of my project, and I have the 
following query:


q = Content.query.outerjoin((File, File.content_id == Content.id), 
File.mime, Mime.major)


SQLAlchemy generates a subquery for the outer join.
Any idea how to ask SQLAlchemy to generate a shorter FROM clause (no 
subquery) ?


This is what I get:

 FROM content LEFT OUTER JOIN (SELECT content.id AS content_id, 
content.added AS content_added, content.updated AS content_updated, 
content.title AS content_title, content.description AS 
content_description, content.effective AS content_effective, 
content.expiration AS content_expiration, content.exclude_nav AS 
content_exclude_nav, content.weight AS content_weight, 
content.customized AS content_customized, content.content_type_id AS 
content_content_type_id, content.icon_content_id AS 
content_icon_content_id, content.container_id AS content_container_id, 
content.owner_id AS content_owner_id, content.polymorphic_loading AS 
content_polymorphic_loading, content.state_id AS content_state_id, 
data.content_id AS data_content_id, data.mime_id AS data_mime_id, 
data.original_name AS data_original_name, data.file_size AS data_file_size
FROM content JOIN data ON content.id = data.content_id) AS 
anon_1 ON anon_1.data_content_id = content.id LEFT OUTER JOIN mime ON 
mime.id = anon_1.data_mime_id LEFT OUTER JOIN mime_major ON 
mime_major.id = mime.major_id


This is what I want:

 FROM content LEFT OUTER JOIN data ON content.id = data.content_id LEFT 
OUTER JOIN mime ON mime.id = anon_1.data_mime_id LEFT OUTER JOIN 
mime_major ON mime_major.id = mime.major_id


My mappers looks like:

orm.mapper(Content, table['content'],
  polymorphic_on = table['content'].c.content_type_id,
  ...)

orm.mapper(File, table['data'], inherits = Content,
  polymorphic_identity = _get_type_id('file'),
  ...)

Thanks!,
Julien

--
No trees were killed in the creation of this message.
However, many electrons were terribly inconvenienced.

--
You received this message because you are subscribed to the Google Groups 
"sqlalchemy" group.
To post to this group, send email to sqlalchemy@googlegroups.com.
To unsubscribe from this group, send email to 
sqlalchemy+unsubscr...@googlegroups.com.
For more options, visit this group at 
http://groups.google.com/group/sqlalchemy?hl=en.

<>

Re: [sqlalchemy] Re: automating inheritance

2012-04-20 Thread lars van gemerden
Hi Mike,

How about this approach with a custom metaclass; so far it works and seems 
the cleanest to me:

from sqlalchemy import *
from sqlalchemy.orm.session import sessionmaker
from sqlalchemy.ext.declarative import declarative_base, 
has_inherited_table, DeclarativeMeta

engine = create_engine('sqlite:///:memory:', echo=False)

class InheritMeta(DeclarativeMeta):

def __init__(cls, name, bases, clsdict):
cls.__tablename__ = cls.__name__
if not has_inherited_table(cls):
cls.id = Column(Integer, primary_key = True)
cls.discriminator = Column(String(50))
cls.__mapper_args__ = {'polymorphic_on': 'discriminator'}
else:
cls.id = Column(Integer, ForeignKey(bases[0].id), primary_key = 
True)
cls.__mapper_args__ = {'polymorphic_identity': cls.__name__}
super(InheritMeta, cls).__init__(name, bases, clsdict)

InheritableBase = declarative_base(bind = engine, metaclass = InheritMeta)

class Person(InheritableBase):
name = Column(String(50))
   
class Engineer(Person):
job = Column(String(50))

class MasterEngineer(Engineer):
specialty = Column(String(50))


if __name__ == '__main__':
InheritableBase.metadata.create_all(engine)
session = sessionmaker(bind=engine)()

a = Person(name = 'ann')
b = Engineer(name = 'bob', job = 'car repair')
c = MasterEngineer(name = 'carl', job = 'car repair', specialty = 
'tires')
session.add_all([a, b, c])
session.commit()
people = session.query(Person).all()
print people

Do you see any drawbacks, gotchas for later on?

Regards, Lars

On Friday, April 20, 2012 12:41:28 PM UTC+2, Michael Bayer wrote:
>
>
> On Apr 20, 2012, at 4:59 AM, lars van gemerden wrote:
>
> > this is the testcase:
> > 
> > 
> > What am i missing?
>
>
> the issue here is one of Python inheritance mechanics.   Declarative calls 
> upon @declared_attr in terms of the class, that is, we look through the 
> class to find each @declared_attr, but when we find one, we invoke it by 
> just calling it as a method, that is, getattr(cls, name).   This works for 
> things like __mapper_args__ which remain as callable methods on classes 
> like Person, Engineer.   But "id", when that is declared on Person is 
> immediately replaced with a mapping.   By the time you get to Engineer, the 
> id() method is gone.
>
> So for inheriting cases you need to build a mixin that is applied to every 
> subclass.  This makes sense because a mixin with a column on it implies 
> that the column is being associated only with that immediate class - if you 
> wanted a subclass to act as single table inheritance, you'd omit this 
> class.  In this case you want the same column on all subclasses.So you 
> can do it like this (note also using declarative.has_inherited_table 
> helper):
>
> class InheritMixin(object):
>
>@declared_attr
>def __tablename__(cls):
>return cls.__name__
>
>@declared_attr
>def id(cls):
>return Column(Integer, primary_key = True)
>
>@declared_attr
>def __mapper_args__(cls):
>if not has_inherited_table(cls):
>return {'polymorphic_on': 'discriminator'}
>else:
>return {'polymorphic_identity': cls.__name__}
>
> class Inherits(InheritMixin):
> @declared_attr
> def id(cls):
> super_id = super(Inherits, cls).id
> return Column(Integer, ForeignKey(super_id),primary_key = True)
>
> class Person(InheritMixin, Base):
>discriminator = Column(String(50))
>name = Column(String(50))
>
> class Engineer(Inherits, Person):
>job = Column(String(50))
>
>
> this should be in the docs so I've added ticket #2471 to handle this.
>
> > 
> > Cheers, Lars
> > 
> > 
> > On Apr 19, 4:13 pm, Michael Bayer  wrote:
> >> On Apr 19, 2012, at 6:23 AM, lars van gemerden wrote:
> >> 
> >> 
> >> 
> >> 
> >> 
> >> 
> >> 
> >> 
> >> 
> >>> I am trying to my my joined inheritance code clearer, for the dynamic
> >>> generation of sa classes and tried to do something like this:
> >> 
> >>> class InheritMixin(object):
> >> 
> >>>@declared_attr
> >>>def __tablename__(cls):
> >>>return cls.__name__
> >>>@declared_attr
> >>>def id(cls):
> >>>if cls.__name__ == 'Object':
> >>>return Column(Integer, primary_key = True)
> >>>else:
> >>>print 'in id: ', cls.__name__, cls.__bases__[0].__name__
> >>>return Column(Integer,
> >>> ForeignKey(cls.__bases__[0].__name__ + '.id'), primary_key = True)
> >>>@declared_attr
> >>>def __mapper_args__(cls):
> >>>if cls.__name__ == 'Object':
> >>>return {'polymorphic_on': 'discriminator'}
> >>>else:
> >>>print 'in mapper_args: ', cls.__name__,
> >>> cls.__bases__[0].__name__
> >>>return {'polymorphic_identity': cls.__name__,
> >>>'inherit_condition': (cls.id ==
> >>> cls.__bases__[0].id)}
> >> 
> >>> Object = type

Re: [sqlalchemy] Re: automating inheritance

2012-04-20 Thread lars van gemerden
Ok, thank you, that helps, but now i cannot inherit from Engineer, as in:

class BaseMixin(object):

discriminator = Column(String(50))

@declared_attr
def __tablename__(cls):
return cls.__name__
@declared_attr
def id(cls):
return Column(Integer, primary_key = True)
@declared_attr
def __mapper_args__(cls):
if not has_inherited_table(cls):
return {'polymorphic_on': 'discriminator'}
else:
return {'polymorphic_identity': cls.__name__}


class InheritMixin(BaseMixin):
@declared_attr
def id(cls):
super_id = super(InheritMixin, cls).id
return Column(Integer, ForeignKey(super_id), primary_key = True)

class Person(BaseMixin, Base):
name = Column(String(50))
   
class Engineer(InheritMixin, Person):
job = Column(String(50))

class MasterEngineer(InheritMixin, Engineer):
specialty = Column(String(50))

Gives an MRO() error and if i would reverse the baseclasses (like class 
Engineer(Person, InheritMixin):  ... ), the inheriting classes pick up the 
wrong id.

Do you see any solution for this? 

BTW: could i just move

@declared_attr
def __mapper_args__(cls):
return {'polymorphic_identity': cls.__name__}

to InheritMixin instead of doing the 'has_inherited_table' if-statement in 
BaseMixin?

Cheers, Lars


On Friday, April 20, 2012 12:41:28 PM UTC+2, Michael Bayer wrote:
>
>
> On Apr 20, 2012, at 4:59 AM, lars van gemerden wrote:
>
> > this is the testcase:
> > 
> > 
> > What am i missing?
>
>
> the issue here is one of Python inheritance mechanics.   Declarative calls 
> upon @declared_attr in terms of the class, that is, we look through the 
> class to find each @declared_attr, but when we find one, we invoke it by 
> just calling it as a method, that is, getattr(cls, name).   This works for 
> things like __mapper_args__ which remain as callable methods on classes 
> like Person, Engineer.   But "id", when that is declared on Person is 
> immediately replaced with a mapping.   By the time you get to Engineer, the 
> id() method is gone.
>
> So for inheriting cases you need to build a mixin that is applied to every 
> subclass.  This makes sense because a mixin with a column on it implies 
> that the column is being associated only with that immediate class - if you 
> wanted a subclass to act as single table inheritance, you'd omit this 
> class.  In this case you want the same column on all subclasses.So you 
> can do it like this (note also using declarative.has_inherited_table 
> helper):
>
> class InheritMixin(object):
>
>@declared_attr
>def __tablename__(cls):
>return cls.__name__
>
>@declared_attr
>def id(cls):
>return Column(Integer, primary_key = True)
>
>@declared_attr
>def __mapper_args__(cls):
>if not has_inherited_table(cls):
>return {'polymorphic_on': 'discriminator'}
>else:
>return {'polymorphic_identity': cls.__name__}
>
> class Inherits(InheritMixin):
> @declared_attr
> def id(cls):
> super_id = super(Inherits, cls).id
> return Column(Integer, ForeignKey(super_id),primary_key = True)
>
> class Person(InheritMixin, Base):
>discriminator = Column(String(50))
>name = Column(String(50))
>
> class Engineer(Inherits, Person):
>job = Column(String(50))
>
>
> this should be in the docs so I've added ticket #2471 to handle this.
>
> > 
> > Cheers, Lars
> > 
> > 
> > On Apr 19, 4:13 pm, Michael Bayer  wrote:
> >> On Apr 19, 2012, at 6:23 AM, lars van gemerden wrote:
> >> 
> >> 
> >> 
> >> 
> >> 
> >> 
> >> 
> >> 
> >> 
> >>> I am trying to my my joined inheritance code clearer, for the dynamic
> >>> generation of sa classes and tried to do something like this:
> >> 
> >>> class InheritMixin(object):
> >> 
> >>>@declared_attr
> >>>def __tablename__(cls):
> >>>return cls.__name__
> >>>@declared_attr
> >>>def id(cls):
> >>>if cls.__name__ == 'Object':
> >>>return Column(Integer, primary_key = True)
> >>>else:
> >>>print 'in id: ', cls.__name__, cls.__bases__[0].__name__
> >>>return Column(Integer,
> >>> ForeignKey(cls.__bases__[0].__name__ + '.id'), primary_key = True)
> >>>@declared_attr
> >>>def __mapper_args__(cls):
> >>>if cls.__name__ == 'Object':
> >>>return {'polymorphic_on': 'discriminator'}
> >>>else:
> >>>print 'in mapper_args: ', cls.__name__,
> >>> cls.__bases__[0].__name__
> >>>return {'polymorphic_identity': cls.__name__,
> >>>'inherit_condition': (cls.id ==
> >>> cls.__bases__[0].id)}
> >> 
> >>> Object = type('Object', (Base, InheritMixin), clsdict)
> >> 
> >>> Where Object should be the (not necessarily direct) baseclass of all
> >>> inheriting classes. However I get errors: "Mapper Mapper|person|person
> >>> could not assemble any primary key columns for mapped table 'Join
> >>> objec

[sqlalchemy] Re: associationproxy for one-to-many

2012-04-20 Thread Eric Lemoine
On Mon, Apr 16, 2012 at 10:49 PM, Eric Lemoine
 wrote:
> Hi
>
> I'd like to use an associationproxy for a simple many-to-one relationship:
>
> class Child(Base):
>     __tablename__ = 'child'
>     id = Column(Integer, primary_key=True)
>     name = Column(Unicode)
>
> class Parent(Base):
>     __tablename__ = 'parent'
>     id = Column(Integer, primary_key=True)
>     child_id = Column(Integer, ForeignKey('child.id')
>     child_ = relationship(Child)
>     child = association_proxy('child_', 'name', creator=)
>
> Now 'child' is a read-only, dictionary-like table. I never want to insert
> new rows in this table.
>
> So I actually pass the following "creator" to the association_proxy
> constructor:
>
> def creator(name):
>     return Session.query(Child).filter_by(name=name).first()
>
> That does the job for "create". But I cannot find a solution for "update".
> On update I'd like to replace the current Child object in the Parent object
> by a new Child object read from the 'child' table.
>
> Using a specific setter (in a getset_factory) does not work for me, as the
> setter receives the Child object (and the value), not the Parent object –
> I'd need a ref to the Parent object to be able to change its Child object in
> child_.
>
> Maybe I'm doing it all wrong and using an associationproxy is not the way to
> go for that case.
>
> Thanks for any suggestion.

No comment for this?

Thanks,



-- 
Eric Lemoine

Camptocamp France SAS
Savoie Technolac, BP 352
73377 Le Bourget du Lac, Cedex

Tel : 00 33 4 79 44 44 96
Mail : eric.lemo...@camptocamp.com
http://www.camptocamp.com

-- 
You received this message because you are subscribed to the Google Groups 
"sqlalchemy" group.
To post to this group, send email to sqlalchemy@googlegroups.com.
To unsubscribe from this group, send email to 
sqlalchemy+unsubscr...@googlegroups.com.
For more options, visit this group at 
http://groups.google.com/group/sqlalchemy?hl=en.



Re: [sqlalchemy] startswith column operator - db specific

2012-04-20 Thread Werner

Michael,

On 20/04/2012 12:21, Michael Bayer wrote:

On Apr 20, 2012, at 4:51 AM, Werner wrote:


On 20/04/2012 10:36, Werner wrote:

I use Firebird SQL, and "like" has a pretty bad performance compared to "starting 
with", as the later uses an index if one is available.

When using "someklass.somecolumn.startswith('value') SA uses "like", what would have to 
be done to use "starting with" instead for the Firebird dialect?


Hhm,

The performance issue should be solved with 2.1+, so did some more search and 
testing.

SA generates something like this when using "startswith" - correct?

select name from cepagesyn where NAME like 'merlot' || '%%';

If I run the above in IBExpert (the db tool I use to admin) it is very slow as the plan 
is "CEPAGESYN NATURAL"

if I use:

select name from cepagesyn where NAME like 'merlot%';

PLAN (CEPAGESYN INDEX (IX_CEPAGESYN_NAME))

So, could the FB dialect be tweaked to do the concatenation in Python instead 
of how it is done now?

Werner

As always thanks for your quick feed back.

the concatenation in SQL is there to handle the case of the argument not being 
a literal string, i.e. another SQL expression like a column.   There also might 
be some edges to it related to escape characters, not sure.

To really handle this we'd have to adjust the mechanism of startswith, endswith, contains 
to move their evaluation out to the compiler, instead of hardwiring them to the 
concatenation.   This is probably a good idea in any case though might be a bit 
destabilizing, might be better for 0.8.In the FB case it would render "STARTING 
WITH".

Would be great if that makes it into 0.8.


for the moment as a workaround I'd employ your own startswith() function, or 
use mycol.op('starting with')(value).

That works great for the case I had a performance issue with.

Thanks a lot
Werner

--
You received this message because you are subscribed to the Google Groups 
"sqlalchemy" group.
To post to this group, send email to sqlalchemy@googlegroups.com.
To unsubscribe from this group, send email to 
sqlalchemy+unsubscr...@googlegroups.com.
For more options, visit this group at 
http://groups.google.com/group/sqlalchemy?hl=en.



Re: [sqlalchemy] Re: Mixing a column declared with @declared_attr into a child class is not mapped in parent class when using STI

2012-04-20 Thread Michael Bayer
there's other edges too, like a custom Column subclass, and contents within the 
open-ended info dict, so __conflicts__ keeps this simple.

I've added ticket 2472 for this.


On Apr 19, 2012, at 4:31 PM, Amos wrote:

> It would be great for declarative to resolve a conflict (perhaps with
> a warning) if the column definitions are exactly the same - though I
> can see this getting complicated with nested ForeignKey objects, etc.
> That said, I really like the idea of exposing the conflict resolution
> mechanism to the user. Perhaps, it could even be made simpler by
> adding a kwarg to the Column definition:
> 
> class MyMixin(object):
>@declared_attr
>def target_id(cls):
>return Column(Integer, ForeignKey('target.id'),
> replace_existing=True)
> 
> On Apr 18, 7:11 am, Michael Bayer  wrote:
>> On Apr 17, 2012, at 8:23 PM, Amos wrote:
>> 
>>> Thanks for the clarification. I did play around with __abstract__ but
>>> like you said it doesn't work in the middle of the inheritance chain.
>>> The main idea behind this approach is the DRY concept - define the
>>> columns/relationships only once and use them interchangeably in any of
>>> the derived STI models. This workaround sort of accomplishes that but
>>> at the same time restricts you to a hierarchical model, whereas using
>>> mixins is much more flexible.
>> 
>> the issue with mixins here is that you essentially have two mixins saying 
>> something that conflicts, they both create a Column object with the same 
>> name.   One could have a different "info" dict than the other, for example - 
>> it would be a surprise for declarative to just pick one, and discard the 
>> other.   For declarative to compare them is also something I'd rather not 
>> get into as again things like the "info" dict and custom subclasses of 
>> Column couldn't necessarily be compared.
>> 
>> But I thought of a possible way to give this capability to you, a new method 
>> __conflicts__, like this:
>> 
>> class MyMixin(object):
>> @declared_attr
>> def target_id(cls):
>> return Column(Integer, ForeignKey('target.id'))
>> 
>> @classmethod
>> def __conflicts__(cls, key, existing, new):
>> if key == 'target_id':
>> return existing
>> else:
>>return None
>> 
>> so basically, instead of declarative raising "column x conflicts with 
>> existing" it will first call __conflicts__ on your class (which could be 
>> anywhere in the hierarchy), giving your code a chance to resolve.
>> 
>> What I like about this is that declarative's behavioral contract doesn't 
>> change at all for anybody, it doesn't have to get into comparing or silent 
>> guessing, and the feature itself, which would be very rarely used as this is 
>> not a typical use case, would have a decent place for documenting under the 
>> "special methods" section of declarative and also be a very simple, two line 
>> feature.
> 
> -- 
> You received this message because you are subscribed to the Google Groups 
> "sqlalchemy" group.
> To post to this group, send email to sqlalchemy@googlegroups.com.
> To unsubscribe from this group, send email to 
> sqlalchemy+unsubscr...@googlegroups.com.
> For more options, visit this group at 
> http://groups.google.com/group/sqlalchemy?hl=en.
> 

-- 
You received this message because you are subscribed to the Google Groups 
"sqlalchemy" group.
To post to this group, send email to sqlalchemy@googlegroups.com.
To unsubscribe from this group, send email to 
sqlalchemy+unsubscr...@googlegroups.com.
For more options, visit this group at 
http://groups.google.com/group/sqlalchemy?hl=en.



Re: [sqlalchemy] Re: automating inheritance

2012-04-20 Thread Michael Bayer

On Apr 20, 2012, at 4:59 AM, lars van gemerden wrote:

> this is the testcase:
> 
> 
> What am i missing?


the issue here is one of Python inheritance mechanics.   Declarative calls upon 
@declared_attr in terms of the class, that is, we look through the class to 
find each @declared_attr, but when we find one, we invoke it by just calling it 
as a method, that is, getattr(cls, name).   This works for things like 
__mapper_args__ which remain as callable methods on classes like Person, 
Engineer.   But "id", when that is declared on Person is immediately replaced 
with a mapping.   By the time you get to Engineer, the id() method is gone.

So for inheriting cases you need to build a mixin that is applied to every 
subclass.  This makes sense because a mixin with a column on it implies that 
the column is being associated only with that immediate class - if you wanted a 
subclass to act as single table inheritance, you'd omit this class.  In this 
case you want the same column on all subclasses.So you can do it like this 
(note also using declarative.has_inherited_table helper):

class InheritMixin(object):

   @declared_attr
   def __tablename__(cls):
   return cls.__name__

   @declared_attr
   def id(cls):
   return Column(Integer, primary_key = True)

   @declared_attr
   def __mapper_args__(cls):
   if not has_inherited_table(cls):
   return {'polymorphic_on': 'discriminator'}
   else:
   return {'polymorphic_identity': cls.__name__}

class Inherits(InheritMixin):
@declared_attr
def id(cls):
super_id = super(Inherits, cls).id
return Column(Integer, ForeignKey(super_id),primary_key = True)

class Person(InheritMixin, Base):
   discriminator = Column(String(50))
   name = Column(String(50))

class Engineer(Inherits, Person):
   job = Column(String(50))


this should be in the docs so I've added ticket #2471 to handle this.





> 
> Cheers, Lars
> 
> 
> On Apr 19, 4:13 pm, Michael Bayer  wrote:
>> On Apr 19, 2012, at 6:23 AM, lars van gemerden wrote:
>> 
>> 
>> 
>> 
>> 
>> 
>> 
>> 
>> 
>>> I am trying to my my joined inheritance code clearer, for the dynamic
>>> generation of sa classes and tried to do something like this:
>> 
>>> class InheritMixin(object):
>> 
>>>@declared_attr
>>>def __tablename__(cls):
>>>return cls.__name__
>>>@declared_attr
>>>def id(cls):
>>>if cls.__name__ == 'Object':
>>>return Column(Integer, primary_key = True)
>>>else:
>>>print 'in id: ', cls.__name__, cls.__bases__[0].__name__
>>>return Column(Integer,
>>> ForeignKey(cls.__bases__[0].__name__ + '.id'), primary_key = True)
>>>@declared_attr
>>>def __mapper_args__(cls):
>>>if cls.__name__ == 'Object':
>>>return {'polymorphic_on': 'discriminator'}
>>>else:
>>>print 'in mapper_args: ', cls.__name__,
>>> cls.__bases__[0].__name__
>>>return {'polymorphic_identity': cls.__name__,
>>>'inherit_condition': (cls.id ==
>>> cls.__bases__[0].id)}
>> 
>>> Object = type('Object', (Base, InheritMixin), clsdict)
>> 
>>> Where Object should be the (not necessarily direct) baseclass of all
>>> inheriting classes. However I get errors: "Mapper Mapper|person|person
>>> could not assemble any primary key columns for mapped table 'Join
>>> object on Object(65389120) and person(65428224)' " etc ..
>> 
>> im not sure of the cause of that error, can you attach a full test case 
>> which illustrates this message being generated ?
>> 
>> 
>> 
>>> I noticed that the method __mapper_args__(cls) is always called before
>>> id(cls) (which is never called, probably due to the error.
>> 
>> the __mapper_args__(cls) method here directly calls upon .id, so if you see 
>> .id() not being called it suggests some other form of .id is being used.
>> 
>> Is it possible that Base or something else has a conflicting "id" attribute?
>> 
>> 
>> 
>>> Also, is there a way to add the discriminator column to the mixin (if
>>> i just directly add it to the declaration, this gave another maybe
>>> related error)?
>> 
>> maybe, let's start with the general idea of the mixin you're going to send 
>> me as a working script.
> 
> -- 
> You received this message because you are subscribed to the Google Groups 
> "sqlalchemy" group.
> To post to this group, send email to sqlalchemy@googlegroups.com.
> To unsubscribe from this group, send email to 
> sqlalchemy+unsubscr...@googlegroups.com.
> For more options, visit this group at 
> http://groups.google.com/group/sqlalchemy?hl=en.
> 

-- 
You received this message because you are subscribed to the Google Groups 
"sqlalchemy" group.
To post to this group, send email to sqlalchemy@googlegroups.com.
To unsubscribe from this group, send email to 
sqlalchemy+unsubscr...@googlegroups.com.
For more options, visit this group at 
http://groups.google.com/group/sqlalchemy?hl=en.



Re: [sqlalchemy] startswith column operator - db specific

2012-04-20 Thread Michael Bayer

On Apr 20, 2012, at 4:51 AM, Werner wrote:

> On 20/04/2012 10:36, Werner wrote:
>> I use Firebird SQL, and "like" has a pretty bad performance compared to 
>> "starting with", as the later uses an index if one is available.
>> 
>> When using "someklass.somecolumn.startswith('value') SA uses "like", what 
>> would have to be done to use "starting with" instead for the Firebird 
>> dialect?
>> 
> Hhm,
> 
> The performance issue should be solved with 2.1+, so did some more search and 
> testing.
> 
> SA generates something like this when using "startswith" - correct?
> 
> select name from cepagesyn where NAME like 'merlot' || '%%';
> 
> If I run the above in IBExpert (the db tool I use to admin) it is very slow 
> as the plan is "CEPAGESYN NATURAL"
> 
> if I use:
> 
> select name from cepagesyn where NAME like 'merlot%';
> 
> PLAN (CEPAGESYN INDEX (IX_CEPAGESYN_NAME))
> 
> So, could the FB dialect be tweaked to do the concatenation in Python instead 
> of how it is done now?
> 
> Werner

the concatenation in SQL is there to handle the case of the argument not being 
a literal string, i.e. another SQL expression like a column.   There also might 
be some edges to it related to escape characters, not sure.

To really handle this we'd have to adjust the mechanism of startswith, 
endswith, contains to move their evaluation out to the compiler, instead of 
hardwiring them to the concatenation.   This is probably a good idea in any 
case though might be a bit destabilizing, might be better for 0.8.In the FB 
case it would render "STARTING WITH".

for the moment as a workaround I'd employ your own startswith() function, or 
use mycol.op('starting with')(value).

-- 
You received this message because you are subscribed to the Google Groups 
"sqlalchemy" group.
To post to this group, send email to sqlalchemy@googlegroups.com.
To unsubscribe from this group, send email to 
sqlalchemy+unsubscr...@googlegroups.com.
For more options, visit this group at 
http://groups.google.com/group/sqlalchemy?hl=en.



[sqlalchemy] Re: automating inheritance

2012-04-20 Thread lars van gemerden
this is the testcase:

from sqlalchemy import *
from sqlalchemy.orm.session import sessionmaker
from sqlalchemy.ext.declarative import declarative_base, declared_attr

engine = create_engine('sqlite:///:memory:', echo=False)
Base = declarative_base(bind = engine)
Session = sessionmaker(bind = engine)

def setup(engine):
Base.metadata.create_all(engine)
Session = sessionmaker(bind=engine)
return Session()

class InheritMixin(object):

@declared_attr
def __tablename__(cls):
return cls.__name__
@declared_attr
def id(cls):
if Base in cls.__bases__:
print 'base in id(cls): ', cls
return Column(Integer, primary_key = True)
else:
print 'in id(cls): ', cls, cls.__bases__[0]
return Column(Integer, ForeignKey(cls.__bases__[0].id),
primary_key = True)
@declared_attr
def __mapper_args__(cls):
if Base in cls.__bases__:
print 'base in __mapper_args__(cls): ', cls
return {'polymorphic_on': 'discriminator'}
else:
print 'in __mapper_args__(cls): ', cls, cls.__bases__[0],
cls.id, (cls.id is cls.__bases__[0].id)
return {'polymorphic_identity': cls.__name__}

class Person(Base, InheritMixin):
discriminator = Column(String(50))
name = Column(String(50))

class Engineer(Person):
job = Column(String(50))

if __name__ == '__main__':

session = setup(engine)
a = Person(name = 'ann')
b = Engineer(name = 'bob', job = 'car repair')
session.add_all([a, b])
session.commit()
people = session.query(Person).all()
print people

Note that i left out the 'inherit_condition', because without there is
already a problem:

base in id(cls):  
base in mapper_args(cls):  
in mapper_args(cls):Person.id True
Traceback (most recent call last):
  File "D:\Documents\Code\Eclipse\workspace\process_data3\src
\little_tests2.py", line 40, in 
class Engineer(Person):
  File "C:\Python27\lib\site-packages\sqlalchemy\ext\declarative.py",
line 1336, in __init__
_as_declarative(cls, classname, cls.__dict__)
  File "C:\Python27\lib\site-packages\sqlalchemy\ext\declarative.py",
line 1329, in _as_declarative
**mapper_args)
  File "C:\Python27\lib\site-packages\sqlalchemy\orm\__init__.py",
line 1116, in mapper
return Mapper(class_, local_table, *args, **params)
  File "C:\Python27\lib\site-packages\sqlalchemy\orm\mapper.py", line
197, in __init__
self._configure_inheritance()
  File "C:\Python27\lib\site-packages\sqlalchemy\orm\mapper.py", line
473, in _configure_inheritance
self.local_table)
  File "C:\Python27\lib\site-packages\sqlalchemy\sql\util.py", line
303, in join_condition
"between '%s' and '%s'.%s" % (a.description, b.description, hint))
sqlalchemy.exc.ArgumentError: Can't find any foreign key relationships
between 'Person' and 'Engineer'.

What am i missing?

Cheers, Lars


On Apr 19, 4:13 pm, Michael Bayer  wrote:
> On Apr 19, 2012, at 6:23 AM, lars van gemerden wrote:
>
>
>
>
>
>
>
>
>
> > I am trying to my my joined inheritance code clearer, for the dynamic
> > generation of sa classes and tried to do something like this:
>
> > class InheritMixin(object):
>
> >    @declared_attr
> >    def __tablename__(cls):
> >        return cls.__name__
> >    @declared_attr
> >    def id(cls):
> >        if cls.__name__ == 'Object':
> >            return Column(Integer, primary_key = True)
> >        else:
> >            print 'in id: ', cls.__name__, cls.__bases__[0].__name__
> >            return Column(Integer,
> > ForeignKey(cls.__bases__[0].__name__ + '.id'), primary_key = True)
> >    @declared_attr
> >    def __mapper_args__(cls):
> >        if cls.__name__ == 'Object':
> >            return {'polymorphic_on': 'discriminator'}
> >        else:
> >            print 'in mapper_args: ', cls.__name__,
> > cls.__bases__[0].__name__
> >            return {'polymorphic_identity': cls.__name__,
> >                    'inherit_condition': (cls.id ==
> > cls.__bases__[0].id)}
>
> > Object = type('Object', (Base, InheritMixin), clsdict)
>
> > Where Object should be the (not necessarily direct) baseclass of all
> > inheriting classes. However I get errors: "Mapper Mapper|person|person
> > could not assemble any primary key columns for mapped table 'Join
> > object on Object(65389120) and person(65428224)' " etc ..
>
> im not sure of the cause of that error, can you attach a full test case which 
> illustrates this message being generated ?
>
>
>
> > I noticed that the method __mapper_args__(cls) is always called before
> > id(cls) (which is never called, probably due to the error.
>
> the __mapper_args__(cls) method here directly calls upon .id, so if you see 
> .id() not being called it suggests some other form of .id is being used.
>
> Is it possible that Base or something else has a conflicting "id" attribute?
>
>
>
> > Also, is there a way to add the discriminator column to the mixin (if
> > i just directly add it to the decla

Re: [sqlalchemy] stucco_evolution 0.4 released

2012-04-20 Thread Wichert Akkerman

On 04/19/2012 07:43 PM, Michael Bayer wrote:
If you've seen my recent talks you saw that I'm a little skeptical of 
what you're terming "non-monolithic" databases.Let's say this 
means, a database with a set of tables maintained by entirely 
different packages, but with the possibility of dependencies between 
those tables.If I understand correctly, if we were dealing with 
sets of tables that didn't have any dependency, you wouldn't need a 
distributed migration tool, each package would handle migrations for 
its own set of tables independently, is that right ?


That suggests that every package would have its own migration tool, 
which is not very practical from a sysadmin point of view. I am an 
upgrading an application I want to be able to run all necessary 
migrations for all components of an application in one run. I do not 
want to be required to figure out which packages an application was 
running and then migrate them all separately. So I definitely see a need 
for an upgrade framework that can deal with multiple packages.


I think what I need to see here are, what exactly are these packages, 
outside of the Django community, that actually create their own tables 
yet encourage dependencies between those tables and your app's own 
tables ?   I know people are working on them since I see people asking 
questions about those use cases, but what are they ?  What's the 
openid and user/groups package you're thinking of here ?


s4u.image is such an example: https://github.com/2style4you/s4u.image . 
That package implements an image store which supports on-demand scaling 
of images. Metadata is stored in a SQL database and commonly you add 
references to images to other tables. Every site we build uses s4u.image 
to manage image handling. This happens to be in-house developed by us, 
but for all intents and purposes it is a third-party package to our 
front-end developers.


In the development world I've always lived in, we just don't have 
third party libraries that bring in their own sub-schemas.  Up until 
now the thinking has been, if it's significant enough that it is part 
of your datamodel, it's part of what you should own yourself, though 
certainly drawing upon past recipes.


I suspect a difference is that we are often building different sites 
that build on shared common functionality. Our main business is building 
sites that deal with online fashion, so everything we build has to deal 
with things like images and clothing articles. The code to handle those 
has been split out to separate packages (s4u.image is one of those) that 
define core datamodels and some logic, and our sites build on those. 
Sometimes we extend the base models, for example when for a particular 
site we need to track extra data for clothing, and sometimes we use the 
base models as-is and reference them directly via relationships and 
foreign keys. That results in an ecosystem of many different packages 
and sites that each have their own evolve in their own way and require 
their own migrations.


When we upgrade a site our process is pretty simple: upgrade version 
pins for buildout, rerun buildout, run upgrade-script, tell mod_wsgi to 
reload. The upgrade-script walks through all migrations from all 
packages a site uses so we have a single interface for administrators to 
upgrade everything. The upgrade framework itself is extremely minimal 
(see https://github.com/2style4you/s4u.upgrade ), but works well enough 
for us. Note that we deviate from stucco_evolution in three important 
ways: we do not use versioning but require upgrade steps to test if an 
upgrade is necessary, our upgrade framework is not tied to SQLAlchemy 
but has a more generic requirements-system so you can use it for other 
things (we use it for filesystem changes and SOLR configuration as well 
for example), and it does not support dependencies. Personally I 
consider the first two to be desirable qualities for an upgrade 
framework. Dependencies are something that we will probably need to add 
at some point.


Wichert.

--
You received this message because you are subscribed to the Google Groups 
"sqlalchemy" group.
To post to this group, send email to sqlalchemy@googlegroups.com.
To unsubscribe from this group, send email to 
sqlalchemy+unsubscr...@googlegroups.com.
For more options, visit this group at 
http://groups.google.com/group/sqlalchemy?hl=en.



Re: [sqlalchemy] startswith column operator - db specific

2012-04-20 Thread Werner

On 20/04/2012 10:36, Werner wrote:
I use Firebird SQL, and "like" has a pretty bad performance compared 
to "starting with", as the later uses an index if one is available.


When using "someklass.somecolumn.startswith('value') SA uses "like", 
what would have to be done to use "starting with" instead for the 
Firebird dialect?



Hhm,

The performance issue should be solved with 2.1+, so did some more 
search and testing.


SA generates something like this when using "startswith" - correct?

select name from cepagesyn where NAME like 'merlot' || '%%';

If I run the above in IBExpert (the db tool I use to admin) it is very 
slow as the plan is "CEPAGESYN NATURAL"


if I use:

select name from cepagesyn where NAME like 'merlot%';

PLAN (CEPAGESYN INDEX (IX_CEPAGESYN_NAME))

So, could the FB dialect be tweaked to do the concatenation in Python 
instead of how it is done now?


Werner

--
You received this message because you are subscribed to the Google Groups 
"sqlalchemy" group.
To post to this group, send email to sqlalchemy@googlegroups.com.
To unsubscribe from this group, send email to 
sqlalchemy+unsubscr...@googlegroups.com.
For more options, visit this group at 
http://groups.google.com/group/sqlalchemy?hl=en.



[sqlalchemy] startswith column operator - db specific

2012-04-20 Thread Werner
I use Firebird SQL, and "like" has a pretty bad performance compared to 
"starting with", as the later uses an index if one is available.


When using "someklass.somecolumn.startswith('value') SA uses "like", 
what would have to be done to use "starting with" instead for the 
Firebird dialect?


Werner

--
You received this message because you are subscribed to the Google Groups 
"sqlalchemy" group.
To post to this group, send email to sqlalchemy@googlegroups.com.
To unsubscribe from this group, send email to 
sqlalchemy+unsubscr...@googlegroups.com.
For more options, visit this group at 
http://groups.google.com/group/sqlalchemy?hl=en.