def on(*args, **listen_kwargs):
    """Class method decorator for SQLAlchemy models. Must be used in
    conjunction with the :func:`.attach_events` class decorator

    Usage::

        @attach_events
        class Post(Model):
            uuid = Column(String(36))
            post_tags = relationship('PostTag', back_populates='post')  # m2m

            # instance event (only one positional argument, the event name)
            # kwargs are passed on to the sqlalchemy.event.listen function
            @on('init', once=True)
            def generate_uuid(self, args, kwargs):
                self.uuid = str(uuid.uuid4())

            # attribute event (two positional args, field name and event name)
            @on('post_tags', 'append')
            def set_tag_order(self, post_tag, initiating_event):
                if not post_tag.order:
                    post_tag.order = len(self.post_tags) + 1
    """
    if len(args) == 1:
        field_name, event_name = (None, args[0])
    elif len(args) == 2:
        field_name, event_name = args
    else:
        raise NotImplementedError('@on accepts only one or two positional arguments')

    def wrapper(fn):
        setattr(fn, _SQLAlchemyEvent.ATTR,
                _SQLAlchemyEvent(field_name, event_name, listen_kwargs))
        return fn
    return wrapper