【发布时间】:2017-09-17 01:29:57
【问题描述】:
我想使用 Enums 将组织数据存储在 PostgreSQL 数据库中。由于组织名称有时会更改,因此我有时需要更新 Enum 值,并且我想使用 Python 和 sqlalchemy 和 psycopg2 自动执行此操作。但是修改 Enum 后,就无法插入新值了。
我怀疑这是由于psycopg2 的内部check() 方法,因为数据库确实接受了新值。你知道更新psycopg2已知类型的方法吗?
这是我对此脚本的测试:
class DbconTestCase(unittest.TestCase):
def setUp(self):
self.engine, self.meta = db.get_connection('test_user', 'test_pass', 'testdb')
# Create test table, which will be deleted later
self.test_table = Table('test_table', self.meta,
Column('id', Integer, primary_key=True),
Column('type', Enum('number', 'text', 'image', name='type'), nullable=False),
Column('text', String(32)))
self.meta.create_all()
def test_add_enum_value(self):
try:
# Add new value to enum named 'type'
db.add_enum_value(self.engine, 'type', 'object')
except Exception as exp:
self.assertTrue(False, msg=exp.__cause__)
else:
self.assertTrue(True)
def test_bulk_copy(self):
types = ['number', 'text', 'image', 'object']
objects = [{'id': idx,
'type': types[idx % len(types)],
'text': 'random text to insert'} for idx in range(10000)]
try:
db.bulk_copy(self.engine, str(self.test_table.name), objects)
except Exception as exp:
self.assertTrue(False, msg=exp.__cause__)
else:
self.assertTrue(True)
def tearDown(self):
self.meta.drop_all()
还有一点解释:基本上我在测试数据库中创建一个测试表,然后用一个新值扩展一个枚举类型。然后我尝试插入大量数据,其中包含枚举的新值。我收到以下错误:
psycopg2.DataError: invalid input value for enum type: "object"
【问题讨论】:
-
psycopg2 不会跟踪它知道的枚举值。我怀疑你的测试用例失败了,因为
test_add_enum_value不能保证在test_bulk_copy之前执行。 -
我明白了,但如果执行顺序因运行而异,在某些情况下我会得到绿色运行,但每次运行都会失败。
-
这是一个错误的假设。如果执行顺序不保证,那么这两个函数可以按任意顺序运行;他们不必必须按所有可能的顺序运行。换句话说,顺序可以是任意但稳定的。
-
我刚刚意识到 setUp 和 tearDown 在每次测试之前运行,直到现在我一直认为 setUp 运行一次,然后运行测试用例中的所有测试,然后调用 tearDown 。所以基本上问题是,一个完全不同的表对象被用来插入,而不是我想的那个。
标签: python postgresql enums sqlalchemy psycopg2