Django и postgresql в docker - Как запустить пользовательский sql для создания представлений после миграции django?
Я хочу создать sql представления после создания таблиц django, так как представления опираются на таблицы, созданные моделями Django.
Проблема заключается в том, что при попытке запустить скрипт python через Dockerfile CMD с вызовом entrypoint.sh
я получаю следующую проблему с именем хоста при попытке подключиться к базе данных postgresql из create_views.py
Я пробовал следующие варианты имен хостов: localhost, db, 0.0.0.0, 127.0.0.1 - безрезультатно.
e.g.
- psycopg2.OperationalError: connection to server at "0.0.0.0", port 5432 failed: Connection refused
- не удалось преобразовать имя хоста "db" в адрес: Временный сбой в разрешении имен
- соединение с сервером на "localhost" (127.0.0.1), порт 5432 не удалось: Connection refused
Я не могу использовать IP-адрес контейнеров, так как при каждом запуске docker-compose up получаются разные IP-адреса для контейнеров...
docker-compose.yml
services:
app:
container_name: django-mhb-0.3.1
build:
context: .
ports:
- "8000:8000"
volumes:
- ./myproject/:/app/
environment:
- DB_HOST=db
- DB_NAME=${POSTGRES_DB}
- DB_USER=${POSTGRES_USER}
- DB_PWD=${POSTGRES_PASSWORD}
depends_on:
- "postgres"
postgres:
container_name: postgres-mhb-0.1.1
image: postgres:14
volumes:
- postgres_data:/var/lib/postgresql/data/
# The following works. However, it runs before the Dockerfile entrypojnt script.
# So in this case its trying to create views before the tables exist.
#- ./myproject/sql/:/docker-entrypoint-initdb.d/
ports:
- "5432:5432"
environment:
- POSTGRES_DB=${POSTGRES_DB}
- POSTGRES_USER=${POSTGRES_USER}
- POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
volumes:
postgres_data:
Переменные окружения докера находятся в файле .env в том же каталоге, что и Dockerfile и docker-compose.yml Секреты Django находятся в файле secrets.json в директории проекта django
Dockerfile
### Dockerfile for Django Applications ###
# Pull Base Image
FROM python:3.9-slim-buster AS myapp
# set work directory
WORKDIR /app
# set environment variables
ENV PYTHONUNBUFFERED 1
ENV PYTHONDONTWRITEBYTECODE 1
# Compiler and OS libraries
RUN apt-get update\
&& apt-get install -y --no-install-recommends build-essential curl libpq-dev \
&& rm -rf /var/lib/apt/lists/* /usr/share/doc /usr/share/man \
&& apt-get clean \
&& useradd --create-home python
# install dependencies
COPY --chown=python:python ./requirements.txt /tmp/requirements.txt
COPY --chown=python:python ./scripts /scripts
ENV PATH="/home/python/.local/bin:$PATH"
RUN pip install --upgrade pip \
&& pip install -r /tmp/requirements.txt \
&& rm -rf /tmp/requirements.txt
USER python
# Section 5- Code and User Setup
ENV PATH="/scripts:$PATH"
CMD ["entrypoint.sh"]
entrypoint.sh
#!/bin/sh
echo "start of entrypoint"
set -e
whoami
pwd
#ls -l
#cd ../app/
#ls -l
python manage.py wait_for_db
python manage.py makemigrations
python manage.py migrate
python manage.py djstripe_sync_models product plan
python manage.py shell < docs/build-sample-data.py
## issue arises running this script ##
python manage.py shell < docs/create_views.py
python manage.py runserver 0.0.0.0:8000
create_views.py
#!/usr/bin/env python
import psycopg2 as db_connect
def get_connection():
try:
return db_connect.connect(
database="devdb",
user="devuser",
password="devpassword",
host="0.0.0.0",
port=5432,
)
except (db_connect.Error, db_connect.OperationalError) as e:
#t_msg = "Database connection error: " + e + "/n SQL: " + s
print('t_msg ',e)
return False
try:
conn = get_connection()
...
Я удалил остальную часть скрипта, так как она не нужна
Когда я запускаю Django/postfgresql вне docker на локальной машине localhost работает нормально.
Надеюсь, кто-нибудь сможет помочь, у меня голова идет кругом, и я уже несколько дней ищу возможный ответ
Спасибо
Благодаря подсказкам Эрика, решено следующим образом
python manage.py makemigrations --empty yourappname
Затем добавил следующее (примечание сокращено для экономии места)
from django.db import migrations
def get_all_items_view(s=None):
s = ""
s += "create or replace view v_all_items_report"
s += " as"
s += " SELECT project.id, project.slug, project.name as p_name,"
...
return s
def get_full_summary_view(s=None):
s = ""
s += "CREATE or replace VIEW v_project_summary"
s += " AS"
s += " SELECT project.id, project.slug, project.name as p_name,
...
return s
class Migration(migrations.Migration):
dependencies = [
('payment', '0002_payment_user'),
]
operations = [
migrations.RunSQL(get_all_items_view()),
migrations.RunSQL(get_full_summary_view()),
migrations.RunSQL(get_invoice_view()),
migrations.RunSQL(get_payment_view()),
]
Обратите внимание на то, чтобы убедиться, что вы перечислили последнюю таблицу, которая должна быть создана в ваших зависимостях, прежде чем будут созданы представления. В моем случае django по умолчанию устанавливает, что все остальные миграции зависят друг от друга в порядке цепочки.
В моем скрипте dockerfile entrypoint.sh находятся команды для создания миграций, миграции и построения некоторых образцов данных