默认值在 SQLAlchemy + PostgreSQL + aiopg + psycopg2 中不起作用
Default value doesn't work in SQLAlchemy + PostgreSQL + aiopg + psycopg2
我在 SQLAlchemy 中发现了意外行为。我正在使用以下版本:
- SQLAlchemy (0.9.8)
- PostgreSQL (9.3.5)
- psycopg2 (2.5.4)
- aiopg (0.5.1)
这是示例的 table 定义:
import asyncio
from aiopg.sa import create_engine
from sqlalchemy import (
MetaData,
Column,
Integer,
Table,
String,
)
metadata = MetaData()
users = Table('users', metadata,
Column('id_user', Integer, primary_key=True, nullable=False),
Column('name', String(20), unique=True),
Column('age', Integer, nullable=False, default=0),
)
现在,如果我尝试对 table 执行简单插入,只需填充 id_user 和name,列 age 应该自动生成正确的?让我们看看...
@asyncio.coroutine
def go():
engine = yield from create_engine('postgresql://USER@localhost/DB')
data = {'id_user':1, 'name':'Jimmy' }
stmt = users.insert(values=data, inline=False)
with (yield from engine) as conn:
result = yield from conn.execute(stmt)
loop = asyncio.get_event_loop()
loop.run_until_complete(go())
这是带有相应错误的结果语句:
INSERT INTO users (id_user, name, age) VALUES (1, 'Jimmy', null);
psycopg2.IntegrityError: null value in column "age" violates not-null constraint
我没有提供 age 列,那么 age = null 值来自哪里?我期待这样的事情:
INSERT INTO users (id_user, name) VALUES (1, 'Jimmy');
或者如果 default 标志实际有效应该是:
INSERT INTO users (id_user, name, Age) VALUES (1, 'Jimmy', 0);
你能解释一下吗?
我认为您需要在插入内容中使用 inline=True
。这将关闭 'pre-execution'。
文档对这个 'pre-execution' 的确切含义有点含糊不清,但他们提到了默认参数:
:param inline:
if True, SQL defaults present on :class:`.Column` objects via
the ``default`` keyword will be compiled 'inline' into the statement
and not pre-executed. This means that their values will not
be available in the dictionary returned from
:meth:`.ResultProxy.last_updated_params`.
这段文档字符串来自 Update class,但它们与 Insert 有共同的行为。
此外,这是他们测试它的唯一方法:
https://github.com/zzzeek/sqlalchemy/blob/rel_0_9/test/sql/test_insert.py#L385
已确认此问题存在 aiopg 错误。似乎目前它忽略了关于数据操作的 default
参数。
我已经使用 server_default
解决了这个问题:
users = Table('users', metadata,
Column('id_user', Integer, primary_key=True, nullable=False),
Column('name', String(20), unique=True),
Column('age', Integer, nullable=False, server_default='0'))
我在 SQLAlchemy 中发现了意外行为。我正在使用以下版本:
- SQLAlchemy (0.9.8)
- PostgreSQL (9.3.5)
- psycopg2 (2.5.4)
- aiopg (0.5.1)
这是示例的 table 定义:
import asyncio
from aiopg.sa import create_engine
from sqlalchemy import (
MetaData,
Column,
Integer,
Table,
String,
)
metadata = MetaData()
users = Table('users', metadata,
Column('id_user', Integer, primary_key=True, nullable=False),
Column('name', String(20), unique=True),
Column('age', Integer, nullable=False, default=0),
)
现在,如果我尝试对 table 执行简单插入,只需填充 id_user 和name,列 age 应该自动生成正确的?让我们看看...
@asyncio.coroutine
def go():
engine = yield from create_engine('postgresql://USER@localhost/DB')
data = {'id_user':1, 'name':'Jimmy' }
stmt = users.insert(values=data, inline=False)
with (yield from engine) as conn:
result = yield from conn.execute(stmt)
loop = asyncio.get_event_loop()
loop.run_until_complete(go())
这是带有相应错误的结果语句:
INSERT INTO users (id_user, name, age) VALUES (1, 'Jimmy', null);
psycopg2.IntegrityError: null value in column "age" violates not-null constraint
我没有提供 age 列,那么 age = null 值来自哪里?我期待这样的事情:
INSERT INTO users (id_user, name) VALUES (1, 'Jimmy');
或者如果 default 标志实际有效应该是:
INSERT INTO users (id_user, name, Age) VALUES (1, 'Jimmy', 0);
你能解释一下吗?
我认为您需要在插入内容中使用 inline=True
。这将关闭 'pre-execution'。
文档对这个 'pre-execution' 的确切含义有点含糊不清,但他们提到了默认参数:
:param inline:
if True, SQL defaults present on :class:`.Column` objects via
the ``default`` keyword will be compiled 'inline' into the statement
and not pre-executed. This means that their values will not
be available in the dictionary returned from
:meth:`.ResultProxy.last_updated_params`.
这段文档字符串来自 Update class,但它们与 Insert 有共同的行为。
此外,这是他们测试它的唯一方法: https://github.com/zzzeek/sqlalchemy/blob/rel_0_9/test/sql/test_insert.py#L385
已确认此问题存在 aiopg 错误。似乎目前它忽略了关于数据操作的 default
参数。
我已经使用 server_default
解决了这个问题:
users = Table('users', metadata,
Column('id_user', Integer, primary_key=True, nullable=False),
Column('name', String(20), unique=True),
Column('age', Integer, nullable=False, server_default='0'))