正如参考中所述,邀请码不仅要能够防止客户端伪造,还要方便服务端验证。
我大体依据参考中的思路。略微不同的是,id和原始码并没有直接拼接,而是交叉。
import random
import string
s_set = string.ascii_letters + string.digits
raw_code_len = 8
class Code(models.Model):
raw_code = fields.Char(string=u'原始码', index=True)
@property
def code(self):
id_str = '{:0>8x}'.format(self.id) # 转换为16进制,并用0填充至8位,故最大值为16**8 - 1
return ''.join(''.join(i) for i in zip(id_str, self.raw_code)) # 在id的每个数字后填充随机字符,构成最终的码
def check_code(self, code):
id_str = code[::2]
raw_code = code[1::2]
try:
int(id_str, 16)
except ValueError, e:
return False
c = self.sudo().browse(int(id_str, 16))
if c.exists() and c.raw_code == raw_code:
return c
else:
return False
@classmethod
def generate_raw_code(cls):
return ''.join(random.choice(s_set) for i in range(raw_code_len))
def create(self, vals):
c = super(Code, self).create(vals)
c.raw_code = c.generate_raw_code()
return c
如果我的计算没错的话,这个最多可以产生近43亿个邀请码。
另外,''.join(''.join(i) for i in zip(id_str, self.raw_code))
可以改进。
In [2]: from itertools import chain
In [3]: id_str = '123'
In [4]: raw_code = 'abc'
In [5]: zip(id_str, raw_code)
Out[5]: [('1', 'a'), ('2', 'b'), ('3', 'c')]
In [8]: list(chain(*zip(id_str, raw_code)))
Out[8]: ['1', 'a', '2', 'b', '3', 'c']
In [11]: list(chain.from_iterable(zip(id_str, raw_code)))
Out[11]: ['1', 'a', '2', 'b', '3', 'c']
所以可以简化为:
In [13]: ''.join(chain.from_iterable(zip(id_str, raw_code)))
Out[13]: '1a2b3c'
In [14]: ''.join(chain(*zip(id_str, raw_code)))
Out[14]: '1a2b3c'
也算是又一次学习了itertools.chain。(苦笑)
如果用协程:
In [3]: def fff():
...: for i in zip(id_str, raw_code):
...: yield from i
In [6]: list(fff())
Out[6]: ['1', 'a', '2', 'b', '3', 'c']
当然,推荐使用 chain
,其使用C实现,效率更高。
网友评论