为啥 SQLAlchemy 不创建串行列?
Posted
技术标签:
【中文标题】为啥 SQLAlchemy 不创建串行列?【英文标题】:Why isn't SQLAlchemy creating serial columns?为什么 SQLAlchemy 不创建串行列? 【发布时间】:2014-02-15 04:57:43 【问题描述】:SQLAlchemy 正在为 postgresql 中的列生成但不启用序列。我怀疑我在引擎设置中可能做错了什么。
使用 SQLAlchemy 教程 (http://docs.sqlalchemy.org/en/rel_0_9/orm/tutorial.html) 中的示例:
#!/usr/bin/env python
from sqlalchemy import create_engine, Column, Integer, String, Sequence
from sqlalchemy.ext.declarative import declarative_base
Base = declarative_base()
class User(Base):
__tablename__ = 'users'
id = Column(Integer, Sequence('user_id_seq'), primary_key=True)
name = Column(String(50))
fullname = Column(String(50))
password = Column(String(12))
def __repr__(self):
return "<User(name='%s', fullname='%s', password='%s')>" % (
self.name, self.fullname, self.password)
db_url = 'postgresql://localhost/serial'
engine = create_engine(db_url, echo=True)
Base.metadata.create_all(engine)
使用此脚本,生成下表:
serial=# \d+ users
Table "public.users"
Column | Type | Modifiers | Storage | Stats target | Description
----------+-----------------------+-----------+----------+--------------+-------------
id | integer | not null | plain | |
name | character varying(50) | | extended | |
fullname | character varying(50) | | extended | |
password | character varying(12) | | extended | |
Indexes:
"users_pkey" PRIMARY KEY, btree (id)
Has OIDs: no
然而,一个序列被创建:
serial=# select sequence_schema,sequence_name,data_type from information_schema.sequences ;
sequence_schema | sequence_name | data_type
-----------------+---------------+-----------
public | user_id_seq | bigint
SQLAlchemy 0.9.1、Python 2.7.5+、Postgresql 9.3.1、Ubuntu 13.10
-里斯
【问题讨论】:
纯\d users
?里面有default nextval('users_id_seq')
吗?
检查您的 CREATE TABLE 语句是否正确,使用此处的说明:docs.sqlalchemy.org/en/latest/…。另外,我使用 Postgres 并且我没有明确定义序列,我让 Postgres 的 SERIAL 类型为我做这件事。我只定义了id = Column(Integer, primary_key=True)
,SQL Alchemy 默认将其设置为 SERIAL 类型
就是这样,@dtheodor!教我不要阅读文档! (实际上 SQLAlchemy 的文档是最好的。)谢谢。
@dtheodor 链接不再有效,我遇到了同样的问题。有不同的链接吗?我想检查一下,因为我也从 sqllite3
迁移到 postgresql
***.com/questions/33225636/…
@thesayhey 看起来它被移到了这里:docs.sqlalchemy.org/en/rel_0_9/faq/…(通过谷歌搜索找到“sqlalchemy how-can-i-get-the-create-table-drop-table-output-as-a-字符串")
【参考方案1】:
这是因为您为其提供了明确的Sequence
。 postgresql 中的SERIAL
数据类型生成其自己的 序列,SQLAlchemy 知道如何定位 - 所以如果省略Sequence
,SQLAlchemy 将呈现SERIAL
,假设意图是该列是自动递增(由 autoincrement
参数与 Integer primary_key 一起确定;默认为 True)。但是当Sequence
被传递时,SQLAlchemy 看到您不希望由SERIAL
隐式创建的序列而是您指定的序列:
from sqlalchemy import create_engine, Column, Integer, String, Sequence
from sqlalchemy.ext.declarative import declarative_base
Base = declarative_base()
class T1(Base):
__tablename__ = 't1'
# emits CREATE SEQUENCE + INTEGER
id = Column(Integer, Sequence('user_id_seq'), primary_key=True)
class T2(Base):
__tablename__ = 't2'
# emits SERIAL
id = Column(Integer, primary_key=True)
class T3(Base):
__tablename__ = 't3'
# emits INTEGER
id = Column(Integer, autoincrement=False, primary_key=True)
engine = create_engine("postgresql://scott:tiger@localhost/test", echo=True)
Base.metadata.create_all(engine)
输出:
CREATE SEQUENCE user_id_seq
CREATE TABLE t1 (
id INTEGER NOT NULL,
PRIMARY KEY (id)
)
CREATE TABLE t2 (
id SERIAL NOT NULL,
PRIMARY KEY (id)
)
CREATE TABLE t3 (
id INTEGER NOT NULL,
PRIMARY KEY (id)
)
【讨论】:
谢谢,迈克。 dtheodor 的建议(== 你的 T2 班)运行良好。令人困惑的是,本教程显示了我期望生成 SERIAL 的另一种方式。现在我明白为什么它们不同了。【参考方案2】:如果您出于某种原因需要显式创建序列,例如设置起始值,并且仍希望使用与使用 Column(Integer, primary_key=True)
表示法时相同的默认值行为,则可以使用以下代码完成:
#!/usr/bin/env python
from sqlalchemy import create_engine, Column, Integer, String, Sequence
from sqlalchemy.ext.declarative import declarative_base
Base = declarative_base()
USER_ID_SEQ = Sequence('user_id_seq') # define sequence explicitly
class User(Base):
__tablename__ = 'users'
# use sequence in column definition, and pass .next_value() as server_default
id = Column(Integer, USER_ID_SEQ, primary_key=True, server_default=USER_ID_SEQ.next_value())
name = Column(String(50))
fullname = Column(String(50))
password = Column(String(12))
def __repr__(self):
return "<User(name='%s', fullname='%s', password='%s')>" % (
self.name, self.fullname, self.password)
db_url = 'postgresql://localhost/serial'
engine = create_engine(db_url, echo=True)
Base.metadata.create_all(engine)
【讨论】:
USER_ID_SEQ
是从哪里来的?【参考方案3】:
里斯
我也将该教程用作模型,但无法让它与任何已经存在的 Postgres 表一起工作,并且具有带有序列序列的键 ID 列来生成新的键 ID 值。
和 David 一样,我发现必须将序列单独定义到类中。对于使用“db.Model”方法的任何人,这里有一个示例。
from flask.ext.sqlalchemy import SQLAlchemy
from sqlalchemy import Sequence
db = SQLAlchemy()
pageimpression_imp_id_seq = Sequence('pageimpression_imp_id_seq')
class PageImpression(db.Model):
__tablename__ = 'pageimpression'
imp_id = db.Column(db.Integer,
pageimpression_imp_id_seq,
server_default=usersession_sessionid_seq.next_value(),primary_key=True)
logdate = db.Column(db.DateTime)
sessionid = db.Column(db.String)
path = db.Column(db.String)
referrer = db.Column(db.String)
def __init__(self, imp_id, logdate, sessionid, path, referrer):
self.imp_id = imp_id
self.logdate = logdate
self.sessionid = sessionid
self.path = path
self.referrer = referrer
def __repr__(self):
return "<PageImpression(imp_id='%s', logdate='%s',sessionid='%s', path='%s', referrer='%s')>" % (self.imp_id, self.logdate, self.sessionid, self.path, self.referrer)
def PageImpressionAdd(sessionid):
sessionid = 0 # dummy value for unit testing
current_time = datetime.now().isoformat()
if CurrentConfig.IMPRESSION_LOGGING_ON == True:
path = request.path
if request.environ.get('HTTP_REFERER') and not request.environ.get('HTTP_REFERER').isspace():
referrer = request.environ.get('HTTP_REFERER') # the string is not-empty
else:
referrer = '' # the string is empty
from website.models import PageImpression
thisPageImpression = PageImpression(None,current_time,sessionid, path, referrer)
db.session.add(thisPageImpression)
db.session.commit()
# get the values created by the Postgres table defaults
imp_id = thisPageImpression.imp_id
logdate = thisPageImpression.logdate
return current_time
【讨论】:
【参考方案4】:您也可以通过 GUI pgAdmin 更改序列而无需任何 SQL 脚本,如下所示:
选择您的数据库 -> 架构 -> 公共 -> 序列 -> 右键单击 -> 属性 -> 定义 -> 当前值。
【讨论】:
以上是关于为啥 SQLAlchemy 不创建串行列?的主要内容,如果未能解决你的问题,请参考以下文章
不确定为啥在使用 SQLAlchemy 时出现线程 ID 错误
sqlalchemy.exc.NoSuchModuleError:无法加载插件:sqlalchemy.dialects:postgres