Re: [sqlalchemy] get to dialect specific column type
I tried with a hack to get to this, but still no luck. I am doing: from sqlalchemy.dialects.firebird import dialect ... fbDialect = dialect() ... if str(col.type) == 'DATETIME': print col.type.dialect_impl(fbDialect) print col.type.get_dbapi_type(fbDialect) The first one gives me DATETIME and the second throws this exception. Traceback (most recent call last): File saCreateDb.py, line 5, in module import model as db File C:\dev\aaTests\sqla\i18nFB\model.py, line 116, in module class Country_LV(Base): File C:\dev\aaTests\sqla\i18nFB\model.py, line 117, in Country_LV __table__ = sautils.make_localize_view(Country(), Country_L(), Language(), metadata) File C:\dev\aaTests\sqla\i18nFB\sautils.py, line 181, in make_localize_view storedProc = doCreateLocaleStoredProc(baseinst, baseTable, localeTable, localeLangCol, localeFK, procName) File C:\dev\aaTests\sqla\i18nFB\sautils.py, line 31, in doCreateLocaleStoredProc print col.type.get_dbapi_type(fbDialect) File c:\python26\lib\site-packages\sqlalchemy-0.6.4-py2.6.egg\sqlalchemy\types.py, line 1191, in get_dbapi_type return dbapi.DATETIME AttributeError: 'FBDialect_kinterbasdb' object has no attribute 'DATETIME' What am I doing wrong here? And is there a cleaner way of doing this, i.e. get the dialect currently used instead of using a hard coded dialect. On 20/09/2010 23:52, werner wrote: I am trying to automatically generate the stored procedure I need for the localize stuff. So, would like to do something like this: aninst.__table__.c['created_at'].type.get_dbapi_type(dbapi) - to get e.g. TIMESTAMP for a DateTime column with Firebird SQL. What is the most efficient/easy way to get at dbapi from e.g. an instance? Isn't there some more elegant way then doing connection.engine.dialect.dbapi? Werner -- You received this message because you are subscribed to the Google Groups sqlalchemy group. To post to this group, send email to sqlalch...@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] declarative - automatically add a primary key if the table doesn't have one
This is related to topic need 0.6_beta2-compat declarative meta http://groups.google.com/group/sqlalchemy/browse_thread/thread/ae7cb9d2ab0b9cca Prior to version 0.6, I use the following code to automatically add a primary key if the table doesn't have one defined: from sqlalchemy.ext.declarative import declarative_base, DeclarativeMeta from sqlalchemy.schema import Column from sqlalchemy.types import Integer class Meta(DeclarativeMeta): def __init__(cls, classname, bases, dict_): for attr in dict_.itervalues(): if isinstance(attr, Column) and attr.primary_key: break else: dict_['id'] = Column(Integer, primary_key=True) return super(Meta, cls).__init__(classname, bases, dict_) Base = declarative_base(metaclass=Meta) Of course, that doesn't work anymore in 0.6. The suggestion from the aforementioned threads is to replace: dict_['id'] = Column(Integer, primary_key=True) with cls.id = Column(Integer, primary_key=True) Unfortunately, that alone doesn't work in this case. The problem is that the Base class itself will be the first one to go through the Meta.__init__() method, so the whole thing essentially becomes: Base.id = Column(Integer, primary_key=True) For it to work, I have to wrap the code in an if-block, i.e. class Meta(DeclarativeMeta): def __init__(cls, classname, bases, dict_): if classname != 'Base': for attr in dict_.itervalues(): if isinstance(attr, Column) and attr.primary_key: break else: cls.id = Column(Integer, primary_key=True) return super(Meta, cls).__init__(classname, bases, dict_) which looks rather ugly. Is there a cleaner way to achieve this? -- You received this message because you are subscribed to the Google Groups sqlalchemy group. To post to this group, send email to sqlalch...@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] Empty a record
On Sep 21, 2010, at 11:51 PM, Michael Hipp wrote: On 9/21/2010 8:17 PM, Michael Bayer wrote: It definitely does not attempt an INSERT if id_ is set to a non-None value, assuming that row already exists in the DB, without something else in your model/usage causing that to happen.If id_ is None or the given id_ doesn't exist in the DB, you get an INSERT. auct_id has no direct effect here. that also makes no sense since if you set auct_id manually, assuming old.auct_id is not None, it wouldn't be None in the UPDATE statement. These behaviors (opposite what we expect) are what I'm indeed seeing. As usual, distilling down the behavior that appears wrong into a single file Attached. I'll be thrilled if you can figure out what really stupid thing I'm doing to cause this. As always, many thanks for your help. So here, the value of None for car.auction, merges into the session which becomes a pending change. The flush overwrites car.auct_id with None because car.auction has been set to None. The merge() process takes everything that is present on the incoming object and assigns it to the object that's in the session. So here when merge sets old.auction = None, this is the effect. So you want to merge an object where every attribute is either exactly the value that you want it to be, or it is not loaded or assigned to in any way (i.e. not present in __dict__). If you pop auction from __dict__ before the merge, or just don't assign to auction in the contructor of Car and also dont issue a print car.auction later on, the program succeeds. So for example, this works: new = Car() new.id_ = old.id_ new.lane = old.lane new = sess.merge(new) sess.commit() if you took the None assignments out of the constructor, all you need is id_ and leave everything else untouched, and it succeeds. So the other thing, with the INSERT, you need to look at stack traces when these things happen: File empty.py, line 72, in module new = sess.merge(new) File sqlalchemy/orm/session.py, line 1165, in merge self._autoflush() File sqlalchemy/orm/session.py, line 863, in _autoflush anytime you see _autoflush in a stack trace, that means that some state is in the session that you don't want it to be, and _autoflush is trying to push it out before its ready. That a car row is being INSERTed during autoflush, means that a Car object has been added to the session. The first thing you do is then ask new in sess to see if that's the case. Here, the issue is that you're mixing the usage of merge() with the usage of objects that are already in the session. new is added to the session via cascade: new = Car() new.id_ = old.id_ new.lane = old.lane new.auct_id = old.auct_id new.auction = old.auction assert new in sess # passes The ways to get around that effect are: - pass cascade=None to your 'cars' backref - this means, when you set somecar.auction = someauction, someauction is already in the session, 'somecar' doesn't get added automatically. cascade also affects what merge() does along relationships so when changing this make sure it has the cascades that you still want. - expunge new before you merge() it, but that's kind of messy. - don't set any relationships that are going to cascade it into the session I think the general rule is to compose the object for merge() carefully so that it only contains what state you want to be merged. None counts as state. I definitely want to add a note about what the state of the given instance is copied means, regarding things in __dict__. Michael -- You received this message because you are subscribed to the Google Groups sqlalchemy group. To post to this group, send email to sqlalch...@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. empty.py -- You received this message because you are subscribed to the Google Groups sqlalchemy group. To post to this group, send email to sqlalch...@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] declarative - automatically add a primary key if the table doesn't have one
On Sep 22, 2010, at 4:30 AM, Yap Sok Ann wrote: This is related to topic need 0.6_beta2-compat declarative meta http://groups.google.com/group/sqlalchemy/browse_thread/thread/ae7cb9d2ab0b9cca Prior to version 0.6, I use the following code to automatically add a primary key if the table doesn't have one defined: from sqlalchemy.ext.declarative import declarative_base, DeclarativeMeta from sqlalchemy.schema import Column from sqlalchemy.types import Integer class Meta(DeclarativeMeta): def __init__(cls, classname, bases, dict_): for attr in dict_.itervalues(): if isinstance(attr, Column) and attr.primary_key: break else: dict_['id'] = Column(Integer, primary_key=True) return super(Meta, cls).__init__(classname, bases, dict_) Base = declarative_base(metaclass=Meta) Of course, that doesn't work anymore in 0.6. The suggestion from the aforementioned threads is to replace: dict_['id'] = Column(Integer, primary_key=True) with cls.id = Column(Integer, primary_key=True) Unfortunately, that alone doesn't work in this case. The problem is that the Base class itself will be the first one to go through the Meta.__init__() method, so the whole thing essentially becomes: Base.id = Column(Integer, primary_key=True) For it to work, I have to wrap the code in an if-block, i.e. class Meta(DeclarativeMeta): def __init__(cls, classname, bases, dict_): if classname != 'Base': for attr in dict_.itervalues(): if isinstance(attr, Column) and attr.primary_key: break else: cls.id = Column(Integer, primary_key=True) return super(Meta, cls).__init__(classname, bases, dict_) which looks rather ugly. Is there a cleaner way to achieve this? I didn't think metaclasses were supposed to be pretty ?Checking that you're not the base is pretty standard metaclass stuff. If the hardcoded name is the issue, you can look in bases: if object not in bases: or something more generic: for k in cls.__mro__[1:]: if isinstance(k, Meta): # you're a Base subclass -- You received this message because you are subscribed to the Google Groups sqlalchemy group. To post to this group, send email to sqlalch...@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 sqlalch...@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] get to dialect specific column type
On Sep 22, 2010, at 3:06 AM, werner wrote: I tried with a hack to get to this, but still no luck. I am doing: from sqlalchemy.dialects.firebird import dialect ... fbDialect = dialect() ... if str(col.type) == 'DATETIME': print col.type.dialect_impl(fbDialect) print col.type.get_dbapi_type(fbDialect) The first one gives me DATETIME and the second throws this exception. Traceback (most recent call last): File saCreateDb.py, line 5, in module import model as db File C:\dev\aaTests\sqla\i18nFB\model.py, line 116, in module class Country_LV(Base): File C:\dev\aaTests\sqla\i18nFB\model.py, line 117, in Country_LV __table__ = sautils.make_localize_view(Country(), Country_L(), Language(), metadata) File C:\dev\aaTests\sqla\i18nFB\sautils.py, line 181, in make_localize_view storedProc = doCreateLocaleStoredProc(baseinst, baseTable, localeTable, localeLangCol, localeFK, procName) File C:\dev\aaTests\sqla\i18nFB\sautils.py, line 31, in doCreateLocaleStoredProc print col.type.get_dbapi_type(fbDialect) File c:\python26\lib\site-packages\sqlalchemy-0.6.4-py2.6.egg\sqlalchemy\types.py, line 1191, in get_dbapi_type return dbapi.DATETIME AttributeError: 'FBDialect_kinterbasdb' object has no attribute 'DATETIME' What am I doing wrong here? And is there a cleaner way of doing this, i.e. get the dialect currently used instead of using a hard coded dialect. On 20/09/2010 23:52, werner wrote: I am trying to automatically generate the stored procedure I need for the localize stuff. So, would like to do something like this: aninst.__table__.c['created_at'].type.get_dbapi_type(dbapi) - to get e.g. TIMESTAMP for a DateTime column with Firebird SQL. what is the piece of information you ultimately want ? I'm not sure what you need the DBAPI type tokens for, unless you are working with the DBAPI's cursor object directly (in which case, you're working with the DBAPI already...dbapi.DATETIME ? if you're generating a stored procedure you're already well within the realm of non-DB-agnostic). Isn't there some more elegant way then doing connection.engine.dialect.dbapi? there's import kintersbasdb -- You received this message because you are subscribed to the Google Groups sqlalchemy group. To post to this group, send email to sqlalch...@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] get to dialect specific column type
I try to explain in more detail what I am trying to do. class Country(Base, CreateUpdateMixin): __tablename__ = u'countries' id = sa.Column(sa.BigInteger(), sa.Sequence('countries_id'), primary_key=True, nullable=False) name = sa.Column(sa.String(length=30, convert_unicode=False)) iso2 = sa.Column(sa.String(length=2, convert_unicode=False)) iso3 = sa.Column(sa.String(length=3, convert_unicode=False)) telcode = sa.Column(sa.SmallInteger()) __localize_columns__ = ['name', ] class Country_L(Base): __table__ = sautils.make_localize_table(Country, 'countries_l', Language, metadata) language = sao.relation(Language, backref='country_l') country = sao.relation(Country, backref='country_l') class Country_LV(Base): __table__ = sautils.make_localize_view(Country(), Country_L(), Language(), metadata) Witin make_localize_view I need to generate a stored procedure which gets information such as columns etc from Country and Country_L , the generated code looks like this: CREATE OR ALTER PROCEDURE countries_lp returns (created_at DATE, updated_at TIMESTAMP, id BIGINT, name VARCHAR(30), iso2 VARCHAR(2), iso3 VARCHAR(3), telcode SMALLINT) as declare variable locale_name VARCHAR(30); begin for select created_at, updated_at, id, name, iso2, iso3, telcode from countries into :created_at, :updated_at, :id, :name, :iso2, :iso3, :telcode do begin begin locale_name = Null; select name from countries_l where :id = countries_l.fk_countries_id and countries_l.fk_languages_code5 = rdb$get_context('USER_SESSION', 'LANG_CODE') into :name; end if (:locale_name is not Null) then begin name = :locale_name; end suspend; end end part of the code to generate the above is the following: for col in basetable.c: if str(col.type) == 'DATETIME': # hack as I can't figure out a nicer/cleaner way colType = 'TIMESTAMP' basetable = Country.__table__ What I like to do is replace the check for DATETIME with similar/same code I assume meta.create_all(engine) is using to generate create table (can't yet figure out where/how this is all done) and ideally this should work not only for Firebird engine. Hope this is clearer. Thanks for looking at all this. Werner -- You received this message because you are subscribed to the Google Groups sqlalchemy group. To post to this group, send email to sqlalch...@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] Empty a record
On 9/22/2010 10:27 AM, Michael Bayer wrote: Michael, thanks so much for taking the time to compose a very thorough answer. If you could indulge a few clarifications/suggestions ... So here, the value of None for car.auction, merges into the session which becomes a pending change. The flush overwrites car.auct_id with None because car.auction has been set to None. The merge() process takes everything that is present on the incoming object and assigns it to the object that's in the session. So here when merge sets old.auction = None, this is the effect. So you want to merge an object where every attribute is either exactly the value that you want it to be, or it is not loaded or assigned to in any way (i.e. not present in __dict__). If you pop auction from __dict__ before the merge, or just don't assign to auction in the contructor of Car and also dont issue a print car.auction later on, the program succeeds. I have been putting more and more things in the constructors for 2 reasons: 1) It's really convenient esp in unit tests to be able to spec everything on 1 line when creating a lot of objects at once. 2) It has always been good business in Python to make sure all instance vars are given a default value as early as possible. But here, that harmless act of setting auction=None actually triggers things to happen that go considerably beyond my simplistic notion of just making sure things have a default value. This is the 2nd time in as many days that I've been tripped-up by having things in the constructor that didn't *have* to be there. But only now am I coming to realize why. Some explanation of or warning about this in the docs would seem appropriate. As I look over the declarative tutorial, it is somewhat implied that every column should be set in the constructor: http://www.sqlalchemy.org/docs/orm/tutorial.html#creating-table-class-and-mapper-all-at-once-declaratively Here, the issue is that you're mixing the usage of merge() with the usage of objects that are already in the session. new is added to the session via cascade: new = Car() new.id_ = old.id_ new.lane = old.lane new.auct_id = old.auct_id new.auction = old.auction assert new in sess # passes The ways to get around that effect are: - pass cascade=None to your 'cars' backref - this means, when you set somecar.auction = someauction, someauction is already in the session, 'somecar' doesn't get added automatically. cascade also affects what merge() does along relationships so when changing this make sure it has the cascades that you still want. - expunge new before you merge() it, but that's kind of messy. - don't set any relationships that are going to cascade it into the session On that last note I found that if I do: new = Car() new.id_ = old.id_ new = sess.merge(new) new.auction = old.auction # do this *after* merge sess.commit() This seems to work and avoids me having to deal with the cascade stuff (which I don't understand) just yet. Any worries with this approach? I definitely want to add a note about what the state of the given instance is copied means, regarding things in __dict__. Some explanation of how things get in __dict__ and what their presence there means would help us noobs. Also, is it really a good idea to go hacking on __dict__ (e.g. popping things out as mentioned above)? Again, thanks, Michael -- You received this message because you are subscribed to the Google Groups sqlalchemy group. To post to this group, send email to sqlalch...@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] get to dialect specific column type
On Sep 22, 2010, at 12:19 PM, werner wrote: Witin make_localize_view I need to generate a stored procedure which gets information such as columns etc from Country and Country_L , the generated code looks like this: CREATE OR ALTER PROCEDURE countries_lp returns (created_at DATE, updated_at TIMESTAMP, id BIGINT, name VARCHAR(30), iso2 VARCHAR(2), iso3 VARCHAR(3), telcode SMALLINT) as declare variable locale_name VARCHAR(30); begin for select created_at, updated_at, id, name, iso2, iso3, telcode from countries into :created_at, :updated_at, :id, :name, :iso2, :iso3, :telcode do begin begin locale_name = Null; select name from countries_l where :id = countries_l.fk_countries_id and countries_l.fk_languages_code5 = rdb$get_context('USER_SESSION', 'LANG_CODE') into :name; end if (:locale_name is not Null) then begin name = :locale_name; end suspend; end end part of the code to generate the above is the following: for col in basetable.c: if str(col.type) == 'DATETIME': # hack as I can't figure out a nicer/cleaner way colType = 'TIMESTAMP' basetable = Country.__table__ What I like to do is replace the check for DATETIME with similar/same code I assume meta.create_all(engine) is using to generate create table (can't yet figure out where/how this is all done) and ideally this should work not only for Firebird engine. Hope this is clearer. nothing to do with DBAPI or their types. Call str(col.type) will give you its default compilation. Call str(col.type.compile(dialect=firebird.dialect()) will give you whatever firebird does with those types. -- You received this message because you are subscribed to the Google Groups sqlalchemy group. To post to this group, send email to sqlalch...@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] Empty a record
On Sep 22, 2010, at 12:21 PM, Michael Hipp wrote: On that last note I found that if I do: new = Car() new.id_ = old.id_ new = sess.merge(new) new.auction = old.auction # do this *after* merge sess.commit() This seems to work and avoids me having to deal with the cascade stuff (which I don't understand) just yet. Any worries with this approach? I'm only worried that you don't understand the cascade behavior. It is this: c = Car() a = Auction() session.add(a) c is not in the session, a is. c.auction = a this assigns c.auction, and because you have auction.cars as a backref, it appends to the cars collection. The same is if you said: auction.cars.append(c) So now, c is in the session, as is a. auction.cars has a default cascade of save-update. Anything appended to this list, gets added to the same session as that of auction. That's cascade. I'm adding an option to relationship, cascade_backrefs=False, which will prevent save-update cascade from firing off on a backref. I definitely want to add a note about what the state of the given instance is copied means, regarding things in __dict__. Some explanation of how things get in __dict__ and what their presence there means would help us noobs. this is mentioned right near the start of the tutorial: http://www.sqlalchemy.org/docs/orm/tutorial.html#setting-up-the-mapping str(ed_user.id) 'None' any attribute accessed defaults to None. Also, is it really a good idea to go hacking on __dict__ (e.g. popping things out as mentioned above)? no. use del obj.attribute instead. -- You received this message because you are subscribed to the Google Groups sqlalchemy group. To post to this group, send email to sqlalch...@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] Empty a record
here's your new section: http://www.sqlalchemy.org/docs/orm/session.html#merge-tips -- You received this message because you are subscribed to the Google Groups sqlalchemy group. To post to this group, send email to sqlalch...@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] Change echo at will
On 8/26/2010 8:55 PM, Mike Conley wrote: On Thu, Aug 26, 2010 at 4:21 PM, Michael Hipp mich...@hipp.com mailto:mich...@hipp.com wrote: Is there a way to set 'echo' at any time? Everything I can find sets it when the engine is created and doesn't seem to change it afterward. You can assign the engine.echo property to True or False any time after creating the engine. Is there something that would trigger this to be recognized? In trying to use this to see the sql from a key piece of code it seems if I have to do the engine.echo=True well in advance of when I want it to start; and similarly I need to wait well after I want it to stop before I set it to False. Otherwise I miss stuff. Thanks, Michael -- You received this message because you are subscribed to the Google Groups sqlalchemy group. To post to this group, send email to sqlalch...@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] Empty a record
On 9/22/2010 11:21 AM, Michael Hipp wrote: new = Car() new.id_ = old.id_ new = sess.merge(new) new.auction = old.auction # do this *after* merge sess.commit() This seems to work and ... Bah. I spoke too soon - it just doesn't throw an exception. But without explicitly setting every field to its default value, the session thinks nothing has changed and the UPDATE leaves most of the fields untouched. Anyway, it appears I need a new approach to empty/blank a record. Options I can think of are: 1) Find a dict of all the default values for every field and set them explicitly. Does SQLAlchemy have that somewhere? 2) What about an approach of forcing a DELETE, INSERT, COMMIT on the old/new objects. Like this: session.begin(subtransactions=True) id_ = old.id_ # grab important stuff from 'old' auct = old.auction session.delete(old) # kill old session.commit() new = Car() new.id_ = id_ new.auction = auct new = session.merge(new) session.commit() But I'm worried about side effects and issues with the version_id_col. Any thoughts appreciated... Michael -- You received this message because you are subscribed to the Google Groups sqlalchemy group. To post to this group, send email to sqlalch...@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] Change echo at will
the logging level is checked on each new connection, so yes you can set echo at any time. On Sep 22, 2010, at 4:46 PM, Michael Hipp wrote: On 8/26/2010 8:55 PM, Mike Conley wrote: On Thu, Aug 26, 2010 at 4:21 PM, Michael Hipp mich...@hipp.com mailto:mich...@hipp.com wrote: Is there a way to set 'echo' at any time? Everything I can find sets it when the engine is created and doesn't seem to change it afterward. You can assign the engine.echo property to True or False any time after creating the engine. Is there something that would trigger this to be recognized? In trying to use this to see the sql from a key piece of code it seems if I have to do the engine.echo=True well in advance of when I want it to start; and similarly I need to wait well after I want it to stop before I set it to False. Otherwise I miss stuff. Thanks, Michael -- You received this message because you are subscribed to the Google Groups sqlalchemy group. To post to this group, send email to sqlalch...@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 sqlalch...@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] Empty a record
On Sep 22, 2010, at 5:17 PM, Michael Hipp wrote: On 9/22/2010 11:21 AM, Michael Hipp wrote: new = Car() new.id_ = old.id_ new = sess.merge(new) new.auction = old.auction # do this *after* merge sess.commit() This seems to work and ... Bah. I spoke too soon - it just doesn't throw an exception. that absolutely does what you tell it (guess thats not what you want). Make sure Car's init is: def __init__(self, lane=None, make='', auction=None): self.lane = lane self.make = make if auction is not None: self.auction = auction then: new = Car() new.id_ = old.id_ new.lane = old.lane new = sess.merge(new) new.auction = old.auction sess.commit() SQL: UPDATE cars SET make=? WHERE cars.id_ = ? ('', 1) But without explicitly setting every field to its default value, the session thinks nothing has changed and the UPDATE leaves most of the fields untouched. Anyway, it appears I need a new approach to empty/blank a record. Options I can think of are: Here's the problem. The term a blank record is meaningless. You have to spell that out explicitly, on every class that has a concept of blank. Class A might consider fields x, y, z but not q, p, r to be part of blank, class B has some totally different idea. Whether or not database fields have a default configured at the database level or table metadata level is also an artificial constraint...sure flip through table.c and look at default /server_default if you want that, but I've never written an app that had rules even that simplistic. Trying to make other tools guess this for you seems to be taking up days of your time - whereas a simple def set_myself_blank(self) method OTOH would take 30 seconds. -- You received this message because you are subscribed to the Google Groups sqlalchemy group. To post to this group, send email to sqlalch...@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] Empty a record
On 9/22/2010 5:24 PM, Michael Bayer wrote: Here's the problem. The term a blank record is meaningless. Well, no, it's not. It's exactly what I get when I do new=Item() and commit(). It's very well defined, precise, and repeatable. Trying to make other tools guess this for you seems to be taking up days of your time - whereas a simple def set_myself_blank(self) method OTOH would take 30 seconds. I've been writing that 30 second method for 2 days now. So evidently it takes longer than that :-) Problem is that model has about 75 columns in it. Each Column() has a default='foo' parameter. And they are all unique to some extent. So I can *replicate* that information that is already there in a dict somewhere that will have 75 lines in it and then maintain it in sync with the official version. That is a severe violation of DRY and it will inevitably lead to bugs and possibly data corruption. Avoiding such seems a worthy goal. I apologize, truly, that I have greatly overused your assistance on this. Thank you. I have formulated a couple of hackish approaches that will probably work. Guess I'm stuck with them. :-) Michael -- You received this message because you are subscribed to the Google Groups sqlalchemy group. To post to this group, send email to sqlalch...@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] Empty a record
On Sep 22, 2010, at 6:44 PM, Michael Hipp wrote: On 9/22/2010 5:24 PM, Michael Bayer wrote: Here's the problem. The term a blank record is meaningless. Well, no, it's not. It's exactly what I get when I do new=Item() and commit(). It's very well defined, precise, and repeatable. Trying to make other tools guess this for you seems to be taking up days of your time - whereas a simple def set_myself_blank(self) method OTOH would take 30 seconds. I've been writing that 30 second method for 2 days now. So evidently it takes longer than that :-) Problem is that model has about 75 columns in it. Each Column() has a default='foo' parameter. And they are all unique to some extent. So I can *replicate* that information that is already there in a dict somewhere that will have 75 lines in it and then maintain it in sync with the official version. That is a severe violation of DRY and it will inevitably lead to bugs and possibly data corruption. Avoiding such seems a worthy goal. I apologize, truly, that I have greatly overused your assistance on this. Thank you. I have formulated a couple of hackish approaches that will probably work. Guess I'm stuck with them. :-) I guess, even though you've never stated this very clearly, that a blank record means, you'd like the default value for all columns reset to the default ? What if the default for a certain column is the current timestamp ? How are you going to recreate that ?Or somehting set by a sequence or other stored procedure where the original value is missing ? You probably don't have this issue but the idea of a blank record is still something somewhat specific to your situation. Anyway as I said, read through the columns on table.c and use default/server_default. -- You received this message because you are subscribed to the Google Groups sqlalchemy group. To post to this group, send email to sqlalch...@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: declarative - automatically add a primary key if the table doesn't have one
On Sep 22, 11:37 pm, Michael Bayer mike...@zzzcomputing.com wrote: On Sep 22, 2010, at 4:30 AM, Yap Sok Ann wrote: This is related to topic need 0.6_beta2-compat declarative meta http://groups.google.com/group/sqlalchemy/browse_thread/thread/ae7cb9... Prior to version 0.6, I use the following code to automatically add a primary key if the table doesn't have one defined: from sqlalchemy.ext.declarative import declarative_base, DeclarativeMeta from sqlalchemy.schema import Column from sqlalchemy.types import Integer class Meta(DeclarativeMeta): def __init__(cls, classname, bases, dict_): for attr in dict_.itervalues(): if isinstance(attr, Column) and attr.primary_key: break else: dict_['id'] = Column(Integer, primary_key=True) return super(Meta, cls).__init__(classname, bases, dict_) Base = declarative_base(metaclass=Meta) Of course, that doesn't work anymore in 0.6. The suggestion from the aforementioned threads is to replace: dict_['id'] = Column(Integer, primary_key=True) with cls.id = Column(Integer, primary_key=True) Unfortunately, that alone doesn't work in this case. The problem is that the Base class itself will be the first one to go through the Meta.__init__() method, so the whole thing essentially becomes: Base.id = Column(Integer, primary_key=True) For it to work, I have to wrap the code in an if-block, i.e. class Meta(DeclarativeMeta): def __init__(cls, classname, bases, dict_): if classname != 'Base': for attr in dict_.itervalues(): if isinstance(attr, Column) and attr.primary_key: break else: cls.id = Column(Integer, primary_key=True) return super(Meta, cls).__init__(classname, bases, dict_) which looks rather ugly. Is there a cleaner way to achieve this? I didn't think metaclasses were supposed to be pretty ? Checking that you're not the base is pretty standard metaclass stuff. If the hardcoded name is the issue, you can look in bases: if object not in bases: or something more generic: for k in cls.__mro__[1:]: if isinstance(k, Meta): # you're a Base subclass Good point. I shall stick with the name checking solution then. Thank you for your help. -- You received this message because you are subscribed to the Google Groups sqlalchemy group. To post to this group, send email to sqlalch...@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.