2016-03-09 32 views
1

我有一些特殊的要求,我試圖找出編碼它的最佳方法。 最好的效率最高,可維護性排在第二位。需求是這樣的(與我一起):Django網絡應用程序的棘手的編碼邏輯

我在我的Django網站上有一個功能,這意味着服務登記和未登記的用戶。這個功能將會在每個用戶的PIN碼之後被選通。我需要這些引腳是隨機生成的(而不是連續的)。

該PIN碼將需要難忘 - 這意味着引腳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)上訪問的收件箱。用戶可以通過社交媒體與他們的朋友分享這個收件箱地址。然後,朋友可以通過他們的手機號碼登錄到該用戶,查看前用戶留下的內容,特別是對於該朋友的眼睛。趕上漂移?

我需要此功能用於註冊和未註冊的用戶 - 因此需要分配pin_code甚至不知道的用戶。但我希望能夠回收未註冊的用戶代碼,以便我不會太快地用完10K的可能性。我在這個網站上有一個適度的大用戶羣。

最終雖然,我耗盡10K組合。我想我會寫代碼,然後無縫地切換到5位數的引腳。但即使在這種情況下,如果任何4位數的引腳過期並變得可用,它們在分配期間將優先考慮。如果你也可以幫助我完成這部分,那太棒了!

回答

1

所有你需要的是django-extensions包裝的RandomCharField。請參閱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) 
0

相當一個故事,但我不是100%確定你的問題是什麼。如何生成隨機數字?

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

把它放在while循環中以確保它在數據庫中不存在。或者,使用used布爾值預先生成數據庫中10000個PIN號碼的列表,以獲得稍微更高效的解決方案。


我不得不問,雖然真的記得要求嗎?如果是這樣,是不是一個更好的主意是一個自定義字符串?隨機數並不是那麼容易記住的,人們在記憶他們自己認爲的東西時會好得多。

+0

關於記憶:是的,它是一個必要條件。事情是,我也使用URL模式生成的引腳 - 從而避免衝突,他們必須是唯一的。但如果您暗示我允許用戶決定保留什麼,無論長短如何 - 我的用戶已經擁有'暱稱'我可以使用。但是很多人都是罕見的角色,有些角色是非常長的。如果你是複製粘貼,這將是很好,但我實際上有一個相當大的人口統計使用**功能手機**,實際上必須手動輸入網址來分享它們*(在我的可選部分閱讀更多內容題)*。 –

0

對於PIN碼分配;我相當確定你的代碼做了類似的事情:

首先,我將保留一個所有代碼可能性的列表(現在還可以創建列表),所以會是一個簡單的表格: unique-4-digit-代碼:分配布爾

然後我會創建一個函數:

須藤代碼:

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,但可能發生在與小池足夠忙碌的網站)。

另一種選擇是,以更多的複雜性添加到您的URL,例如 example.com/USER_NAME/XXXX

,並讓用戶選擇的XXXX,並確保他們有一個獨特的名字。對於未註冊的用戶,您可以指定一個隨機單詞。

如果這太複雜;我將在長度建議從3允許代碼6,使得 example.com/pin/XXX example.con /銷/ XXXX example.com/pin/XXXXX等

如果銷分配的所有工作。這將大大增加您的游泳池大小。

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的下一個地方是無主或逾期。