02.06.2014 16:44, Michael Bayer kirjoitti:
the ORM can't persist any value for "delivery_method" unless there is an actual attribute set event.

If you are saying session.add(DeliveryAddress()) and flushing, these are the options for "deliveryaddress.delivery_method":

1. the value has no setting and is not present in the INSERT statement - it gets set as NULL in the DB.

2. the value has no setting, but you have a python or server side default set up on it. At before_insert() time, that value is still None so that can't be what you're doing.

3. The DeliveryAddress() constructor sets delivery_method, so there's an attribute set event.

So I can only guess that you're looking for the None here? I guess there's some odd relationship to this Settings object such that it already exists in the DB with some other value such that you actually need to positively set None. In any case, to have something happen upon DeliveryAddress(), you can either place that logic as part of __init__() (regular Python!) or if that bothers you, you can also set up the init() event for the DeliveryAddress class.
Settings is a singleton (just one row with ID 1). It contains the default values for a number of things.

I will have a look at __declare_last__, thanks!

That said, sometimes I need to react to inserts and insert other rows then. Attribute events won't help me there. So far I've ended up making a module for these listeners and I just had a single listener for each event (before_insert or before_flush) with a lot of if..elif...branching.

If all of these options don't suit you and you absolutely insist on the before_insert event, it is very easy to add to your declarative base a mixin that sets these up for you (see http://docs.sqlalchemy.org/en/rel_0_9/orm/extensions/declarative.html#declare-last):

class BeforeInsertMixin(object):
    @classmethod
    def __declare_last__(cls):
        if hasattr(cls, 'before_insert'):
            event.listen(cls, 'before_insert', cls.before_insert)

Base = declarative_base(cls=BeforeInsertMixin)

class DeliveryAddress(Base):
    # ...

    @classmethod
    def before_insert(cls, mapper, connection, target):
        #...


if you want to change the signature, no problem:

class BeforeInsertMixin(object):
    @classmethod
    def __declare_last__(cls):
        if hasattr(cls, 'before_insert'):
            @event.listens_for(cls, 'before_insert')
            def before_insert(mapper, connection, target):
target.before_insert(object_session(target))


class DeliveryAddress(Base):
    # ...

    def before_insert(self, session):
        #...
These are "frameworky" types of hooks that SQLAlchemy would prefer to remain agnostic of, but it provides for you all the components you need to create whatever system of hooks you'd like.





On Jun 2, 2014, at 8:04 AM, Alex Grönholm <alex.gronh...@nextday.fi <mailto:alex.gronh...@nextday.fi>> wrote:

That's the first thing I tried, but validators don't get called unless you explicitly set a value to the column.

So for something like session.add(DeliveryAddress()), the validator doesn't get called.

maanantai, 2. kesäkuuta 2014 14.27.47 UTC+3 Michael Bayer kirjoitti:


    On Jun 2, 2014, at 1:47 AM, Alex Grönholm <alex.g...@nextday.fi>
    wrote:

    > This has been a problem for me for years.
    >
    > class DeliveryAddress(Base, Address):
    >     ...
    >     delivery_method = Column(String)
    >     ...
    >
    > @event.listens_for(DeliveryAddress, 'before_insert')
    > def before_insert_deliveryaddress(mapper, connection, target):
    >     settings = object_session(target).query(Settings).one()
    >     target.delivery_method = settings.default_delivery_method
    >
    > Is there absolutely no way to encapsulate this logic cleanly in
    the actual class?


    I use an attribute event for that, and more often just a simple
    @validates.

    @validates("default_delivery_method")
    def _set_delivery_method(self, key, value):
        self.settings.delivery_method = value
        return value




--
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 tosqlalchemy+unsubscr...@googlegroups.com <mailto:sqlalchemy+unsubscr...@googlegroups.com>. To post to this group, send email tosqlalch...@googlegroups.com <mailto:sqlalchemy@googlegroups.com>.
Visit this group athttp://groups.google.com/group/sqlalchemy.
For more options, visithttps://groups.google.com/d/optout.

--
You received this message because you are subscribed to a topic in the Google Groups "sqlalchemy" group. To unsubscribe from this topic, visit https://groups.google.com/d/topic/sqlalchemy/-s9GWB3hfso/unsubscribe. To unsubscribe from this group and all its topics, send an email to sqlalchemy+unsubscr...@googlegroups.com <mailto:sqlalchemy+unsubscr...@googlegroups.com>. To post to this group, send email to sqlalchemy@googlegroups.com <mailto:sqlalchemy@googlegroups.com>.
Visit this group at http://groups.google.com/group/sqlalchemy.
For more options, visit https://groups.google.com/d/optout.

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

Reply via email to