Django网络应用程序的棘手编码逻辑

时间:2016-03-09 00:20:42

标签: python django python-2.7 django-views

我有一些特殊要求,我正在努力找出编码它的最佳方法。 最佳效率最高,可维护性最高。要求是这样的(跟我一起):

我的Django网站上有一个功能,即为 注册和未注册用户提供服务。此功能将在每个用户的引脚代码后面进行门控。我要求这些引脚是随机生成的(而不是连续生成的)。

密码需要令人难忘 - 这意味着密钥len成为一个因素。因此,我要去一个 4位引脚。还有数字,因为字母数字比纯数字更难忘(根据我进行的可用性测试 - 我坚持这些结果)。

我不能在密码代码之间发生冲突,因为它们也会被用作标识符 - 所以它们都必须是唯一的。我的范围将在0000到9999之间。只有10K的独特组合可能。这是限制性的,但是引脚代码的可记忆性优先于可能的引脚代码池的大小。所以我会牺牲。

最后,将永久分配注册用户的密码。另一方面,未注册的用户将被分配保留不超过24小时的引脚,之后到期 - 因此再次进入未使用的引脚池

想象一下我上面的数据模型(在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_code对象分配一个可用的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_code。每个已注册和未注册的用户都会分配一个可在example.com/pin/XXXXXXXXpin_code)访问的收件箱。用户可以通过社交媒体与他们的朋友分享此收件箱地址。然后,朋友可以通过他们的移动号码登录它,查看前用户特别为所述朋友的眼睛留下的内容。抓住漂移?

我为已注册和未注册的用户都需要此功能 - 因此需要为{1}}分配给未知用户。但我希望能够回收未注册的用户代码,这样我就不会太快耗尽10K的可能性。我在这个网站上有一个中等大的用户群。

最终,我用完10K组合。我想我会写代码,然后无缝转换到5位数的引脚。但即使在这种情况下,如果任何4位数的引脚过期并可用,它们将在分配期间获得优先权。如果你也可以帮助我,那就太好了!

4 个答案:

答案 0 :(得分:1)

您需要的只是RandomCharFielddjango-extensions包。请参阅django-extensions docs

RandomCharField(length=4, include_alpha=False)
# 7097

在您的代码中:

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)

答案 1 :(得分:0)

相当一个故事,但我不是100%确定你的问题是什么。如何生成随机数?

import random
print('%04d' % random.randint(0, 10000))

将其置于while循环中以确保它尚未存在于数据库中。或者,使用used布尔值在数据库中预生成10000个引脚号的列表,以获得更高效的解决方案。

我不得不问,是否记得真的有要求?如果是,是不是一个自定义字符串更好的主意?随机数字并不容易记住,人们更善于记住他们自己想到的东西。

答案 2 :(得分:0)

用于密码分配;我很相信你的代码做了类似的事情:

首先,我将保留所有代码可能性的列表(现在也可以创建列表),因此将是一个简单的表: 独特-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_list的数据库表,其他调用必须等到db_list可用,这样你就不会意外地分配一个引脚(不太可能使用rand,但可能发生在足够忙碌的小站点。)

另一种选择是为您的网址添加更多复杂性,例如 example.com/USER_NAME/XXXX

让用户选择XXXX并确保它们具有唯一的名称。对于那些未注册的人,您可以指定一个随机单词。

如果那太复杂了;我建议允许长度为3到6的代码 example.com/pin/XXX example.con /销/ XXXX example.com/pin/XXXXX等

如果分配了引脚,则所有工作。这会大大增加您的游泳池大小。

答案 3 :(得分:0)

如果您改为

,该怎么办?
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)

然后获取一个引脚,只需简单地查询PinCodes,查找下一个无主或未到期的PinCodes。