<p>您需要存储上次授权启动的时间,如果用户输入pin,则清除该时间戳</p>
<pre><code># models.py
class LockerUserQueue(models.Model):
user = models.ForeignKey(get_user_model())
locker = models.ForeignKey("yourapp.Locker")
created_at = models.DateTimeField(index=True, auto_now_add=True)
class Locker(models.Model):
last_authorization = models.DateTimeField(null=True, blank=True)
user_queue = models.ManyToManyField(through=LockerUserQueue)
class BadPin(Exception):
pass
def enqueue_user(self, user):
self.user_queue.add(user)
def process_authorization(self, user):
# do authorization for user
def process_pin(self, user, pin):
self.last_authorization = None
if validate_pin(user, pin):
# pin OK logic
else:
raise self.BadPin
# views.py
def authorize_user(request, locker_id):
locker = get_object_or_404(pk=locker_id)
locker.enqueue_user(request.user)
locker.save()
return render(request, "authorization_started.html")
def open_bay_with_pin(request, locker_id):
locker = get_object_or_404(pk=locker_id)
pin = get_pin_from_request(request)
try:
# No matter if the pin is correct, the locker.last_authorization is cleared
locker.process_pin(user, pin)
except locker.BadPin:
return render(request, "bad_pin.html")
finally:
locker.save()
return render(request, "good_pin.html")
# management/commands/process_queue.py
# you would run this by
# $ python manage.py process_queue
class Command(BaseCommand):
@transaction.atomic
def process_queue(self):
# you probably want to put the 3 min delay in your settings.py
# so you don't end up with a magic value here
for locker in LockerUserQueue.objects.filter(
Q(locker__last_authorization__isnull=True)|Q(locker__last_authorization__gt=now() - timedelta(minutes=3))
).order_by("created_at").values_list("locker", flat=True).distinct():
locker.process_authorization()
def handle(self):
while True:
self.process_queue()
# you don't want to keep querying the DB when there's nothing in the queue
sleep(5)
</code></pre>
<p>上面的代码显示了如何使用数据库作为队列,在低容量用例中,这应该很好。如果卷很大,我会将储物柜<code>last_authorization</code>存储在更快的存储中,比如<code>redis</code>,队列也可以在<code>redis</code>中维护。但背后的逻辑是一样的</p>