如何在Docker化的Django中运行迁移?

8

我跟随了一个Docker + Django教程,非常好,按照指示成功地构建和运行了网站。但是,我无论如何都无法弄清楚如何在更改模型后成功运行数据库迁移。

这是我所采取的步骤:

  1. 克隆相关的 git repo
  2. 设置一个名为 dev 的虚拟机:

    • 使用 docker-machine create -d virtualbox dev
    • 并用 eval $(docker-machine env dev) 指向它。
  3. 构建并启动它:

    • docker-compose build
    • 然后 docker-compose up -d
  4. 运行初始迁移 (唯一一次我能够成功运行迁移):

    • docker-compose run web python manage.py migrate
  5. 通过导航到由以下命令返回的 IP 地址来检查网站是否正常工作:

    • docker-machine ip dev
  6. 对模型进行更改。我只是在 web/docker_django/apps/todo/models.py 文件中的 Item 模型中添加了以下内容:

    • name = models.CharField(default='Unnamed', max_length=50, null=False)
  7. 更新镜像并重新启动容器:

    • docker-compose down --volumes
    • 然后 docker-compose build
    • 然后 docker-compose up --force-recreate -d

迁移尝试1:

我使用了:

docker-compose run web python manage.py makemigrations todo

然后:

docker-compose run web python manage.py migrate

在执行makemigrations命令后,它显示:
Migrations for 'todo':
  0001_initial.py:
    - Create model Item

当我运行 migrate 命令时,它给出了以下消息:
Operations to perform: 
  Synchronize unmigrated apps: messages, todo, staticfiles 
  Apply all migrations: contenttypes, admin, auth, sessions 
Synchronizing apps without migrations: 
  Creating tables... 
    Running deferred SQL... 
  Installing custom SQL... 
Running migrations: 
  No migrations to apply. 

那个方法没起作用。

迁移尝试第二步:

这一次我尝试直接在正在运行的 web 容器内运行迁移。看起来是这样的:

(macbook)$ docker exec -it dockerizingdjango_web_1 bash
root@38f9381f179b:/usr/src/app# ls
Dockerfile  docker_django  manage.py  requirements.txt  static  tests
root@38f9381f179b:/usr/src/app# python manage.py makemigrations todo
Migrations for 'todo':
  0001_initial.py:
    - Create model Item
root@38f9381f179b:/usr/src/app# python manage.py migrate
Operations to perform:
  Synchronize unmigrated apps: staticfiles, messages
  Apply all migrations: contenttypes, todo, admin, auth, sessions
Synchronizing apps without migrations:
  Creating tables...
    Running deferred SQL...
  Installing custom SQL...
Running migrations:
  Rendering model states... DONE
  Applying todo.0001_initial...Traceback (most recent call last):
  File "/usr/local/lib/python3.5/site-packages/django/db/backends/utils.py", line 62, in execute
    return self.cursor.execute(sql)
psycopg2.ProgrammingError: relation "todo_item" already exists

此外,我在该容器中找不到任何“迁移”文件夹。
我显然对底层发生的事情一无所知,因此如果有人能向我展示如何成功更改模型并运行数据库迁移,我将不胜感激。如果您可以帮助我理解运行这些命令时发生了什么,以使Web和Postgres图像能够协同工作,则会获得额外的积分。
编辑:对我有用的是什么
@MazelTov的建议将有助于我在逐渐熟悉使用Docker开发的过程中自动化该过程,但我错过的是,@MazelTov在非常有帮助的讨论中告诉我要挂载,以便在我的本地机器上显示迁移。
因此,基本上,如果我没有像这样执行: 迁移尝试1 那么就会很好。
docker-compose run web python manage.py makemigrations todo

...我使用了:

docker-compose run --service-ports -v $(pwd)/web:/usr/src/app web python manage.py makemigrations todo
2个回答

9

有很多方法可以实现这个目标。

1)在bash脚本中启动应用程序(uwsgi、runserver等)之前,请运行./manage.py migrate。

Dockerfile

FROM debian:latest

...

# entrypoint, must be executable file chmod +x entrypoint.sh
COPY entrypoint.sh /home/docker/entrypoint.sh

# what happens when I start the container
CMD ["/home/docker/entrypoint.sh"]

entrypoint.sh

#!/bin/bash

./manage.py collectstatic --noinput
# i commit my migration files to git so i dont need to run it on server
# ./manage.py makemigrations app_name
./manage.py migrate

# here it start nginx and the uwsgi
supervisord -c /etc/supervisor/supervisord.conf -n

2) 如果你有很多迁移文件并且不想出现任何停机时间,你可以从单独的docker-compose服务中运行迁移命令。

docker-compose.yml

version: '3.3'

services:  

  # starts the supervisor (uwsgi + nginx)
  web:
    build: .
    ports: ["80:80"]

  # this service will use same image, and once the migration is done it will be stopped
  web_migrations:
    build: .
    command: ./manage.py migrate

谢谢您的回复!但是我无法让您的建议起作用...您是否愿意在聊天室里帮助我?无论如何,我会尝试描述我遇到的问题。首先,提交迁移文件听起来像个好主意,但我不知道如何将我在docker容器中生成的迁移文件取回到我的本地文件中。无论如何,在入口点中放置makemigrations或migrate似乎没有任何作用...从单独的容器运行迁移的第二种方法抱怨找不到manage.py... - Ben Lindsay
第二种方法需要在Dockerfile中将WORKDIR设置为您的项目所在的文件夹(manage.py文件),因为如果您不在Dockerfile中设置WORKDIR,则最有可能在根目录/下运行命令。 - Mazel Tov
1
这是一个很好的例子,说明为什么应该在远程机器(例如Gitlab-CI)上构建镜像,因为您会发现所有必要的文件都必须提交到git中....回答你的问题...当你构建镜像时,我相信你会将代码复制到镜像内部,那么为什么不在那里运行'makemigrations'呢? - Mazel Tov
据我所知,./manage.py migrate 只会影响数据库而不会影响 Django 项目。 - Mazel Tov
让我们在聊天中继续这个讨论 - Ben Lindsay
显示剩余2条评论

2
我通过以下方式解决了这个问题:

docker-compose exec web /usr/local/bin/python manage.py makemigrations todo

然后:
docker-compose exec web /usr/local/bin/python manage.py migrate 

我从这个问题中得到了它。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接