我正在尝试在SQLAlchemy ORM中创建基于字符串的序列。我知道最好的做法是使用基于Integer的列来管理表的ID,但在我的情况下,由于项目的一些要求,我需要将数据存储为基于字符串的ID for ID。
我知道在某些数据库中,可以使用基于字符串的序列来存储数据,如:
但是在SQL炼金术中我无法通过Sequence方法实现这一点。它只生成基于整数的序列,我找不到在序列生成中“追加”前缀的选项。
实现这一目标有一个简单的解决方案吗?
答案 0 :(得分:0)
你可以在PostgreSQL中这样做:
CREATE TABLE test(
id text PRIMARY KEY,
val text
);
CREATE SEQUENCE test_id_seq OWNED BY test.id;
ALTER TABLE test
ALTER id SET DEFAULT to_hex(nextval('test_id_seq'));
在该示例中,我使用to_hex
函数来获取十六进制表示,但您可以使用任何您喜欢的表达式。
答案 1 :(得分:0)
由于Sequence
对象是基于整数的,因此似乎无法帮助您。需要将类似'AAA' + str(some_numeric_id)
之类的内容显式地发布到包含主键的列中。
以下类使用itertools.product
生成一系列唯一的字符串ID。
import itertools
class StringCounter:
def __init__(self, pattern: List):
self.digit_types = {
'uppercase': 'ABCDEFGHIJKLMNOPQRSTUVWXYZ',
'number': '0123456789',
'hex': '0123456789ABCDEF',
}
format = [self.digit_types[d] for d in pattern]
self.sequence = (''.join(s) for s in itertools.product(*format))
def get_n_ids(self, n):
return [s for _, s in zip(range(n), self.sequence)]
def next_id(self):
return self.sequence.__next__()
def continue_from(self, from_id):
self.sequence = itertools.dropwhile(lambda s: s != from_id, self.sequence)
示例:
id_seq = StringCounter(['uppercase', 'uppercase', 'uppercase', 'number'])
first_batch = id_seq.get_n_ids(9)
print(f'First batch of ids: {first_batch}')
data = ['data1', 'data2', 'data3']
for d in data:
unique_id = id_seq.next_id()
print(f"Posting data '{d}' under unique id {unique_id}")
from_id = 'ACZ8'
id_seq.continue_from(from_id)
print(f'...continuing from {from_id}')
data = ['data4', 'data5', 'data6']
for d in data:
unique_id = id_seq.next_id()
print(f"Posting data '{d}' under unique id {unique_id}")
输出:
First batch of ids: ['AAA0', 'AAA1', 'AAA2', 'AAA3', 'AAA4', 'AAA5', 'AAA6', 'AAA7', 'AAA8']
Posting data 'data1' under unique id AAA9
Posting data 'data2' under unique id AAB0
Posting data 'data3' under unique id AAB1
...continuing from ACZ8
Posting data 'data4' under unique id ACZ8
Posting data 'data5' under unique id ACZ9
Posting data 'data6' under unique id ADA0
将两个StringCounter
实例一起使用的示例:
product_seq = StringCounter(['uppercase', 'uppercase', 'uppercase'])
sale_seq = StringCounter(['number'] * 6)
sale_seq.continue_from('000998')
for prod in range(3):
prod_id = product_seq.next_id()
for line in range(3):
print(f"Posting sale '{sale_seq.next_id()}' of product id '{prod_id}'")
输出:
Posting sale '000998' of product id 'AAA'
Posting sale '000999' of product id 'AAA'
Posting sale '001000' of product id 'AAA'
Posting sale '001001' of product id 'AAB'
Posting sale '001002' of product id 'AAB'
Posting sale '001003' of product id 'AAB'
Posting sale '001004' of product id 'AAC'
Posting sale '001005' of product id 'AAC'
Posting sale '001006' of product id 'AAC'
答案 2 :(得分:0)
这不是一个很好的答案,但是如果您需要以字符串形式访问PK,则可以使用惯用的整数PK,以确保PK是连续且唯一的,然后使用int()
将其转换为字符串/ str()
。