【问题标题】:django rest single thread / blocking viewdjango rest单线程/阻塞视图
【发布时间】:2018-12-26 16:34:16
【问题描述】:

是否可以阻止视图中的代码在单个用户执行时阻止所有访问视图的用户执行?一种单线程视图。

我需要它,因为我在此视图中使用pyinstaller 生成 python 可执行文件,并通过配置文件将用户名传递给可执行文件。

例如:

class CliConfig(APIView):

    def get(self, request, format=None):
        try:
            config['DEFAULT']['username'] = request.user

            #make a build with pyinstaller
            bin_file = open(*generated filepath *, 'rb')
            response = Response(FileWrapper(bin_file), content_type='application/octet-stream')
            response['Content-Disposition'] = 'attachment; filename="%s"' % '*filename*'
            return response
        finally:
            config['DEFAULT']['username'] = ''

所以,基本上我想要的是生成一个 python 可执行文件,它将在 django rest 框架APIView 中设置一个唯一的用户名。除了通过设置文件传递用户名之外,我没有看到其他方法。如果有办法 - 将不胜感激。

python 3.6.5djangorestframework==3.8.2pyinstaller==3.3.1

【问题讨论】:

  • 生成的文件路径是如何创建的?对于每个请求都有一个唯一的而不是阻止其他人生成安装程序,您感觉如何?编辑:啊,我看到了问题。你想锁定修改你的config['DEFAULT']['username']
  • 为什么不为每个请求创建一个不同名称的配置文件呢? tempfile 模块可能对此有所帮助。
  • 如果配置名称不同,构建将不会知道新的配置名称
  • 大概你有多个并行运行的工作进程。如果您只有一个进程和一个线程(如在 django 开发运行服务器中),一次只会处理一个请求,并且保证没有竞争条件。如果你有多个wsgi工作进程,在一个进程中修改settings不会对其他进程产生任何影响。您必须创建一个在工作人员之间共享的锁。例如数据库锁。 docs.djangoproject.com/en/2.0/ref/models/querysets/…
  • 我相信这个问题是这个的副本(由于赏金,不能将这个作为副本提交)stackoverflow.com/questions/1123200/… 如果您不需要这个扩展到多个服务器,最简单的解决方案是使用数据库锁或文件系统锁。

标签: python django python-3.x django-rest-framework pyinstaller


【解决方案1】:

看看 Django-channels 项目。通道为开发人员提供了抽象,并支持包括 HTTP 在内的许多协议。您可以将关键页面重写为渠道消费者。因此,您将能够使用async/await 构造以块方式编写异步代码。 https://channels.readthedocs.io/en/latest/topics/consumers.html#asynchttpconsumer

您也可以通过 Javascript 显示锁定状态并使用 Redis 锁定机制:https://redis.io/topics/distlock

# <settings_dir>/settings.py
ASGI_APPLICATION = "my_app.routing.application"


# my_app/routing.py
from channels.routing import ProtocolTypeRouter

from .consumers import LockConsumer


application = ProtocolTypeRouter({
    "websocket": AuthMiddlewareStack(
        URLRouter([
            url("^ws/lock$", LockConsumer),
        ])
    ),
})


# my_app/consumers.py
class LockConsumer(JsonWebsocketConsumer):

    def connect(self):
        if self.scope['user'].is_authenticated:
            self.accept()
        else:
            self.close(code='unauthorized')
        pass

    def receive_json(self, content, **kwargs):
       # process lock procedures
       # try to lock by REDIS API
       # if locked -> show alarm to user by javascript 


# template, see fuul doc here http://channels.readthedocs.io/en/latest/javascript.html
...
<script src="{% static "websocketbridge.js" %}"></script>
....

【讨论】:

    【解决方案2】:

    为什么要将用户名存储在配置中? 这一代不应该是每个用户吗?

    无论如何,在视图中执行耗时的任务并不是一个好习惯。
    Celery 用于将生成可执行文件并在不停止 Django 的情况下接受任何变量的长期任务。在此任务结束时Celery 可以将可执行文件发送到电子邮件或其他东西。

    from celery import Celery
    
    app = Celery('hello', broker='amqp://guest@localhost//')
    
    
    @app.task
    def generate_executable(username):
        # make a build with pyinstaller with username
    
        bin_file = open(*generated filepath *, 'rb')
        response = Response(FileWrapper(bin_file), content_type='application/octet-stream')
        response['Content-Disposition'] = 'attachment; filename="%s"' % '*filename*'
    
        # send email and/or returns as task result
    
        return response
    
    
    class CliConfig(APIView):
    
        def get(self, request, format=None):
            task = generate_executable(request.user)
            task.delay()
    
            return Response({"status": "started", "task_id": task.task_id})
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-07-06
      • 1970-01-01
      • 1970-01-01
      • 2015-12-04
      • 2016-01-27
      • 1970-01-01
      • 2018-02-16
      • 1970-01-01
      相关资源
      最近更新 更多