【问题标题】:Dockerized Django: how to manage sql scripts in migrations?Dockerized Django:如何在迁移中管理 sql 脚本?
【发布时间】:2019-09-18 06:14:48
【问题描述】:

对于 Docker 来说还很新,我正在尝试将自定义 sql 脚本(触发器和函数)的执行添加到 Django 的迁移过程中,我开始感到有点失落。总体而言,我想要实现的目标遵循这个漂亮的clear tutorial。在本教程中,迁移是通过执行入口点脚本来实现的。在 Dockerfile 中:

# run entrypoint.sh
ENTRYPOINT ["/usr/src/my_app/entrypoint.sh"]

这里是 entrypoint.sh

#!/bin/sh

if [ "$DATABASE" = "postgres" ]
then
    echo "Waiting for postgres..."

    while ! nc -z $SQL_HOST $SQL_PORT; do
      sleep 0.1
    done

    echo "PostgreSQL started"
fi

# tried several with and without combinations
python manage.py flush --no-input 
python manage.py makemigrations my_app 
python manage.py migrate

exec "$@"

到目前为止一切顺利。关于在迁移过程中集成自定义sql脚本的执行的问题,我看的大部分文章(例如this one)都建议创建一个空迁移来添加sql语句的执行。这是我所拥有的 my_app/migrations/0001_initial_data.py

import os
from django.db import migrations, connection

def load_data_from_sql(filename):
    file_path = os.path.join(os.path.dirname(__file__), '../sql/', filename)
    sql_statement = open(file_path).read()
    with connection.cursor() as cursor:
        cursor.execute(sql_statement)

class Migration(migrations.Migration):
    dependencies = [
        ('my_app', '0001_initial'),
    ]

    operations = [
        migrations.RunPython(load_data_from_sql('my_app_base.sql'))
    ]

dependencies 所述,此步骤取决于初始步骤 (0001_initial.py):

from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion


class Migration(migrations.Migration):

    initial = True

    dependencies = [
        migrations.swappable_dependency(settings.AUTH_USER_MODEL),
    ]

    operations = [
        migrations.CreateModel(
            name='Unpayed',
            fields=[
etc etc 

[问题] 但是,即使我尝试手动迁移 (docker-compose exec web python manage.py makemigrations my_app),我也会收到以下错误,因为 postgresql 容器中的 db 是 empty

File "/usr/src/my_app/my_app/migrations/0001_initial_data.py", line 21, in Migration
    migrations.RunPython(load_data_from_sql('my_app_base.sql'))
  File "/usr/local/lib/python3.7/site-packages/django/db/backends/utils.py", line 82, in _execute
....
    return self.cursor.execute(sql)
    django.db.utils.ProgrammingError: relation "auth_user" does not exist

[我不明白的地方] 但是,当我登录容器时,删除0001_initial_data.py 并运行./entrypoint.sh,一切都像魅力一样工作并创建了表格。我可以稍后手动添加0001_initial_data.py,再次运行entrypoint.sh 并拥有我的功能。当我在运行docker-compose up -d --build 之前删除此文件时也是如此:已创建表。

我觉得我错过了一些明显的方法,并且在尝试以这种规范方式集成 sql 脚本迁移时更容易。我只需要在 0001_initial 迁移结束后运行这个脚本。你会怎么做?

[编辑] docker-compose.yml:

version: '3.7'

services:
  web:
    build: 
      context: ./my_app
      dockerfile: Dockerfile
    command: python /usr/src/my_app/manage.py runserver 0.0.0.0:8000
    volumes:
      - ./my_app/:/usr/src/my_app/
    ports:
      - 8000:8000
    environment:
      - SECRET_KEY='o@@xO=jrd=p0^17svmYpw!22-bnm3zz*%y(7=j+p*t%ei-4pi!'
      - SQL_ENGINE=django.db.backends.postgresql
      - SQL_DATABASE=postgres
      - SQL_USER=postgres
      - SQL_PASSWORD=N0tTh3D3favlTpAssw0rd
      - SQL_HOST=db
      - SQL_PORT=5432
    depends_on:
      - db
  db:
    image: postgres:10.5-alpine
    volumes:
      - postgres_data:/var/lib/postgresql/data/ 

volumes:
  postgres_data:

django:2.2 蟒蛇:3.7

【问题讨论】:

  • 为什么在 Docker 文件中运行 makemigrationsmy_app/migrations/0001_initial.py 签到了吗?
  • “签到”?你的意思是,在我docker-compose up之后的容器中?是的。以及为什么makemigrations 在入口点?老实说,因为我发现这个“创建一个空的迁移以在迁移期间执行自定义 sql”的技巧非常令人困惑,只是为了弄清楚它是否改变了一些东西。我认为makemigrations必须在migrate之前运行
  • “签入”就像在“签入到版本控制”中一样。或者换句话说,迁移0001_initial是否存在docker-compose up之前?
  • 是的。它在我docker-compose up 之前的源文件中(如果我理解正确的话)
  • 请分享您的撰写文件。还有什么版本的python和django?

标签: django postgresql docker database-migration devops


【解决方案1】:

我相信问题与您命名迁移文件并手动使用相同的前缀“0001”创建依赖项有关。我之所以这么说是因为当您进行反向迁移时,您只需引用前缀即可。如果您想从第 7 次迁移到第 6 次迁移,请使用 IE。该命令看起来像这样python manage.py migrate my_app 0006 无论哪种方式,我都会尝试通过python manage.py makemigrations my_app --empty 删除并创建一个新的迁移文件并将您的代码移动到该文件中。这也应该为您编写依赖项。

但是,您在添加迁移文件后运行的测试旁边的错误消息表明存在问题。一些初始迁移在另一个迁移之前没有运行。我也会尝试删除您的数据库,因为它可能会持续存在一些不良状态./manage.py sqlflush

【讨论】:

  • 我刚刚尝试将文件重命名为0002_create_custom_functions.py(手动和makemigrations --empty),但问题仍然存在。我可以拥有这张桌子的唯一方法是在我构建时只让0001_initial.py。每次尝试后,我都会通过docker-compose down -v 删除数据库。我对entrypoint.sh 中的flush --no-inputmigrate 命令有点困惑。我是否可以假设 /my_app/migrations 中的所有迁移都应该由 migrate 运行?
  • 您是否想到了一种更简单的方法来在之后(在经典迁移过程之外)执行此脚本?该应用程序的cointainer 没有psql,但db 有。也许将 sql 脚本从 app 发送到 db,登录并运行它(就像我手动执行的操作一样)。我注意到manage.py 有某种dbshel​​l。我有机会通过它运行脚本吗?
  • 这么几件事。我做事的方式是写一个引导脚本。可以说boot.sh。我把所有的 migrate 和 runserver 都放在那里。我没有将 makemigrations 放在该引导脚本中,因为我运行它手动将迁移文件提交到 repo。而不是在 docker 文件中包含所有这些命令,我​​将其作为命令 command: bootprod.sh bootprod 包含 pip install -r requirements.txt python3 manage.py migrate && python3 manage.py runserver
【解决方案2】:

[我能找到的最简单的方法] 我只是将 django 迁移与在数据库中创建自定义函数分开。首先运行迁移,以便在创建函数时表存在。这是 entrypoint.sh

#!/bin/sh

if [ "$DATABASE" = "postgres" ]
then
    echo "Waiting for postgres..."

    while ! nc -z $SQL_HOST $SQL_PORT; do
      sleep 0.1
    done

    echo "PostgreSQL started"
fi

python manage.py flush --no-input
python manage.py migrate

# add custom sql functions to db 
cat my_app/sql/my_app_base.sql | python manage.py dbshell

python manage.py collectstatic --no-input

exec "$@"

请记住,manage.py dbshell 需要 postgresql-client 才能运行。我只需要将它添加到 Dockerfile 中:

# pull official base image
FROM python:3.7-alpine

...........

# install psycopg2
RUN apk update \
    && apk add --virtual build-deps gcc python3-dev musl-dev \
    && apk add postgresql-dev postgresql-client\
    && pip install psycopg2 \
    && apk del build-deps

【讨论】:

    猜你喜欢
    • 2018-07-20
    • 2018-11-06
    • 2021-06-23
    • 2017-05-21
    • 2020-03-14
    • 1970-01-01
    • 1970-01-01
    • 2020-08-24
    • 1970-01-01
    相关资源
    最近更新 更多