Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p>this is a little tricky, for these reasons:</p> <ol> <li><p>your SELECT MAX() will return NULL if the table is empty; you should use COALESCE to produce a default "seed" value. See below.</p></li> <li><p>the whole approach of inserting the rows with SELECT MAX is entirely not safe for concurrent use - so you need to make sure only one INSERT statement at a time invokes on the table or you may get constraint violations (you should definitely have a constraint of some kind on this column).</p></li> <li><p>from the SQLAlchemy perspective, you need your custom element to be aware of the actual Column element. We can achieve this either by assigning the "nextusn()" function to the Column after the fact, or below I'll show a more sophisticated approach using events.</p></li> <li><p>I don't understand what you're going for with "server_onupdate=nextusn". "server_onupdate" in SQLAlchemy doesn't actually run any SQL for you, this is a placeholder if for example you created a trigger; but also the "SELECT MAX(id) FROM table" thing is an INSERT pattern, I'm not sure that you mean for anything to be happening here on an UPDATE.</p></li> <li><p>The @compiles extension needs to return a string, running the select() there through compiler.process(). See below.</p></li> </ol> <p>example:</p> <pre><code>from sqlalchemy import Column, Integer, create_engine, select, func, String from sqlalchemy.ext.declarative import declarative_base from sqlalchemy.sql.expression import ColumnElement from sqlalchemy.schema import ColumnDefault from sqlalchemy.ext.compiler import compiles from sqlalchemy import event class nextusn_default(ColumnDefault): "Container for a nextusn() element." def __init__(self): super(nextusn_default, self).__init__(None) @event.listens_for(nextusn_default, "after_parent_attach") def set_nextusn_parent(default_element, parent_column): """Listen for when nextusn_default() is associated with a Column, assign a nextusn(). """ assert isinstance(parent_column, Column) default_element.arg = nextusn(parent_column) class nextusn(ColumnElement): """Represent "SELECT MAX(col) + 1 FROM TABLE". """ def __init__(self, column): self.column = column @compiles(nextusn) def compile_nextusn(element, compiler, **kw): return compiler.process( select([ func.coalesce(func.max(element.column), 0) + 1 ]).as_scalar() ) Base = declarative_base() class A(Base): __tablename__ = 'a' id = Column(Integer, default=nextusn_default(), primary_key=True) data = Column(String) e = create_engine("sqlite://", echo=True) Base.metadata.create_all(e) # will normally pre-execute the default so that we know the PK value # result.inserted_primary_key will be available e.execute(A.__table__.insert(), data='single row') # will run the default expression inline within the INSERT e.execute(A.__table__.insert(), [{"data": "multirow1"}, {"data": "multirow2"}]) # will also run the default expression inline within the INSERT, # result.inserted_primary_key will not be available e.execute(A.__table__.insert(inline=True), data='single inline row') </code></pre>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload