Sqlalchemy在为表生成sql时似乎没有保留列顺序。如何让sqlalchemy使用与定义列相同的顺序?
示例:
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import Table, MetaData, Column, BigInteger, Integer, String, MetaData, ForeignKey, Date, DateTime
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
Base = declarative_base()
class MyTable(Base):
__tablename__ = "my_table"
id = Column(BigInteger, primary_key=True)
col1 = Column(String(20), name="col1")
col2 = Column(Integer)
col3 = Column(BigInteger, name="col_3")
engine = create_engine('sqlite:///foo.db')
Session = sessionmaker(engine)
db = Session()
print(db.query(MyTable).statement.compile(engine))
输出是:
SELECT my_table.col_3, my_table.id, my_table.col1, my_table.col2
FROM my_table
而不是
SELECT my_table.id, my_table.col1, my_table.col2, my_table.col_3
FROM my_table
Sqlalchemy似乎确实保留了表定义中的列顺序,因为当它生成CREATE TABLE命令时,列顺序与订单列匹配。
from sqlalchemy.schema import CreateTable
print(CreateTable(MyTable.__table__).compile(engine))
答案 0 :(得分:2)
列在mapper中的存储方式与表中的不同。当您执行CreateTable(MyTable.__table__)
looks through columns
on the table时。当您执行session.query(MyTable)
looks through _props
on the current mapper时。 _props
的填充方式与columns
的填充方式不同,由于SQLAlchemy内部的某些决定,这可能会导致不同的顺序。
答案最终是否定的,你不能保证查询列的顺序,因为幕后工作还有其他的力量。如果命令对你很重要,那么它应该是brought up as an issue对抗SQLAlchemy。
在这种情况下,指定与属性名称不匹配的列名会更改列内部存储的顺序。从该列中删除name='col_3'
将"修复"此
答案 1 :(得分:1)
这有点好笑,但如果你将col_3更改为col3,它会按声明的方式发出列。
为什么?
执行映射器配置时,会有此注释
# look through columns in the current mapper that
# are keyed to a propname different than the colname
# (if names were the same, we'd have popped it out above,
# in which case the mapper makes this combination).
# See if the superclass has a similar column property.
# If so, join them together.
你的col_3将转到mapper类的属性参数,该参数将用作可选择的第一个参数。