获取数据库对象的半长唯一id(非顺序)键的最佳方法是什么

2024-10-01 07:38:06 发布

您现在位置:Python中文网/ 问答频道 /正文

我正在构建一个web应用程序,我希望我的URL方案看起来像这样:

someurl.com/object/FJ1341lj

目前我只使用SQL Alchemy对象的主键,但问题是我不希望url是连续的或低数字。例如,我的URL如下所示:

^{pr2}$

Tags: 对象comweb应用程序urlsqlobject方案
3条回答

考虑到您的需求,最好的选择是使用itertools.combinations有点像这样

>>> urls=itertools.combinations(string.ascii_letters,6)
>>> 'someurl.com/object/'+''.join(x.next())
'someurl.com/object/abcdek'
>>> 'someurl.com/object/'+''.join(x.next())
'someurl.com/object/abcdel'
>>> 'someurl.com/object/'+''.join(x.next())
'someurl.com/object/abcdem'

对整数进行编码

您可以对整数使用可逆编码:

def int_str(val, keyspace):
    """ Turn a positive integer into a string. """
    assert val >= 0
    out = ""
    while val > 0:
        val, digit = divmod(val, len(keyspace))
        out += keyspace[digit]
    return out[::-1]

def str_int(val, keyspace):
    """ Turn a string into a positive integer. """
    out = 0
    for c in val:
        out = out * len(keyspace) + keyspace.index(c)
    return out

快速测试代码:

^{pr2}$

输出

OK? True -- int_str(1064463423090) = 'antmgabi'; str_int('antmgabi') = 1064463423090
OK? True -- int_str(4319193500) = 'w7q0hm-'; str_int('w7q0hm-') = 4319193500
OK? True -- int_str(495689346389) = 'ev_dpe_d'; str_int('ev_dpe_d') = 495689346389
OK? True -- int_str(2496486533) = '1q2t4w'; str_int('1q2t4w') = 2496486533

混淆它们并使它们成为非连续的

要使ID不连续,可以将原始值与任意值相乘,然后添加随机“chaff”作为要丢弃的数字—在我的示例中,使用简单的模数检查:

def chaffify(val, chaff_size = 150, chaff_modulus = 7):
    """ Add chaff to the given positive integer.
    chaff_size defines how large the chaffing value is; the larger it is, the larger (and more unwieldy) the resulting value will be.
    chaff_modulus defines the modulus value for the chaff integer; the larger this is, the less chances there are for the chaff validation in dechaffify() to yield a false "okay".
    """
    chaff = random.randint(0, chaff_size / chaff_modulus) * chaff_modulus
    return val * chaff_size + chaff

def dechaffify(chaffy_val, chaff_size = 150, chaff_modulus = 7):
    """ Dechaffs the given chaffed value. The chaff_size and chaff_modulus parameters must be the same as given to chaffify() for the dechaffification to succeed.
    If the chaff value has been tampered with, then a ValueError will (probably - not necessarily) be raised. """
    val, chaff = divmod(chaffy_val, chaff_size)
    if chaff % chaff_modulus != 0:
        raise ValueError("Invalid chaff in value")
    return val

for x in xrange(1, 11):
    chaffed = chaffify(x)
    print x, chaffed, dechaffify(chaffed)

输出(随机):

1 262 1
2 440 2
3 576 3
4 684 4
5 841 5
6 977 6
7 1197 7
8 1326 8
9 1364 9
10 1528 10

编辑:再想一想,箔条的随机性可能不是一个好主意,因为你失去了每个混淆ID的典型性——这缺乏随机性,但仍有有效性(如果chaff_val足够大,更改一个数字可能会使整数无效)。在

def chaffify2(val, chaff_val = 87953):
    """ Add chaff to the given positive integer. """
    return val * chaff_val

def dechaffify2(chaffy_val, chaff_val = 87953):
    """ Dechaffs the given chaffed value. chaff_val must be the same as given to chaffify2(). If the value does not seem to be correctly chaffed, raises a ValueError. """
    val, chaff = divmod(chaffy_val, chaff_val)
    if chaff != 0:
        raise ValueError("Invalid chaff in value")
    return val

把它们放在一起

document_id = random.randint(0, 1000000)
url_fragment = int_str(chaffify(document_id))
print "URL for document %d: http://example.com/%s" % (document_id, url_fragment)
request_id = dechaffify(str_int(url_fragment))
print "Requested: Document %d" % request_id

输出(随机)

URL for document 831274: http://example.com/w840pi
Requested: Document 831274

可能比你想的长一点。在

Python 2.7.1+ (r271:86832, Apr 11 2011, 18:13:53) 
[GCC 4.5.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import uuid
>>> uuid.uuid4()
UUID('ba587488-2a96-4daa-b422-60300eb86155')
>>> str(uuid.uuid4())
'001f8565-6330-44a6-977a-1cca201aedcc'
>>> 

如果使用的是sqlalchemy,那么可以定义一个uuid类型的id列,如下所示

^{pr2}$

如果您使用的是Django,那么Preet的答案可能更合适,因为Django的很多东西都依赖于int的主键。在

相关问题 更多 >