首页 > 解决方案 > Django 将 FileField 中的文件保存在 docker 容器中

问题描述

我有一个带有 FileField 的模型。我的应用程序在使用 dockerfile 创建的 docker 容器中运行。当我保存文件时,它会保存在我的本地路径而不是容器的基础根目录中。但是,当我尝试检索文件并将其作为电子邮件附件发送时,我收到一个未找到文件的错误。媒体根目录基于 Dockerfile 的基本根目录。电子邮件作为异步任务在另一个容器中构建和发送。Dockerfile 看起来像这样:

# pull official base image
FROM python:3.9.1-alpine

# set work directory
#ENV APP_HOME=/code
#RUN mkdir $APP_HOME
#RUN mkdir $APP_HOME/static
#RUN mkdir $APP_HOME/media
#WORKDIR $APP_HOME
WORKDIR /code

# set environment variables
ENV PYTHONDONTWRITEBYTECODE 1
ENV PYTHONUNBUFFERED 1

COPY requirements.txt /code/

RUN apk --update --upgrade --no-cache add \
    postgresql-libs make gdal-dev geos-dev g++ python3-dev cairo-dev pango-dev gdk-pixbuf-dev ttf-ubuntu-font-family

RUN \
    apk add --virtual .build-deps gcc musl-dev postgresql-dev jpeg-dev zlib-dev libffi-dev && \
    pip3 install --no-cache-dir -r /code/requirements.txt && \
    apk --purge del .build-deps

COPY entrypoint.sh /entrypoint.sh
RUN chmod +x /entrypoint.sh

# copy project
COPY . /code/

我有一个 docker-compose 文件来构建图像并运行容器。它看起来像这样:

version: "3.9"

services:
  db:
    image: postgis/postgis:13-3.0-alpine
    volumes:
      - postgres_data:/var/lib/postgresql/data/
    # TODO remove ports for production
    ports:
      - "5432:5432"
    environment:
      - POSTGRES_DB=DB
      - POSTGRES_USER=USER
      - POSTGRES_PASSWORD=PW
  api:
    build: .
    image: app/api
    command: python manage.py runserver 0.0.0.0:8000 --settings=api.settings.production
    volumes:
      - .:/code
      - static:/code/static
      - media:/code/media
    ports:
      - "8000:8000"
    env_file:
      - ./.env.dev
    depends_on:
      - db
    entrypoint: /entrypoint.sh
  mail:
    image: app/api
    command: python manage.py qcluster --settings=api.settings.production
    depends_on:
      - api

volumes:
  postgres_data:
  static:
  media:

示例模型如下所示:

def order_nested_item_directory_path(instance, filename):
    # file will be uploaded to MEDIA_ROOT/orders/user_<id>/<filename>
    user_id = instance.order.user.id if instance.order.user else 'anonymous'
    return f'orders/user_{user_id}/order_{instance.order.id}/{filename}'

class Invoice(TimeStampedModel):
    order = models.ForeignKey(Order, related_name='invoices', on_delete=models.CASCADE)
    number = models.CharField(max_length=100)
    pdf = models.FileField(upload_to=order_nested_item_directory_path)

使用媒体根设置:

BASE_DIR = Path(__file__).resolve().parent.parent.parent
MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')

任何人都可以帮助如何将文件保存在 Dockerfile 的基本根目录中?

标签: djangodockerdjango-rest-frameworkdocker-compose

解决方案


我不确定它是否能解决您的问题,但如果您想使用 docker-compose 在容器之间共享命名卷中的数据,您需要将这些卷添加到所有这些容器或使用扩展字段。

由于第一件事更容易,只需添加

    volumes:
      - media:/code/media

到您mail在 docker-compose 中的服务。

之后重建你的容器。

然后,当它运行时,运行docker exec -it <image id> sh并检查是否/code/media存在。


推荐阅读