Dockerized Django:如何在迁移中管理SQL脚本?

时间:2019-04-29 15:28:16

标签: django postgresql docker database-migration devops

Docker 的新手,我试图将自定义 sql脚本(触发器和函数)的执行添加到Django的迁移过程中,我开始感到有点失落。总的来说,我要努力实现的目标是clear tutorial。在本教程中,迁移是通过执行入口点脚本来实现的。在Dockerfile中:

my_app/migrations/0001_initial_data.py

这是 entrypoint.sh

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'))
    ]

到目前为止,一切都很好。关于在迁移过程中集成自定义sql脚本的执行的问题,我阅读的大多数文章(例如,this one)都建议创建一个空迁移以添加sql语句的执行。这就是我所拥有的 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):

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),也会收到以下错误,因为postgresql容器中的 db是

./entrypoint.sh

[我不了解的地方]但是,当我登录到容器时,删除0001_initial_data.py并运行docker-compose up -d --build,一切都会像超级按钮一样工作并创建表。我可以稍后手动添加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: ,重新运行entrypoint.sh并具有我的功能。在运行library(lubridate) df[cols] <- lapply(df[cols], parse_date_time, c("mdy", "dmy", "dmY")) df # a b #1 1988-12-01 1988-12-01 #2 1999-10-17 <NA> 之前删除此文件时相同:创建表。

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

[编辑] docker-compose.yml:

df
django:2.2 python:3.7

2 个答案:

答案 0 :(得分:1)

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

您在运行测试并添加迁移文件之后运行的错误消息虽然表明存在问题。有些最初的迁移没有在其他迁移之前进行。我还尝试删除您的数据库,因为它可能一直处于某些错误状态./manage.py sqlflush

答案 1 :(得分:0)

[我能找到的最简单的方法],我只是将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