在Django中排队请求图片

Queuing pictures to be requested in Django

我正在建立一个系统,其中一个用户将 posting 图像发送到 Django 服务器,N 个用户将同时查看 posted 图像的一个子集。我似乎无法在 Django 中找到一个队列机制来完成这个任务。最接近的是将 latest 与 filter() 一起使用,但这只会一遍又一遍地发送最新图像,直到出现新图像。任务队列没有帮助,因为这不是周期性任务,它仅在用户请求下一张图片时发生。我有一个 Viewset 用于上传图像,另一个用于获取。我考虑过使用 python 线程安全队列。卸载程序会将上传的图像 pk 排入队列,当多个用户请求新图像时,发送视图集会将图像 pk 出队并将其发送给最近请求图像的用户,然后下一个出队给第二个最近的用户和等等...

但是,我仍然觉得这里可能存在一些竞争条件。我读到 Django 是线程安全的,但该应用程序可能会变得非线程安全。此外,队列需要是全局的才能在视图集之间共享,这感觉是不好的做法。有没有更好更安全的方法来解决这个问题?

编辑

这里有更多关于我正在努力完成的事情的详细信息,并提供了一些背景信息。拍摄照片的用户 post 是连接到无人机的 Smart-phone。它将 post 以恒定的间隔从空中向 Django 服务器发送图片。因为会有很多图片进来。我希望能够让多个用户分担查看所有图片的工作量(即没有两个用户应该看到相同的图片)。因此,当用户联系 Django 服务器时,会说 "send me the next pic you have or send me the next 3 pics you have or etc..."。但是,多个用户可能会同时说这句话。所以 Django 需要对图片保持某种排序,这就是为什么我说 Queue 并弄清楚如果一次有多个用户请求时如何将它传递给用户。因此,一个 Viewset 是供智能 phone 到 post 图片的,另一个是供用户索取图片的。我正在寻找一种线程安全的方法来做到这一点。到目前为止我唯一的想法是使用 Python 的线程安全队列并使其成为视图集的全局队列。但是,我觉得这是一种不好的做法,而且我不确定它在 Django 中是否是线程安全的。

Django本身没有队列,但是你可以很容易的模拟出来。就个人而言,我可能会使用外部服务,如 rabbitMQ,但如果你愿意,也可以在纯 Django 中完成。添加一个单独的 ImageQueue 模型来保存对传入图像的引用,并使用事务管理来确保同时请求不会 return 相同的图像。也许是这样的(当然,这纯粹是概念代码的证明)。

class ImageQueue(models.Model):
    image = models.OneToOne(Image)
    added = models.DateTimeField(auto_now_add=True)
    processed = models.DateTimeField(null=True, default=None)
    processed_by = models.ForeignKey(User, null=True, default=None)

    class Meta:
        order_by=('added')

...
# in the incoming image API that drone uses
def post_an_image(request):
    image = Image()
    ... whatever you do to post an image ...
    image.save()
    queue = ImageQueue.objects.create(image=image)
    ... whatever else you need to do ...

# in the API your users will use
from django.db import transaction

@transaction.atomic
def request_images(request):
    user = request.user
    num = request.POST['num'] # number of images requested
    queue_slice = ImageQueue.objects.filter(processed__isnull=True)[:num]
    for q in queue_slice:
        q.processed = datetime.datetime.now()
        q.processed_by = user
        q.save()
    return [q.image for q in queue_slice]