Re: [sqlalchemy] duplicate column name error when subquery() or join() a subclass

2012-05-03 Thread Wu-bin Zhen
Hi Michael,

I modified your code and got the error with subquery(). I remember I used
to have the same error with the join() method but couldn't reproduce it
with this sample. The SQLAlchemy version is still 0.6.8.
I really appreciate your reply and help.

--
from sqlalchemy import *
from sqlalchemy.orm import *
from sqlalchemy.ext.declarative import declarative_base

Base= declarative_base()

class BaseClass(object):
id = Column(id, Integer, primary_key=True, key=id)

class Resource(Base, BaseClass):
__tablename__ = resources

class BasePrAc(Resource):
__tablename__ = base_products_accessories
_polymorphicIdentity = Column(polymorphic_identity, String(20),
key=polymorphicIdentity)
__mapper_args__ = {
'polymorphic_on': _polymorphicIdentity,
'polymorphic_identity': None
}
id = Column(id, Integer, ForeignKey(resources.id), primary_key=True)

class Product(BasePrAc):
__tablename__ = products
__mapper_args__ = {
'polymorphic_identity': 'Product'
}
id = Column(id, Integer, ForeignKey(base_products_accessories.id),
primary_key=True)

class Accessory(BasePrAc):
__tablename__ = accessories
__mapper_args__ = {
'polymorphic_identity': 'Accessory'
}
id = Column(id, Integer, ForeignKey(base_products_accessories.id),
primary_key=True)

class Post(Base, BaseClass):
__tablename__ = posts
basePrAcId = Column(Integer, ForeignKey('base_products_accessories.id'))
basePrAc = relationship(BasePrAc, uselist=False,
backref=backref(_posts, collection_class=set))

e = create_engine(mysql://root@localhost/sample?charset=utf8, echo=True)
Base.metadata.create_all(e)
s = Session(e)
s.add_all([
Post(
basePrAc=Product()
),
Post(
basePrAc=Accessory()
),
Post(
basePrAc=Accessory()
)
])
sq = s.query(BasePrAc).subquery()
q = s.query(Post).join((sq, sq.c.id == Post.basePrAcId)).all()
print q

2012-05-03 18:42:03,539 INFO sqlalchemy.engine.base.Engine.0x...ae90
CREATE TABLE resources (
id INTEGER NOT NULL AUTO_INCREMENT,
PRIMARY KEY (id)
)


2012-05-03 18:42:03,539 INFO sqlalchemy.engine.base.Engine.0x...ae90 ()
2012-05-03 18:42:03,657 INFO sqlalchemy.engine.base.Engine.0x...ae90 COMMIT
2012-05-03 18:42:03,658 INFO sqlalchemy.engine.base.Engine.0x...ae90
CREATE TABLE base_products_accessories (
polymorphic_identity VARCHAR(20),
id INTEGER NOT NULL,
PRIMARY KEY (id),
FOREIGN KEY(id) REFERENCES resources (id)
)


2012-05-03 18:42:03,658 INFO sqlalchemy.engine.base.Engine.0x...ae90 ()
2012-05-03 18:42:03,769 INFO sqlalchemy.engine.base.Engine.0x...ae90 COMMIT
2012-05-03 18:42:03,770 INFO sqlalchemy.engine.base.Engine.0x...ae90
CREATE TABLE accessories (
id INTEGER NOT NULL,
PRIMARY KEY (id),
FOREIGN KEY(id) REFERENCES base_products_accessories (id)
)


2012-05-03 18:42:03,770 INFO sqlalchemy.engine.base.Engine.0x...ae90 ()
2012-05-03 18:42:03,893 INFO sqlalchemy.engine.base.Engine.0x...ae90 COMMIT
2012-05-03 18:42:03,893 INFO sqlalchemy.engine.base.Engine.0x...ae90
CREATE TABLE posts (
id INTEGER NOT NULL AUTO_INCREMENT,
`basePrAcId` INTEGER,
PRIMARY KEY (id),
FOREIGN KEY(`basePrAcId`) REFERENCES base_products_accessories (id)
)


2012-05-03 18:42:03,893 INFO sqlalchemy.engine.base.Engine.0x...ae90 ()
2012-05-03 18:42:04,016 INFO sqlalchemy.engine.base.Engine.0x...ae90 COMMIT
2012-05-03 18:42:04,017 INFO sqlalchemy.engine.base.Engine.0x...ae90
CREATE TABLE products (
id INTEGER NOT NULL,
PRIMARY KEY (id),
FOREIGN KEY(id) REFERENCES base_products_accessories (id)
)


2012-05-03 18:42:04,017 INFO sqlalchemy.engine.base.Engine.0x...ae90 ()
2012-05-03 18:42:04,140 INFO sqlalchemy.engine.base.Engine.0x...ae90 COMMIT
/usr/local/lib/python2.7/dist-packages/SQLAlchemy-0.6.8-py2.7.egg/sqlalchemy/sql/expression.py:2104:
SAWarning: Column 'id' on table sqlalchemy.sql.expression.Select at
0x1bb1390; Select object being replaced by another column with the same
key.  Consider use_labels for select() statements.
  self[column.key] = column
2012-05-03 18:42:04,145 INFO sqlalchemy.engine.base.Engine.0x...ae90 BEGIN
(implicit)
2012-05-03 18:42:04,146 INFO sqlalchemy.engine.base.Engine.0x...ae90 INSERT
INTO resources () VALUES ()
2012-05-03 18:42:04,146 INFO sqlalchemy.engine.base.Engine.0x...ae90 ()
2012-05-03 18:42:04,147 INFO sqlalchemy.engine.base.Engine.0x...ae90 INSERT
INTO resources () VALUES ()
2012-05-03 18:42:04,147 INFO sqlalchemy.engine.base.Engine.0x...ae90 ()
2012-05-03 18:42:04,147 INFO sqlalchemy.engine.base.Engine.0x...ae90 INSERT
INTO resources () VALUES ()
2012-05-03 18:42:04,147 INFO sqlalchemy.engine.base.Engine.0x...ae90 ()
2012-05-03 18:42:04,148 INFO sqlalchemy.engine.base.Engine.0x...ae90 INSERT
INTO base_products_accessories (polymorphic_identity, id) VALUES (%s, %s)
2012-05-03 

Re: [sqlalchemy] cascade delete in relationship and session.execute(table.update())

2012-01-06 Thread Wu-bin Zhen
I really appreciate your help! It works great without any problem.
I tried session.refresh(storeobject) and I was wondering why it didn't
work, now I learned the difference from your method.

Again, thank you very much, and have a great weekend.


On Tue, Jan 3, 2012 at 10:56 AM, Michael Bayer mike...@zzzcomputing.comwrote:


 On Jan 2, 2012, at 4:06 PM, Wubin wrote:

 
  class Product(PolymorphicClass): #there are different types of the
  product
 __tablename__ = products
 id = Column(id, Integer, primary_key=True, key=id)
name = Column(name, String(50), unique=True, nullable=False)
 storeId = Column(store_id, Integer, ForeignKey(store.id),
  key=storeId)
store = relationship(Store,
uselist=False,
backref=backref(_products, collection_class=set,
 cascade=all,
  delete))
 
  class Store(object):
 __tablename__ = stores
id = Column(id, Integer, primary_key=True, key=id)
 name = Column(name, String(50), unique=True, nullable=False)
 
  I tried to use query object to update the storeId column in the
  Product class, like:
 
 session.query(Product).filter(Product.storeId==oldStoreId).update({Product.storeId:
  newStoreId})
 
  but the sqlalchemy rejected this with the Only update via a single
  table query is currently supported message.

 This would indicate that PolymorphicClass is mapped to a table as well.
  A DELETE or UPDATE statement, in standard SQL, doesn't support more than
 one table being affected at the same time (only MySQL has an extended
 syntax that supports this but it's not supported by the ORM).   There's
 also a syntax that supports only one table being updated, but multiple
 tables in the FROM clause which on Postgresql is UPDATE..FROM, and
 SQLAlchemy now supports that too, but again the ORM doesn't yet have
 support for that to be integrated.


  So then I decided to use
  session.execute(Product.__table__.values().where()) to update the
  table and it works fine.

 OK


  But in the final step deleting old store, I
  tried to delete the store object(now the store has no product after
  the update), and the store object is deleted...but with the products
  that previously belong to this store.

 
  I guess the cascade delete in the relationship does not notice if I
  use session.execute() to update the table. So my question is...(1) Is
  there anyway to tell the relationship hey now those products no
  longer belong to you, and you shouldn't delete them when you are to
  deleted?

 yeah just expire the collection:

 session.expire(storeobject, ['name_of_products_collection'])

  (2) Is there any trick, even the polymorphic class can use
  the query object to update table, without getting Only update via a
  single table query error? I still prefer to use session.query()
  instead of session.execute()...

 Right now you can only pass in the base class, I took a look since we do
 support UPDATE..FROM for supporting DBs, the controversial part here is
 that an UPDATE against the child table which then refers to the base table
 would need WHERE criterion to join the two together, which introduces
 tricky decisionmaking.   But one possibility is to just leave that up to
 the user in this case.

 I've added http://www.sqlalchemy.org/trac/ticket/2365 to look at this
 possibility.


 --
 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] Column parameters: default=callable is working, but onupdate=callable is not.

2011-12-01 Thread Wu-bin Zhen
Hi Michael,

I really appreciate your quick reply, and that you made me clear for this
issue.
Actually my goal is to log when an object was last modified, and who did
it. So I guess I need to use MapperExtension to implement this.

Thank you very much, and have a nice day.

On Thu, Dec 1, 2011 at 2:32 PM, Michael Bayer mike...@zzzcomputing.comwrote:


 On Dec 1, 2011, at 1:32 AM, Wubin wrote:

  Hi,
  I created two classes Resource and BaseMedia, and BaseMedia is a
  subclass of Resource. The table mapping is implemented as below:
 
  class Resource(Database.Base):
__tablename__ = resources
createUserId = Column(create_user_id, Integer,
  ForeignKey(users.id), nullable=True, key=createUserId,
  default=currentUserId)
modifyUserId = Column(modify_user_id, Integer,
  ForeignKey(users.id), nullable=True, key=modifyUserId,
  default=currentUserId, onupdate=currentUserId)
 
  class BaseMedia(Resource.Resource):
__tablename__ = base_media
 id = Column(id, Integer, ForeignKey(resources.id),
  primary_key=True)
__mapper_args__ = { 'extension':
  BaseMediaMapperExtension.BaseMediaMapperExtension() }
name = Column(name, Unicode(50))
type = Column(type, String(50))
size = Column(size, Integer)
 
  and then, when I try to use session.add() to insert a new BaseMedia
  object, the parameter default=currentUserId in both createUserId
  and modifyUserId columns is working properly. However, if I use
  session.merge() to update the name column in an existing BaseMedia
  object, the name field is updated correctly in the database, but the

 name is on the base_media table, not resources, so no onupdate
 proceeds when only columns against base_media are modified.

 onupdate is mostly used for timestamp columns to log when a row was last
 modified.  Using it to set integer foreign key values seems pretty
 questionable.


 --
 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.