Python Django web应用程序的复杂编码逻辑
我有一些特殊的需求,我正试图找出编写它的最佳方法。最重要的是效率,其次是可维护性。要求是这样的(请容忍我): 我的Django网站上有一个功能,旨在为注册用户和未注册用户提供服务。这项功能将在每个用户的pin码后面设置门控。我要求随机生成这些管脚(而不是串行生成) pin码需要令人难忘-这意味着pinPython Django web应用程序的复杂编码逻辑,python,django,python-2.7,django-views,Python,Django,Python 2.7,Django Views,我有一些特殊的需求,我正试图找出编写它的最佳方法。最重要的是效率,其次是可维护性。要求是这样的(请容忍我): 我的Django网站上有一个功能,旨在为注册用户和未注册用户提供服务。这项功能将在每个用户的pin码后面设置门控。我要求随机生成这些管脚(而不是串行生成) pin码需要令人难忘-这意味着pinlen成为一个因素。我想要一个4位数的pin码。因为字母数字比纯数字更难记忆(根据我进行的可用性测试,我坚持这些结果) 我不能在pin码之间发生冲突,因为它们也将被用作标识符——所以它们都必须是唯一
len
成为一个因素。我想要一个4位数的pin码。因为字母数字比纯数字更难记忆(根据我进行的可用性测试,我坚持这些结果)
我不能在pin码之间发生冲突,因为它们也将被用作标识符——所以它们都必须是唯一的。我的范围将在0000到9999之间。只有10K的独特组合是可能的。这是有限制的,但pin码的可记忆性比可能的pin码池的大小具有更高的优先级。所以我要牺牲
最后,注册用户的pin码将被永久分配。另一方面,未注册的用户将被分配不超过24小时的PIN,在这24小时后,他们将过期,因此再次进入未使用PIN池
假设我的上述数据模型(在models.py
中)是这样的:
class Inbox(models.Model):
pin_code = models.CharField(default='0')
owner = models.ForeignKey(User)
creation_time = models.DateTimeField(auto_now_add=True)
在views.py
中,我需要一种方法将可用的pin_代码
分配给我创建的每个Inbox
对象。最有效的逻辑是什么?以下是我如何看待它的:
def expire_pin(time_difference=None):
#admin user (with id 1) is assumed as the 'unregistered user'
Inbox.objects.filter(creation_time__lte=time_difference,owner_id=1).update(pin_code='0')
def get_pin():
parent_list = ['{:04d}'.format(i) for i in range(10000)]
day_ago = timezone.now() - timedelta(hours=24)
expire_pin(day_ago)
to_exclude = Inbox.objects.filter(~Q(pin_code='0')).values_list('pin_code',flat=True)
new_list = [item for item in parent_list if item not in to_exclude]
return random.choice(new_list)
可选:您不必阅读它,但以下是我使用
pin\u代码的目的。每个已注册和未注册的用户都分配了一个收件箱,可在example.com/pin/XXXX
(XXXX
为pin\u代码
)访问。用户可以通过社交媒体与其朋友共享此收件箱地址。朋友们可以通过他们的手机号码登录,查看前用户留给这位朋友的内容。明白了吗
我需要为已注册和未注册的用户提供此功能-因此需要为未知用户分配pin_代码。但我希望能够回收未注册的用户代码,这样我就不会太快用完10K的可能性。我在这个网站上有一个相当大的用户群
不过,最终我会用完10K组合。我想我会写代码,然后无缝转换到5位数的引脚。但即使在这种情况下,如果任何4位PIN过期并可用,它们将在分配期间获得第一优先权。如果你也能帮我,那就太好了 这是一个很好的故事,但我不能100%确定你的问题是什么。如何生成随机数
import random
print('%04d' % random.randint(0, 10000))
将其放入while循环中,以确保它还不存在于数据库中。或者,使用used
布尔值在数据库中预生成10000个pin码的列表,以获得稍微更有效的解决方案
我不得不问,记住真的是一个要求吗?如果是,自定义字符串不是更好的主意吗?随机数并不是那么容易记住的,人们更善于记住自己想的东西。对于pin码分配;我相当肯定您的代码也在做类似的事情:
首先,我将保留一个所有代码可能性的列表(最好现在创建该列表),因此将是一个简单的表:
唯一的4位代码:指定的布尔值
然后我将创建一个函数:
sudo代码:
def new_pin(db_list):
# db_list is passed in array of db values where assigned-boolean = false
random number between 1 and 9998 # i wouldn't use 0000 and 9999, may even want to remove all 1111, 2222, but will further reduce pool size
if rand in db_list:
db.assigned-boolean = true for rand
return rand
else:
return new_pin(db_list)
上述问题;您可能有竞争条件,因此必须为db_列表锁定数据库表,其他调用必须等到db_列表可用,这样您就不会意外地分配两次pin(使用rand不太可能,但可能发生在具有小池的足够繁忙的站点上)
例如,另一个选择是增加url的复杂性
example.com/USER\u NAME/XXXX
并让用户选择XXXX并确保其具有唯一的名称。对于那些未注册的,您可以分配一个随机字
如果这太复杂;我建议允许代码长度从3到6,以便
example.com/pin/XXX
example.con/pin/XXXX
example.com/pin/XXXXX等
所有工作,如果引脚分配。这将大大增加您的池大小。如果您有
class PinCode(models.Model):
code = models.CharField(max_length='4', primary_key=True, validators=[lambda x: len(x) == 4])
current_owner = models.ForeignKey(User, blank=True, null=True)
created = models.DateTimeField(auto_now_add=True)
然后,要获得pin码,只需查询PinCodes,查找下一个未拥有或过期的pin码。所需的只是django extensions
包的RandomCharField
。看
在代码中:
from django_extensions.db.fields import RandomCharField
class Inbox(models.Model):
pin_code = RandomCharField(length=4, unique=True, include_alpha=False)
owner = models.ForeignKey(User)
creation_time = models.DateTimeField(auto_now_add=True)
关于记忆:是的,这是一项要求。问题是,我还在URL模式中使用生成的pin——因此为了避免冲突,它们必须是唯一的。但如果你是在暗示我让用户决定保留什么,保留多长时间——我的用户已经有了昵称
,我可以使用。但许多是罕见的字符,有些是不适合长。如果你是复制粘贴的话,这也没问题,但是我实际上有一个相当大的人口,他们使用功能手机,而且实际上必须手动键入URL来共享它们(在我问题的可选部分阅读更多关于它的信息)。
from django_extensions.db.fields import RandomCharField
class Inbox(models.Model):
pin_code = RandomCharField(length=4, unique=True, include_alpha=False)
owner = models.ForeignKey(User)
creation_time = models.DateTimeField(auto_now_add=True)