Re: [sqlalchemy] Updating a one-to-many relationship
I think you may be confused about the relationship properties you have here. As far as I can tell, a Creator can have many companies, but each Company has only one creator, correct? So Company.creator should only ever be an instance of Creator (or None), whereas Creator.companies should be a list. In your __repr__ example: class Creator(Base): def __repr__(self): return '%s' % self.creator class Company(Base): def __repr__(self): return '%s, created by %s' % (self.company, self.creator[0]) Why are you using self.creator[0] here? self.creator is not a list, it should either be an instance of Creator, or None. Overriding __repr__ is also a good way to make debugging difficult. For example, if you had a list of Creator instances and you printed them at the python prompt, it would just look like a list of strings. When I want extra information from __repr__, I normally write it something like this: def __repr__(self): classname = type(self).__name__ return '%s name=%r' % (classname, self.name) In your second example: a=session.query(Creator).first() a[0].companies a.companies Query.first() returns a single value, not a list. So typing a[0] doesn't make any sense. Please try to create a self-contained script that demonstrates your problem. Here is a good example: https://groups.google.com/d/msg/sqlalchemy/jQtIRJXVfH8/LgwX-bomEIQJ Thanks, Simon On Wed, Aug 14, 2013 at 2:45 AM, csdr...@gmail.com wrote: I'm afraid there are still some bugs in here that hopefully you can help with. class Creator(Base): __tablename__ = creators id = Column(Integer, primary_key = True) company_id = Column(Integer, ForeignKey('companies.id')) creator = Column(String(100), nullable=False, unique=True) def __init__(self, creator): self.creator = creator def __repr__(self): return '%s' % self.creator # otherwise returns a single entry list for some reason (e.g. would display [user]) class Company(Base): __tablename__ = companies id = Column(Integer, primary_key = True) company = Column(String(100), unique=True, nullable=False) #might want to revise string sizes at some point creator = relationship(Creator, backref=companies, cascade=all) def __init__(self, company, creator): self.company = company #self.creator.append(Creator(creator)) existing_creator = session.query(Creator).filter_by(creator=creator).first() #self.creator.append(existing_creator or Creator(creator)) if existing_creator: print True self.creator.append(existing_creator) else: self.creator.append(Creator(creator)) def __repr__(self): return '%s, created by %s' % (self.company, self.creator[0]) 1) Weird __repr__ error: class Creator(Base): def __repr__(self): return '%s' % self.creator class Company(Base): def __repr__(self): return '%s, created by %s' % (self.company, self.creator[0]) c=Company(Company1, mike) session.add(c) c=Company(Company2, mike) True session.add(c) c=Company(Company3, john) session.add(c) c=Company(Company4, mike) True session.add(c) session.query(Company).all() [Traceback (most recent call last): File stdin, line 1, in module File stdin, line 17, in __repr__ However, if I divide the query lines among every add() statement, there is no __repr__ error. c=Company(Company1, mike) session.add(c) session.query(Company).all() [Company1, created by mike] c=Company(Company2, mike) True session.add(c) session.query(Company).all() [Company1, created by mike, Company2, created by mike] c=Company(Company3, john) session.add(c) session.query(Company).all() [Company1, created by mike, Company2, created by mike, Company3, created by john] c=Company(Company4, mike) True session.add(c) session.query(Company).all() [Company1, created by mike, Company2, created by mike, Company3, created by john, Company4, created by mike] 2) Creator.companies only shows the most recently added company: session.query(Company).all() [Company1, created by mike, Company2, created by mike, Company3, created by john, Company4, created by mike] session.query(Creator).all() [mike, john] a=session.query(Creator).first() a[0].companies a.companies Company4, created by mike 3) Weird Company.creator error: session.query(Company).all() [Company1, created by mike, Company2, created by mike, Company3, created by john, Company4, created by mike] session.query(Company.creator).all() [(False,), (False,), (False,), (False,), (True,), (False,), (False,), (True,)] a=session.query(Company).first() a.creator [mike] Anyone have any ideas? -- 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
Re: [sqlalchemy] Cross-schema foreign keys reflection
On Tuesday, August 13, 2013 7:43:54 PM UTC-4, Michael Bayer wrote: cross-schema reflection is supported on PG but has caveats, see http://docs.sqlalchemy.org/en/rel_0_8/dialects/postgresql.html#remote-cross-schema-table-introspectionfor a discussion of recommended usage patterns. Thanks for pointing out that page. I also needed to add the schema to the foreign key declarations. eg Column(Integer, ForeignKey('otherschema.othertable.id')) instead of Column(Integer, ForeignKey('othertable.id')) -- Jason -- 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 http://groups.google.com/group/sqlalchemy. For more options, visit https://groups.google.com/groups/opt_out.
[sqlalchemy] many-to-one relationship with intermediate table non equijoin
Hello all Tried for hours to figure out the various relationship() options with no luck. Consider: class Enrolment(base): __tablename__ = 'enrolment' person_id = Column(String, primary_key=True) group_id= Column(String, primary_key=True) enrol_date = Column(Date, primary_key=True) level_id= Column(String, nullable=False) next_date = Column(Date) def __repr__(self): return 'Enrol(%s, %s, %s, %s)' % (self.person_id, self.enrol_date, self.group_id, self.level_id) class RosterLine(base): __tablename__ = 'roster_line' line_id = Column(String, primary_key=True) group_id= Column(String, nullable=False) class Timesheet(base): __tablename__ = 'timesheet' id = Column(Integer, primary_key=True) person_id = Column(String, nullable=False) line_id = Column(String, nullable=False) date= Column(Date, nullable=False) enrolment = relationship(Enrolment, primaryjoin=lambda:( (Timesheet.person_id == foreign(Enrolment.person_id)) (Timesheet.date = Enrolment.enrol_date) ((Timesheet.date Enrolment.next_date) | (Enrolment.next_date == None)) # (Timesheet.line_id == RosterLine.line_id) # (RosterLine.group_id == Enrolment.group_id) ), # uselist=False, viewonly=True) The relationship as it stands works correctly but I can't figure out the magic words to introduce the intermediate join to RosterLine. The relationship should issue SQL like: select E.* fromroster_line L, enrolment E where L.line_id = 'work' and L.group_id = E.group_id and E.person_id = 'bob' and E.enrol_date = '2012-03-04' and (E.next_date '2012-03-04' or E.next_date is null) Eternally grateful for any help. Thanks. -- 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 http://groups.google.com/group/sqlalchemy. For more options, visit https://groups.google.com/groups/opt_out. from sqlalchemy import * from sqlalchemy.orm import * from sqlalchemy.ext.declarative import declarative_base from datetime import date base = declarative_base() class Enrolment(base): __tablename__ = 'enrolment' person_id = Column(String, primary_key=True) group_id= Column(String, primary_key=True) enrol_date = Column(Date, primary_key=True) level_id= Column(String, nullable=False) next_date = Column(Date) def __repr__(self): return 'Enrol(%s, %s, %s, %s)' % (self.person_id, self.enrol_date, self.group_id, self.level_id) class RosterLine(base): __tablename__ = 'roster_line' line_id = Column(String, primary_key=True) group_id= Column(String, nullable=False) class Timesheet(base): __tablename__ = 'timesheet' id = Column(Integer, primary_key=True) person_id = Column(String, nullable=False) line_id = Column(String, nullable=False) date= Column(Date, nullable=False) enrolment = relationship(Enrolment, primaryjoin=lambda:( (Timesheet.person_id == foreign(Enrolment.person_id)) (Timesheet.date = Enrolment.enrol_date) ((Timesheet.date Enrolment.next_date) | (Enrolment.next_date == None)) # (Timesheet.line_id == RosterLine.line_id) # (RosterLine.group_id == Enrolment.group_id) ), #uselist=False, viewonly=True) e = create_engine('sqlite://', echo=True) base.metadata.create_all(e) db = Session(e) db.add(RosterLine(line_id='work', group_id='staff')) db.add(RosterLine(line_id='etc', group_id='manager')) db.add(Enrolment(person_id='bob', group_id='staff', level_id='normal', enrol_date=date(2010,1,1), next_date=date(2011,1,1))) db.add(Enrolment(person_id='bob', group_id='staff', level_id='better', enrol_date=date(2011,1,1)))
Re: [sqlalchemy] many-to-one relationship with intermediate table non equijoin
create a non primary mapper to a select() that's against the Enrolment table joined to RosterLine (i.e. mapper(myselect.alias(), non_primary=True), then construct a relationship() to that mapper (viewonly=True of course). at some point I should add an example of this technique, it's just the easiest way to deal with the relationship-across-any-number-of-tables use case. On Aug 14, 2013, at 2:30 PM, avdd adr...@gmail.com wrote: Hello all Tried for hours to figure out the various relationship() options with no luck. Consider: class Enrolment(base): __tablename__ = 'enrolment' person_id = Column(String, primary_key=True) group_id= Column(String, primary_key=True) enrol_date = Column(Date, primary_key=True) level_id= Column(String, nullable=False) next_date = Column(Date) def __repr__(self): return 'Enrol(%s, %s, %s, %s)' % (self.person_id, self.enrol_date, self.group_id, self.level_id) class RosterLine(base): __tablename__ = 'roster_line' line_id = Column(String, primary_key=True) group_id= Column(String, nullable=False) class Timesheet(base): __tablename__ = 'timesheet' id = Column(Integer, primary_key=True) person_id = Column(String, nullable=False) line_id = Column(String, nullable=False) date= Column(Date, nullable=False) enrolment = relationship(Enrolment, primaryjoin=lambda:( (Timesheet.person_id == foreign(Enrolment.person_id)) (Timesheet.date = Enrolment.enrol_date) ((Timesheet.date Enrolment.next_date) | (Enrolment.next_date == None)) # (Timesheet.line_id == RosterLine.line_id) # (RosterLine.group_id == Enrolment.group_id) ), # uselist=False, viewonly=True) The relationship as it stands works correctly but I can't figure out the magic words to introduce the intermediate join to RosterLine. The relationship should issue SQL like: select E.* fromroster_line L, enrolment E where L.line_id = 'work' and L.group_id = E.group_id and E.person_id = 'bob' and E.enrol_date = '2012-03-04' and (E.next_date '2012-03-04' or E.next_date is null) Eternally grateful for any help. Thanks. -- 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 http://groups.google.com/group/sqlalchemy. For more options, visit https://groups.google.com/groups/opt_out. myrelation.py signature.asc Description: Message signed with OpenPGP using GPGMail
Re: [sqlalchemy] Updating a one-to-many relationship
Simon, your idea about putting together a script is a good one. Please see the attached. I think all these errors are related but I'm scratching my head about what the problem is. The reason I use self.creator[0] versus self.creator is for aesthetics. And, to your point about creator not being a list, SQLAlchemy is treating creator as a list-like object. Since any company can only have one creator, I wasn't concerned about indexing creator[0]. a=session.query(Company).first() a Company1, created by mike rather than a=session.query(Company).first() a Company1, created by [mike] a.creator [mike] More info on creator: type(a.creator) class 'sqlalchemy.orm.collections.InstrumentedList' type(a.creator[0]) class '__main__.Creator' Chris On Wednesday, August 14, 2013 6:18:51 AM UTC-4, Simon King wrote: I think you may be confused about the relationship properties you have here. As far as I can tell, a Creator can have many companies, but each Company has only one creator, correct? So Company.creator should only ever be an instance of Creator (or None), whereas Creator.companies should be a list. In your __repr__ example: class Creator(Base): def __repr__(self): return '%s' % self.creator class Company(Base): def __repr__(self): return '%s, created by %s' % (self.company, self.creator[0]) Why are you using self.creator[0] here? self.creator is not a list, it should either be an instance of Creator, or None. Overriding __repr__ is also a good way to make debugging difficult. For example, if you had a list of Creator instances and you printed them at the python prompt, it would just look like a list of strings. When I want extra information from __repr__, I normally write it something like this: def __repr__(self): classname = type(self).__name__ return '%s name=%r' % (classname, self.name) In your second example: a=session.query(Creator).first() a[0].companies a.companies Query.first() returns a single value, not a list. So typing a[0] doesn't make any sense. Please try to create a self-contained script that demonstrates your problem. Here is a good example: https://groups.google.com/d/msg/sqlalchemy/jQtIRJXVfH8/LgwX-bomEIQJ Thanks, Simon On Wed, Aug 14, 2013 at 2:45 AM, csd...@gmail.com javascript: wrote: I'm afraid there are still some bugs in here that hopefully you can help with. class Creator(Base): __tablename__ = creators id = Column(Integer, primary_key = True) company_id = Column(Integer, ForeignKey('companies.id')) creator = Column(String(100), nullable=False, unique=True) def __init__(self, creator): self.creator = creator def __repr__(self): return '%s' % self.creator # otherwise returns a single entry list for some reason (e.g. would display [user]) class Company(Base): __tablename__ = companies id = Column(Integer, primary_key = True) company = Column(String(100), unique=True, nullable=False) #might want to revise string sizes at some point creator = relationship(Creator, backref=companies, cascade=all) def __init__(self, company, creator): self.company = company #self.creator.append(Creator(creator)) existing_creator = session.query(Creator).filter_by(creator=creator).first() #self.creator.append(existing_creator or Creator(creator)) if existing_creator: print True self.creator.append(existing_creator) else: self.creator.append(Creator(creator)) def __repr__(self): return '%s, created by %s' % (self.company, self.creator[0]) 1) Weird __repr__ error: class Creator(Base): def __repr__(self): return '%s' % self.creator class Company(Base): def __repr__(self): return '%s, created by %s' % (self.company, self.creator[0]) c=Company(Company1, mike) session.add(c) c=Company(Company2, mike) True session.add(c) c=Company(Company3, john) session.add(c) c=Company(Company4, mike) True session.add(c) session.query(Company).all() [Traceback (most recent call last): File stdin, line 1, in module File stdin, line 17, in __repr__ However, if I divide the query lines among every add() statement, there is no __repr__ error. c=Company(Company1, mike) session.add(c) session.query(Company).all() [Company1, created by mike] c=Company(Company2, mike) True session.add(c) session.query(Company).all() [Company1, created by mike, Company2, created by mike] c=Company(Company3, john) session.add(c) session.query(Company).all() [Company1, created by mike, Company2, created by mike, Company3, created by john] c=Company(Company4, mike) True session.add(c)
[sqlalchemy] Under what circumstances will a `inspect(myobject).attrs.myattribute.history` be a sequence of more than one item ?
As previously discussed, i'm using an object's history to log changes to the database within an application. http://docs.sqlalchemy.org/en/rel_0_8/orm/session.html?highlight=history#sqlalchemy.orm.attributes.History Each tuple member is an iterable sequence I'm trying to figure out when I would expect that sequence to have more than 1 item in it. My guess is that for object relationships, it might contain a list of more than one element -- but for column data it would only be a single element. is that correct or am I off ? -- 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 http://groups.google.com/group/sqlalchemy. For more options, visit https://groups.google.com/groups/opt_out.
[sqlalchemy] TypeDecorator to store bool as ENUM('N', 'Y')?
I'm working with an existing MySQL schema that has lots of columns of type ENUM('N', 'Y'). I'd like to deal with them as real booleans on the python side. I have a simple TypeDecorator which almost works (I think): class YNBoolean(sqlalchemy.types.TypeDecorator): impl = mysql.ENUM('N', 'Y', charset='ascii') def process_bind_param(self, value, dialect): if value is None: return value return 'Y' if value else 'N' def process_result_value(self, value, dialect): if value is None: return None return value == 'Y' The one problem I've discovered with this is that session.query(MyTable).filter(MyTable.ynbool) produces a query like SELECT ... FROM MyTable WHERE MyTable.ynbool; What I really want is SELECT ... FROM MyTable WHERE MyTable.ynbool = 'Y'; (If I do .filter(MyTable.ynbool == True) that does work as desired/expected.) Is there a way to customize how my column gets compiled when used in an expression in a boolean context? (If not, I can live with it as is. I'll just get surprised once in awhile when I forget that treating the column as a boolean in expressions won't work.) Thank you for any help. Jeff -- 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 http://groups.google.com/group/sqlalchemy. For more options, visit https://groups.google.com/groups/opt_out.
[sqlalchemy] Re: many-to-one relationship with intermediate table non equijoin
Thanks for the quick response! After much fiddling I got it working using alias(), foreign() and corresponding_column(). It seems to get the right results. Is this the simplest, right approach? joined = Enrolment.__table__.join(RosterLine, Enrolment.group_id==RosterLine.group_id).alias() cc = joined.corresponding_column secmapper = mapper(Enrolment, joined, non_primary=True) # ... enrolment = relationship(secmapper, primaryjoin=lambda:( (Timesheet.line_id == foreign(cc(RosterLine.line_id))) (Timesheet.person_id == cc(Enrolment.person_id)) (Timesheet.date = cc(Enrolment.enrol_date)) ((Timesheet.date cc(Enrolment.next_date)) | (cc(Enrolment.next_date) == None)) ), uselist=False, viewonly=True) On Thursday, 15 August 2013 04:30:12 UTC+10, avdd wrote: Hello all Tried for hours to figure out the various relationship() options with no luck. Consider: class Enrolment(base): __tablename__ = 'enrolment' person_id = Column(String, primary_key=True) group_id= Column(String, primary_key=True) enrol_date = Column(Date, primary_key=True) level_id= Column(String, nullable=False) next_date = Column(Date) def __repr__(self): return 'Enrol(%s, %s, %s, %s)' % (self.person_id, self.enrol_date, self.group_id, self.level_id) class RosterLine(base): __tablename__ = 'roster_line' line_id = Column(String, primary_key=True) group_id= Column(String, nullable=False) class Timesheet(base): __tablename__ = 'timesheet' id = Column(Integer, primary_key=True) person_id = Column(String, nullable=False) line_id = Column(String, nullable=False) date= Column(Date, nullable=False) enrolment = relationship(Enrolment, primaryjoin=lambda:( (Timesheet.person_id == foreign(Enrolment.person_id)) (Timesheet.date = Enrolment.enrol_date) ((Timesheet.date Enrolment.next_date) | (Enrolment.next_date == None)) # (Timesheet.line_id == RosterLine.line_id) # (RosterLine.group_id == Enrolment.group_id) ), # uselist=False, viewonly=True) The relationship as it stands works correctly but I can't figure out the magic words to introduce the intermediate join to RosterLine. The relationship should issue SQL like: select E.* fromroster_line L, enrolment E where L.line_id = 'work' and L.group_id = E.group_id and E.person_id = 'bob' and E.enrol_date = '2012-03-04' and (E.next_date '2012-03-04' or E.next_date is null) Eternally grateful for any help. Thanks. -- 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 http://groups.google.com/group/sqlalchemy. For more options, visit https://groups.google.com/groups/opt_out.
[sqlalchemy] how to tell which columns are deferred in orm ?
i'm trying to generate a list of non-deffered columns from an object referencing this example: class Book(Base): __tablename__ = 'book' book_id = Column(Integer, primary_key=True) title = Column(String(200), nullable=False) summary = Column(String(2000)) excerpt = deferred(Column(Text)) photo = deferred(Column(Binary)) how can I tell , when dealing with an instance of `Book()`, which columns are deferred or not ? i tried inspecting virtually everything in: class_mapper(Book)) and looked over these multiple times: class_mapper(Book).mapped_table) class_mapper(Book).mapped_table.c) but couldn't seem to find anything that works. -- 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 http://groups.google.com/group/sqlalchemy. For more options, visit https://groups.google.com/groups/opt_out.
[sqlalchemy] Re: DeferredReflection and mapper
On Wednesday, August 14, 2013 12:10:12 AM UTC-5, Lukasz Szybalski wrote: Hello, How do I go from class like defeinition to below with mapper. The docs in 0.8 say I can use: from sqlalchemy.ext.declarative import DeferredReflectionBase = declarative_base() class MyClass(DeferredReflection, Base): __tablename__ = 'mytable' but how do I do below with DefferedReflection -- from sqlalchemy import Table from sqlalchemy.orm import mapper, relation class Recall(object): def __init__(self, **kw): automatically mapping attributes for key, value in kw.iteritems(): setattr(self, key, value) recall_table = Table('recall_db', metadata, autoload=True,autoload_with=engine) mapper(Recall, recall_table,primary_key=[recall_table.c.RECORD_ID]) I'm using pyramid, and I want to autoload tables in models.py which does not have the engine bound yet. I will bind in in main function with DeferredReflection.prepare(engine) Never mind: I followed the documentation: In models.py I did from sqlalchemy.ext.declarative import DeferredReflection class Recall(DeferredReflection, Base): __tablename__ = 'recall_db' in __init__.py I did from sqlalchemy.ext.declarative import DeferredReflection then under Base.metadata.bind = engine add DeferredReflection.prepare(engine) I can access the table with Recall.__table__ and mapper with Recall.__mapper__ I presume this does the same as : recall_table = Table('recall_db', metadata, autoload=True,autoload_with= engine) class Recall(object): def __init__(self, **kw): automatically mapping attributes for key, value in kw.iteritems(): setattr(self, key, value) mapper(Recall, recall_table,primary_key=[recall_table.c.RECORD_ID]) Thanks Lucas -- 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 http://groups.google.com/group/sqlalchemy. For more options, visit https://groups.google.com/groups/opt_out.
Re: [sqlalchemy] Under what circumstances will a `inspect(myobject).attrs.myattribute.history` be a sequence of more than one item ?
yes it will always be one element for a scalar reference, a collection for collections. the ORM internally treats everything like a collection, kind of another artifact that probably wouldnt have been the case if this API were written for end-users originally... On Aug 14, 2013, at 9:20 PM, Jonathan Vanasco jvana...@gmail.com wrote: As previously discussed, i'm using an object's history to log changes to the database within an application. http://docs.sqlalchemy.org/en/rel_0_8/orm/session.html?highlight=history#sqlalchemy.orm.attributes.History Each tuple member is an iterable sequence I'm trying to figure out when I would expect that sequence to have more than 1 item in it. My guess is that for object relationships, it might contain a list of more than one element -- but for column data it would only be a single element. is that correct or am I off ? -- 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 http://groups.google.com/group/sqlalchemy. For more options, visit https://groups.google.com/groups/opt_out. signature.asc Description: Message signed with OpenPGP using GPGMail