2014-01-24 34 views
6

SQLAlchemy正在爲postgresql中的列生成但不啓用序列。我懷疑我可能在引擎設置上做錯了什麼。SQLAlchemy爲什麼不創建串行列?

使用來自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

-Reece

+0

Plain'\ d users'?那裏有一個'default nextval('users_id_seq')'嗎? –

+3

使用以下說明檢查您的CREATE TABLE語句是否正確:http://docs.sqlalchemy.org/en/latest/faq.html#how-can-i-get-the-create-table-drop-table輸出爲字符串。另外,我使用Postgres,並且我沒有明確定義序列,我讓Postgres的SERIAL類型爲我做。我只是定義了'id = Column(Integer,primary_key = True)'和SQL Alchemy默認將其設置爲SERIAL類型 – dtheodor

+0

就是這樣,@dtheodor!教我不要閱讀文檔! (其實SQLAlchemy的文檔是最好的。)謝謝。 – Reece

回答

11

這是因爲你有一個明確的Sequence提供它。該SERIAL數據類型PostgreSQL中產生了自己序列,它的SQLAlchemy知道如何定位 - 所以,如果你省略了Sequence,SQLAlchemy的會使SERIAL,假設其意圖是該列是自動遞增的(這是由autoincrement參數確定結合整數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:[email protected]/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) 
) 
+0

謝謝,邁克。 dododor的建議(==你的T2班級)完美地工作。令人困惑的是,本教程展示了我期望生成SERIAL的另一種方式。現在我明白爲什麼這些不同了。 「USER_ID_SEQ」來自哪裏的 – Reece

1

如果您需要由於某種原因明確創建序列,例如設置起始值,並且仍希望使用與使用表示法相同的默認值行爲,則可以使用以下代碼完成該操作:

#!/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) 
+0

? –

0

里斯

我也用該教程作爲一種模式,只是無法得到它與已經存在,並與串行序列密鑰ID列,生成新的密鑰ID值的任何在Postgres表工作。

像大衛一樣,我發現序列必須單獨定義給班級。對於任何使用「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