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'))
]
如依赖关系所述,此步骤取决于初始值(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为空:
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 angain并拥有我的功能。在运行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 python:3.7
我相信这个问题与您命名迁移文件并手动使用相同的前缀“0001”进行依赖关系我之所以这样做是因为当您进行反向迁移时,您只需引用前缀即可。 IE如果你想从第7次迁移到第6次迁移。该命令看起来像这个python manage.py migrate my_app 0006
无论哪种方式,我会尝试通过python manage.py makemigrations my_app --empty
删除并创建一个新的迁移文件,并将您的代码移动到该文件中。这也应该为您编写依赖项。
与您之后添加迁移文件所运行的测试一起出现的错误消息表明了问题。一些初始迁移如何在另一个之前没有运行。我也会尝试丢弃你的数据库,因为它可能持有一些糟糕的状态./manage.py sqlflush
[我能找到最简单的方法]我只是从数据库中创建自定义函数中解开了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