【问题标题】:Django Download/Upload Files In ProductionDjango 在生产环境中下载/上传文件
【发布时间】:2021-03-13 01:35:21
【问题描述】:

我有一个当前托管的 Django 项目。我正在提供静态文件,但不知道如何处理 MEDIA 文件夹中的用户文件上传/下载。我读过很多关于 Docker、Nginx 和 Gunicorn 的文章,但不知道我需要哪些,也不知道如何设置它们。我学习了不少于 20 个教程,观看了不少于 15 个 YouTube 视频,但仍然感到困惑(我访问了所有 Google 搜索的前 2 页的每个链接)。

我的问题是,我需要其中哪些来允许用户从站点上传/下载文件?最重要的是,我已经尝试让所有三个工作但无法弄清楚,当然我不是唯一一个对此有这么多困难的人,是否有一个很好的资源/教程可以指导我完成整个过程(我已经花了 40 多个小时来阅读这些东西并试图让它发挥作用,我已经到了只要它有效,我就不关心理解它们是如何组合在一起的)?

谢谢。

edit - 这是所请求内容的精简版本。我没有包含 html,因为这是我第一次这样做,而且我使用过 Ajax 和其他东西,这完全是一团糟,我肯定会让你感到困惑。

settings.py

STATIC_URL = '/static/'
STATIC_ROOT = os.path.join(BASE_DIR, 'static_files')

MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'static_media')

STAT=os.path.join(BASE_DIR, 'static')

STATICFILES_DIRS = [ STAT,
                    os.path.join('static/'),
                    os.path.join('templates/static/'), # for overridden templates css
                    ]

view.py

class UploadView(View):
    def get(self, request):
        files_list = UploadedFile.objects.all()
        return render(self.request, 'users/modules.html', {'files': files_list})

    def post(self, request, *args, **kwargs):
        data = {}
        
        form = UploadedFileForm(self.request.POST, self.request.FILES)
        form.instance.data_id = self.request.POST['data_id']

        if form.is_valid():
            uploaded_file = form.save()

谢谢。

【问题讨论】:

  • 此时最好停止阅读,开始编码。任何文件上传都从带有 HTML 表单的页面开始。因此,作为第一步,您需要一个 Django 视图来显示用户可以上传文件的页面。
  • @DmitryBelaventsev 我已经建立了一个用户登录等的网站。所以我已经弄清楚(在 StackOverflow 的人们的帮助下)我遇到的大多数问题(从开发到生产服务器的过渡特别困难)。我已经创建了用户上传/下载文件的页面,但尽管我阅读和编码,但我无法弄清楚如何在生产中提供这些服务。它在我的开发环境中运行良好。
  • 好的,那么您能否显示:所有 STATIC* 和 MEDIA* 设置、负责文件上传的视图、带有上传表单的 html?你已经使用 docker/uwsgi/gunicorn/nginx 了吗?如果是这样,请告诉我你的 Dockerfile 和/或 docker compose config。
  • @DmitryBelaventsev 当然。我添加了您所要求的内容的精简版。我没有包括一些东西,因为这是我第一次这样做,而且我使用过 Ajax 和其他东西,所以它非常非常混乱。我应该补充一点,这实际上适用于我的开发服务器,但我知道我应该使用诸如 docker/uwsgi/gunicorn/nginx 之类的东西。不,我还没有实现 docker/uwsgi/gunicorn/nginx。谢谢。

标签: django docker nginx gunicorn


【解决方案1】:

所以您想知道如何使您的(在开发环境中工作)项目准备好生产。让我们从需要哪些组件开始

  1. Web 服务器 (Nginx)
  2. 应用服务器 (uWSGI)
  3. 应用程序(Django

Web 服务器 为用户的请求提供服务。它知道如何为请求生成正确的输出——从文件系统读取文件,将请求进一步传递给应用服务器等等。 Nginx 是不错的选择。

Application ServerWeb ServerApplication 之间的中间人。它可以生成应用程序实例(进程)、平衡这些实例之间的负载、重启死实例和许多其他事情。 uWSGI 是不错的选择。

应用程序 - 在您的情况下,它是您在开发环境中工作的 Django 项目。你已经准备好了一切,但很可能你应该稍微调整一下设置。 Django 将通过 WSGI 协议与 Application Server 进行通信。


此时您还应该了解网络浏览器将如何加载、呈现和显示您的网站。一切都始于想要在您的网站上打开页面的用户,例如http://example.com/uploads。浏览器将向您的服务器发送 HTTP GET 请求,Web 服务器程序 (Nginx) 将捕获此请求并决定下一步做什么。

由于该特定请求不是关于某个静态文件(静态 HTML 文件或静态 JPEG 图像等) - Nginx 将决定将请求传递给应用程序服务器。 uWSGI 将获取请求并将其转发给 Django。

Django 将使用所有urls.py 文件找到正确的视图以生成http://example.com/upload 页面的响应。你的观点会做什么?

    def get(self, request):
        files_list = UploadedFile.objects.all()
        return render(self.request, 'users/modules.html', {'files': files_list})

它将返回 HTML 页面(呈现的模板)。这样 HTML 文档将返回到 Application Server,然后返回到 Web Server,最后返回到用户的 Web 浏览器。

然后浏览器将开始解析该 HTML 文档,并且很可能会找到一些额外的资源来加载 - css、javascript、图像、字体……对于每个资源 - 它会向 Web 服务器发出额外的 GET 请求。而这一次 Web Server 不会将请求转发到 Application Server。它只会从文件系统中读取这些文件并返回给浏览器。

这些资源不是动态的,它们是静态的。因此,您基本上将它们存储在 static 命名空间下。例如:

这些文件是您的应用程序的一部分。您的应用程序随这些文件一起提供。但也有一些文件可以上传到您的系统。您可以将这些文件保存在任何地方——文件系统、数据库……但您必须有它们的 URL。通常是media命名空间:

在这两种情况下 - 这些调用将只转发到 Web 服务器,然后转发到文件系统。

为什么您会在开发环境中看到一切正常?这可能是因为您使用python manage.py runserver 运行应用程序。在这种情况下 - Django 也是您的 Web 服务器(并且不会有应用程序服务器中间人)。所以它会管理自己的实例,它会获取用户的请求,它会返回静态文件,它会返回“媒体”文件,它会返回动态生成的页面等等。


上面描述的每个组件都需要它自己的配置文件。让我向您展示一些可用于您的项目的示例。

网络服务器 (Nginx)

sites-enabled/default.conf

upstream uwsgi {
  server uwsgi:8080;
}


server {
  listen 80 default_server;
  listen [::]:80 default_server;

  error_log /var/log/nginx/error.log;

  charset utf-8;

  location /media  {
      alias /home/web/media;
      expires 7d;
  }

  location /static {
      alias /home/web/static;
      expires 7d;
  }

  location / {
      uwsgi_pass uwsgi;
      include uwsgi_params;
  }
}

注意事项:

应用服务器 (uWSGI)

uwsgi.conf

[uwsgi]

req-logger = file:/var/log/uwsgi-requests.log
logger = file:/var/log/uwsgi-errors.log

workers = %k
# enable-threads = true
# threads = 4

chdir = /home/web/app
module = core.wsgi
master = true
pidfile=/tmp/app.pid
socket = 0.0.0.0:8080
env = DJANGO_SETTINGS_MODULE=core.settings
memory-report = true
harakiri = 60
listen = 10240

注意事项:

  • chdir = /home/web/app - 这是您的应用程序的路径
  • module = core.wsgi - 你的应用程序应该有一个名为core 的主(核心)应用程序目录(你应该在那里看到wsgi.py
  • pidfile=/tmp/app.pid - 只是一个 pid 文件的地方
  • socket = 0.0.0.0:8080 - 它将监听端口8080
  • env = DJANGO_SETTINGS_MODULE=core.settings - 同样,您需要将主应用程序称为 core(它应该在 core 目录中),并且您应该在其中有 settings.py

Docker / Docker Compose

您可能需要 Docker 和 Docker Compose 来编排所有这些软件。但也可以尝试在没有它的情况下运行所有​​内容。

docker-compose.yml

version: "2.4"

services:

  uwsgi:
    build:
      context: ./docker
      dockerfile: Dockerfile
    hostname: uwsgi
    sysctls:
      net.core.somaxconn: 10240
    environment:
      - DJANGO_SETTINGS_MODULE=${DJANGO_SETTINGS_MODULE}
      - C_FORCE_ROOT=${C_FORCE_ROOT}
    volumes:
      - ./config/uwsgi/uwsgi.conf:/uwsgi.conf
      - ../app:/home/web/app
      - ./static:/home/web/static:rw
      - ./media:/home/web/media:rw
      - ./logs:/var/log/
    restart: always
    networks:
      myapp_backend:
        aliases:
          - uwsgi

  web:
    image: nginx
    hostname: nginx
    sysctls:
      net.core.somaxconn: 10240
    depends_on:
      - uwsgi
    volumes:
      # - ./config/nginx/nginx.conf:/etc/nginx/nginx.conf
      - ./config/nginx/sites-enabled:/etc/nginx/conf.d
      - ./media:/home/web/media:ro
      - ./static:/home/web/static:ro
      - ./logs:/var/log/nginx
    ports:
      - "80:80"
      # - "443:443"
    restart: always
    networks:
      - myapp_backend

networks:
  myapp_backend:

Dockerfile

FROM python:3.9.0

RUN export DEBIAN_FRONTEND=noninteractive
ENV DEBIAN_FRONTEND noninteractive
RUN dpkg-divert --local --rename --add /sbin/initctl

RUN apt-get install -y --fix-missing && apt-get update -y

RUN apt-get install -y python3-pip \
    python3-setuptools

COPY requirements.txt /requirements.txt
RUN pip install -r /requirements.txt
RUN pip install uwsgi

WORKDIR /home/web/app

EXPOSE 8080

CMD ["uwsgi", "--ini", "/uwsgi.conf"]

目录结构

您可以使用此存储库中的目录结构:https://github.com/ansysy24/GameEconomy/tree/master/deployment

另外我强烈推荐这篇文章https://andrey-borzenko.medium.com/simple-nginx-uwsgi-daphne-reactive-application-part-1-the-big-picture-20d7b9ee5b96

不要忘记添加.env 像这样的文件https://github.com/ansysy24/GameEconomy/blob/master/deployment/.env_template(但你应该重命名ofc)

【讨论】:

  • 非常感谢。我真的很感激帮助。我的项目有很多需要吸收和实施的地方。至少一天后我会回复你,因为我需要那么多时间才能让它发挥作用。再次感谢。实施后我会给你一个更新:)
  • 谢谢。这很有帮助。我真的很感激。
  • 很高兴听到这个消息,布伦登。如果您有任何问题,请随时与我联系。
  • 您能否告知为什么uwsgi.conf 中的enable-threads 被注释掉了?谢谢,
猜你喜欢
  • 2017-08-18
  • 2018-02-27
  • 2018-08-28
  • 2014-10-13
  • 1970-01-01
  • 2018-09-18
  • 2015-11-26
  • 1970-01-01
  • 2019-08-06
相关资源
最近更新 更多