Dockerized Django: как управлять сценариями sql в миграциях? - PullRequest
0 голосов
/ 29 апреля 2019

Совершенно новый для Docker , я пытаюсь добавить выполнение пользовательского sql сценария (триггеры и функции) в процесс миграции Django, и я начинаю чувствовать себя немного потерянным , В целом, то, что я пытаюсь достичь, следует этому милому понятному учебнику . В этом руководстве миграции выполняются путем выполнения сценария точки входа. В 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 в процессе миграции, большинство прочитанных мною статей (например, эта ) рекомендуют создать пустую миграцию, чтобы добавить выполнение 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), я получаю следующую ошибку, поскольку db в контейнере postgresql пусто

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 миграции. Как бы вы это сделали?

[ edit ] 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:

Джанго: 2,2 питон: 3,7

Ответы [ 2 ]

1 голос
/ 30 апреля 2019

Я полагаю, что проблема связана с тем, что вы называете файл миграции и вручную задаете зависимости с тем же префиксом «0001». Причина, по которой я это говорю, заключается в том, что когда вы выполняете обратную миграцию, вы просто можете ссылаться на префикс. То есть, если вы хотите перейти от 7-й миграции к 6-й миграции. Команда выглядит следующим образом: python manage.py migrate my_app 0006 В любом случае, я бы попытался удалить и создать новый файл миграции через python manage.py makemigrations my_app --empty и переместить ваш код в этот файл. Это также должно написать зависимости для вас.

Сообщение об ошибке рядом с тестом, который вы запустили с добавлением файла миграции после, указывает на проблему. Некоторые как начальные миграции не запускаются раньше других Я также попытался бы сбросить вашу БД, поскольку она могла сохраниться в каком-то плохом состоянии ./manage.py sqlflush

0 голосов
/ 02 мая 2019

[ Самый простой способ, который я мог найти ] Я просто оторвал миграции 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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...