Hello Michael, On Sunday, March 16, 2014 10:19:16 PM UTC+1, Michael Bayer wrote: > > > > are you sure it’s actually saying “SET NULL” in the SQL? if the value > isn’t present in the params, that just means it’s leaving it unaffected. > this is normal behavior when the value hasn’t changed. > > I can’t say much else because these are only excerpts of code without > context. > > if you wanted to show, “stores a NULL”, send a full script that does that > and asserts it’s the case. >
Yes, I'm positive, SA explicitly SETs editor_id = NULL. Please find attached a stand-alone script. -- 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/d/optout.
#!/usr/bin/env python import logging import sqlalchemy as sa import sqlalchemy.orm import transaction import zope.sqlalchemy from sqlalchemy.ext.declarative import ( declared_attr, declarative_base ) logging.basicConfig(level=logging.INFO) lgg = logging.getLogger(__name__) salgg = logging.getLogger('sqlalchemy.engine') salgg.setLevel(logging.INFO) DbEngine = sa.create_engine("postgresql+psycopg2://test:test@localhost/test") DbSession = sa.orm.scoped_session( sa.orm.sessionmaker( extension=zope.sqlalchemy.ZopeTransactionExtension() ) ) DbSession.configure(bind=DbEngine) DbBase = declarative_base(bind=DbEngine) def _validate_editor(context): pass # if not context.current_parameters['editor_id']: # raise ValueError('Editor must be set on update.') class DefaultMixin(object): """Mixin to add Parenchym's standard fields to a model class. These are: id, ctime, owner, mtime, editor. """ id = sa.Column(sa.Integer(), primary_key=True, nullable=False) """Primary key of table.""" ctime = sa.Column(sa.DateTime(), server_default=sa.func.current_timestamp(), nullable=False) """Timestamp, creation time.""" # noinspection PyMethodParameters @declared_attr def owner_id(cls): """ID of user who created this record.""" return sa.Column( sa.Integer(), sa.ForeignKey( "pym.user.id", onupdate="CASCADE", ondelete="RESTRICT" ), nullable=False ) mtime = sa.Column(sa.DateTime(), onupdate=sa.func.current_timestamp(), nullable=True) """Timestamp, last edit time.""" # noinspection PyMethodParameters @declared_attr def editor_id(cls): """ID of user who was last editor.""" return sa.Column( sa.Integer(), sa.ForeignKey( "pym.user.id", onupdate="CASCADE", ondelete="RESTRICT" ), nullable=True, onupdate=_validate_editor ) class User(DbBase, DefaultMixin): __tablename__ = "user" __table_args__ = ( {'schema': 'pym'} ) principal = sa.Column(sa.Unicode(255), nullable=False) class Tenant(DbBase, DefaultMixin): """ A tenant. """ __tablename__ = "tenant" __table_args__ = ( sa.UniqueConstraint('name', name='tenant_ux'), {'schema': 'pym'} ) name = sa.Column(sa.Unicode(255), nullable=False) # Load description only if needed descr = sa.orm.deferred(sa.Column(sa.UnicodeText, nullable=True)) """Optional description.""" def __repr__(self): return "<{name}(id={id}, name='{n}'>".format( id=self.id, n=self.name, name=self.__class__.__name__) def setup(sess): with transaction.manager: sess.execute("create schema pym") zope.sqlalchemy.mark_changed(sess) with transaction.manager: DbBase.metadata.create_all(DbEngine) u1 = User() u1.owner_id = 1 u1.principal = 'salomon' u2 = User() u2.owner_id = 1 u2.principal = 'sibylle' sess.add(u1) sess.add(u2) def dance(sess): lgg.info('=' * 78) with transaction.manager: try: tn = sess.query(Tenant).filter(Tenant.name == 'foo').one() cnt = tn.descr.count('o') except sa.orm.exc.NoResultFound: tn = Tenant() tn.owner_id = 2 tn.name = 'foo' tn.descr = 'o' sess.add(tn) cnt = 0 lgg.info('Loop {} (added): {} {} {}'.format(cnt, tn.editor_id, tn.descr, tn.descr.count('o'))) else: lgg.info('Loop {} (stored before change): {} {} {}'.format(cnt, tn.editor_id, tn.descr, tn.descr.count('o'))) tn.descr += 'o' tn.editor_id = 2 lgg.info('-' * 78) def main(): sess = DbSession() setup(sess) dance(sess) dance(sess) dance(sess) dance(sess) dance(sess) if __name__ == '__main__': main()