Приветствую всех!

Я начинающий разработчик и хочу поделиться своим решением проблемы, с которой столкнулся и не нашел готового решения в интернете. Мой подход может не быть оптимальным, но может быть полезен другим новичкам.

Предполагаю, что если вы нашли эту статью, то уже знакомы с процессом установки Docker и использования Django, поэтому не буду расписывать их детально. Но у вас уже должен быть установлен Docker.

Я работаю на windows, поэтому если у вас другая операционная система, то команды могут отличаться.

Шаг 1

Самый сложный.
Создаем рабочую папку.

Шаг 2

Создаем или сразу запускаем виртуальное окружение если оно у вас есть.

Создаем:
В терминале переходим в рабочую папку, которую только что создали. Переход выполняется посредством команды cd и путь к вашей папке.

Пример:
C:\Users\User>cd C:\Test
Далее, находясь в рабочий папке, введите так же в терминале, команду для создания виртуального окружения: python -m venv +---> (название)
Пример: C:\Test>python -m venv myenv

Активируем:

В терминале пишем путь до папки Scripts
Пример:
C:\Test>cd C:\Test\myenv\Scripts
Затем прописываем команду activate, которая и активируем наше виртуальное окружение.
Пример:
C:\Test\myenv\Scripts>activate
Если вы сделали правильно, то успешная активация виртуального окружения будет выглядеть следующим образом:
(myenv) C:\Test\myenv\Scripts>
Как можете заметить, вначале строки появилось название виртуального окружения в скобках.

Шаг 3

Возвращаемся в корневую папку проекта (Шаг 1)
Пример:
(myenv) C:\Test\myenv\Scripts>cd C:\Test
Создаем файл requirements.txt, в терминале пишите команду:
pip freeze > requirements.txt
После чего в вашей директории появится файл requirements.txt ,в котором будут отображаться ваши установленные пакеты и зависимости. На данном этапе, если вы начинали проект с самого начала вместе со мной, то этот файл у вас будет пустой.

Шаг 4

Устанавливаем пакеты, в терминале пишем следующие команды:
python -m pip install Django - устанавливаем фреймворк Django с помощью менеджера пакетов pip в Python.
Пример:
(myenv) C:\Test>python -m pip install Django
Далее пишем другую команду в терминале:
pip install psycopg2-binary - библиотека psycopg2-binary предоставляет Python-интерфейс для работы с СУБД PostgreSQL.
Пример:
(myenv) C:\Test>pip install psycopg2-binary
После установки, обновляем requirements.txt посредством уже известной нам команды:
pip freeze > requirements.txt
Теперь в файле requirements.txt, должны отображаться ваши установленные пакеты.

Шаг 5

Создаем новый проект Django в корневой директории (Шаг 1) с заданным названием.
docker-compose run django django-admin startproject (название) .
Не забудь про точку в конце команды.
Пример:
(myenv) C:\Test>docker-compose run django django-admin startproject testpostgre .

Далее:
Cоздаем новое Django приложение в корневой директории с новым названием.
python manage.py startapp (название)
Пример:
(myenv) C:\Test\testpostgre>python manage.py startapp app

Далее:
Переносим вручную файл manage.py в корневую директорию (папка из шага 1)

Шаг 6

Открываем свой IDE, и в корневой директории (в папке из "Шаг 1") создаем два файла:

  1. Dockerfile (название файла)

# Используем официальный образ Python в качестве базового образа
FROM python
# Устанавливаем рабочую директорию внутри контейнера
WORKDIR /usr/src/app
# Копируем файл requirements.txt внутрь контейнера
COPY requirements.txt ./
# Устанавливаем зависимости, описанные в файле requirements.txt
RUN pip install -r requirements.txt
  1. docker-compose.yml (название файла)

# Определение версии Docker Compose и начало описания сервисов
version: '3'

services:
  django:
    # Сборка образа для сервиса django из текущей директории
    build: .
    # Задание имени контейнера для сервиса django
    container_name: django
    # Задание команды, которую нужно запустить при запуске контейнера для сервиса django
    command: python manage.py runserver 0.0.0.0:8000
    volumes:
      - .:/usr/src/app
    # Открытие порта на хостовой машине и перенаправление на порт в контейнере
    ports:
      - 8000:8000
    # Зависимость от другого сервиса
    depends_on:
      - pgdb

  pgdb:
    # Использование готового образа postgres
    image: postgres
    # Задание переменных окружения для контейнера с postgres
    environment:
      - POSTGRES_DB=postgres
      - POSTGRES_USER=postgres
      - POSTGRES_PASSWORD=postgres
     # Задание имени контейнера для сервиса pgdb
    container_name: pgdb
     # Связывание тома с директорией в контейнере для сохранения данных postgres
    volumes:
      - pgdbdata:/var/lib/postgresql/data/

volumes:
  pgdbdata: null

Таким образом структура вашего проекта должна выглядеть примерно так:

Шаг 7

Открываем файл settings.pyи меняем там следующие строки кода:

Так было:
ALLOWED_HOSTS = []
Так стало:
# Определяем список разрешенных хостов для доступа к приложению
ALLOWED_HOSTS = ['localhost', '127.0.0.1', '0.0.0.0']

Далее спускаемся ниже по коду:

Так было:
INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
]
    
Так стало:
INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'app', # Добавляем наше приложение из "Шаг 5"
    'django.contrib.postgres', #это модуль Django, который предоставляет интеграцию с базой данных PostgreSQL 
]

Далее меняем следующие строки:

Так было:
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': BASE_DIR / 'db.sqlite3',
    }
}


Так стало:
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.postgresql',   # Используется PostgreSQL
        'NAME': 'postgres', # Имя базы данных
        'USER': 'postgres', # Имя пользователя
        'PASSWORD': 'postgres', # Пароль пользователя
        'HOST': 'pgdb', # Наименование контейнера для базы данных в Docker Compose
        'PORT': '5432',  # Порт базы данных
    }
}

Шаг 8

Переходим в файл models.py и создаем там модель для теста БД.

# Импорт модуля models из библиотеки Django
from django.db import models
# Определение класса MyModel, который наследует модель Django Model
class MyModel(models.Model):
    # Определение поля id типа AutoField как первичного ключа
    id = models.AutoField(primary_key=True)
    # Определение поля phone типа CharField с максимальной длиной в 20 символов
    phone = models.CharField(max_length=20)

    # Определение метода __str__, который будет использоваться для представления экземпляров модели в виде строки
    def __str__(self):
        return self.phone

Далее открываем файл admin.py и регистрируем созданную нами модель в админ-панели Django:

# Импорт модуля admin из библиотеки Django.contrib
from django.contrib import admin
# Импорт модели MyModel из текущего каталога (".")
from .models import MyModel
# Регистрация модели MyModel для административного сайта
admin.site.register(MyModel)

Шаг 9

Запускает все сервисы, определенные в файле docker-compose.yml в текущей директории, в режиме detached (фоновый режим) с помощью команды в терминале:
docker-compose up
Пример:
C:\Test> docker-compose up

Далее:
Открываем браузер и переходим по адресу http://localhost:8000/
И если вы всё правильно запустили, то вас будет ждать там следующая картина:

Далее:

Производите миграцию, выполнив команду в терминале:
docker-compose run django python manage.py migrate
Пример:
C:\Test> docker-compose run django python manage.py migrate

Далее:

Создаем супер-пользователя для входа в админ-панель:
В терминале, находясь в папке (Шаг 1) пишем следующую команду:
docker-compose run django python manage.py createsuperuser
Пример:
C:\Test> docker-compose run django python manage.py createsuperuser
Затем вам нужно ввести имя пользователя:
Username (leave blank to use 'root'): - вводите любое имя латинице
После будет поле Email:
Email address: - можете вводить или пропустить нажав Enter
Далее поле с паролем, сразу учтите, при вводе пароля, он отображаться не будет, не пугайтесь. Как ввели пароль, нажмите Enter, и потом повторите пароль ещё раз.
Password:
Password (again):
Если вы введете легкий пароль, то вас спросят:
Bypass password validation and create user anyway? [y/N]: - введите "y" и нажмите Enter
Строка Superuser created successfully. означает что вы все сделали правильно.

Далее:

Поднимаете ваши контейнера, с помощью команды docker-compose up
Пример: C:\Test> docker-compose up
Открываете браузер и переходите по адресу: http://localhost:8000/admin
Должны увидеть следующее:

Вводите имя пользователя и пароль, которые только что создали.

Нажимаем на My models (или как вы назвали свой класс в "Шаг 8")

Добавляете несколько данных для проверки работоспособности.

Шаг 10

Входим в интерактивный режим Postgres внутри контейнера Docker.

Для этого нужно прописать следующую команду в терминале:
docker exec -it <имя_контейнера> psql -U <имя_пользователя> <имя_базы_данных>
Пример:
docker exec -it pgdb psql -U postgres postgres

Чтобы посмотреть таблицы в PostgreSQL из интерактивного режима psql, вы можете выполнить команду \dt;, которая выведет список всех таблиц в текущей базе данных.
Пример:
postgres=# \dt;

Получаем список всех таблиц в нашей базе данных:

Для того, чтобы посмотреть данные в таблице app_mymodel, необходимо выполнить следующую команду:
SELECT * FROM app_mymodel;

Ну вот и всё, теперь у вас в контейнере Docker запущен Django и PostgreSQL.

Бонус

Если перейти по ссылке https://hub.docker.com/_/postgres
И скопировать текст команды docker pull postgres

То, эта команда запустит процесс загрузки (pull) образа Docker для СУБД PostgreSQL из официального репозитория Docker Hub.

Для этого вставьте скопированный текст в терминал.
Пример:
(dtenv)C:\Docker_Test> docker pull postgres

После того, как процесс загрузки завершится, образ будет доступен локально на вашей машине и вы сможете использовать его для создания и запуска контейнеров PostgreSQL в вашей среде.

Затем меняем немного код в файле docker-compose.yml

version: '3'

services:
  django:
    build: .
    container_name: django
    command: python manage.py runserver 0.0.0.0:8000
    volumes:
      - .:/usr/src/app
    ports:
      - 8000:8000
    depends_on:
      - pgdb

  pgdb:
    image: postgres
    restart: always
    environment:
      - POSTGRES_DB=postgres
      - POSTGRES_USER=postgres
      - POSTGRES_PASSWORD=postgres
    container_name: pgdb
    volumes:
      - pgdbdata:/var/lib/postgresql/data/

  adminer:
    image: adminer
    restart: always   #c 26 по 30 строку(вставлен новый фрагмент)
    ports:
      - 8080:8080
volumes:
  pgdbdata: null

Вновь выполняем команду сборки docker-compose up
Пример:
(dtenv)C:\Docker_Test> docker-compose up

После проделанных манипуляций, можем перейти по адресу http://127.0.0.1:8080/
И увидеть там вход в БД:

В разделе "Движок" меняете MySQL на PostgreSQL, в разделе "Сервер" пишите название Хоста указанного у вас в файле settings.py, если не можете найти, то посмотрите на картинку:

Далее вводите Имя пользователя и Пароль что вы указали, или если делали как я, то указывайте тоже самое. Название БД вводить не обязательно.

После входа, вы сможете просматривать таблицы вашей БД без труда и в нормальном виде!

Комментарии (14)


  1. rSedoy
    17.04.2023 16:18
    +7

    • добавлять django.contrib.postgres нужно только если используешь PostgreSQL specific features

    • настройки в DATABASES лучше передавать через переменные окружения, а не явно их прописывать. Для pgdb же сделано, почему так же и для остальных не сделать?

    • а зачем AutoField писать? он и так уже есть у Model

    • как использовать докер, хорошо посмотреть у крупных проектов на github, например, https://github.com/saleor/saleor-platform/blob/main/docker-compose.yml https://github.com/saleor/saleor/blob/main/Dockerfile


  1. klis
    17.04.2023 16:18
    +2

    Я начинающий разработчик и хочу поделиться своим решением проблемы, с которой столкнулся и не нашел готового решения в интернете.

    Серьезно? Это вот прям проблема, решение которой достойно аж отдельной статьи? И прям решений в интернете нет?
    Попробуйте вот этот сайт https://letmegooglethat.com/?q=dockerize+django+postgres


  1. Hivemaster
    17.04.2023 16:18
    +2

    Шаг 1: Не суйте СУБД в контейнер.
    Конец.


    1. askolo4ek
      17.04.2023 16:18
      +1

      Только что хотел это написать) Советую всегда БД на отдельном сервере разворачивать. Или в виртуалке, если учитесь и для себя делаете. Не нужно воплощать в жизнь плохие практики


      1. Bupyc
        17.04.2023 16:18

        1. я так понимаю это касается прода, никогда не пихал базу в контейнер, но интересно почему это не рекомендуется?

        2. сервис API тоже не рекомендуется в контейнере заливать на прод?


        1. askolo4ek
          17.04.2023 16:18
          +2

          1. Дело в том, что контейнеры очень любят падать и штука эта вообще не стабильная. К примеру, вы поднимаете свой Django проект в контейнере вместе с БД, всё работает отлично. Трафик и идёт, пользователи авторизируются, базёнка всё сохраняет. Но вдруг происходит какая то ошибка и тогда сразу контейнер завершит свою работу и падает, и все данные в БД и сама БД исчезают.

            Контейнеры нужны только для того, чтобы изолировать программу от хоста со своими зависимостями. Благодаря этому контейнеры жрут мало ресурсов по сравнению с ВМ. Но обратная сторона медали - это скудное его наполнение, только самое необходимое (файловая система, плюс возможность создать процесс). А держать БД в контейнере - плохая идея, потому что он в целом не предназначен под работу с дисковой памятью, да и изоляция БД от хостовой системы не требуется, потому что дисковая память итак изолирована, сегментирована. Если контейнер упадёт, то вы потеряте файл БД и все данные, там хранящиеся.


            Для решения проблемы устойчивости контейнеров как раз и придумали Kubernetes, который сам чуть что сбалансирует трафик, переподнимет, так же ещё можно сделать несколько реплик одного и того же приложения (для горизонтального масштабирования), можно задать количество потребляемых ресурсов на контейнер (RAM и CPU). Но Kubernetes также не решает проблемы БД (хотя потуги есть, например, StatefulSet)

          2. Сервис API в контейнере - это самое популярное и правильное решение. Но рекомендуется выносить БД на отдельный сервер, куда сервис API будет слать данные и брать оттуда. Так вы обеспечите сохранность и нивелируете кучу рисков. Также на сервере рекомендуется создать крон для бекапирования БД(на всякий случай). Ну и в идеале конечно вообще сделать несколько реплик БД, которые живут на разных серваках, географически разделенных с бекапами, блекджеком и тд :)). Так обеспечивается 99.99% сохранения данных.

            Также, желательно, на проде иметь Kubernetes, который и будет оркестрировать ваши контейнеры с сервисами. Для этого он представляет все возможности (внутреннюю сеть, неймспэйсы для изолирования, про реплики и балансировку описал выше)


          1. klis
            17.04.2023 16:18
            +2

            Но вдруг происходит какая то ошибка и тогда сразу контейнер завершит свою работу и падает, и все данные в БД и сама БД исчезают.

            Если контейнер упадёт, то вы потеряте файл БД и все данные, там хранящиеся.

            Эм... Что, простите?

            Но рекомендуется выносить БД на отдельный сервер

            Кем рекомендуется? Поделитесь рефенсами на исследования об этом. Желательно за последние лет 10.


          1. DeepHill
            17.04.2023 16:18

            А в случае если сервер один ? На хосте, а приложение в докер?


        1. Hivemaster
          17.04.2023 16:18

          На Stackoverflow есть хороший ответ на эту тему от одного из разработчиков PostgreSQL.


          1. klis
            17.04.2023 16:18
            -1

            "PostgreSQL DBA, время от времени контрибьютор проекта." != разработчик PostgreSQL

            Итак, файловая система необходима хоста, сеть необходима хоста. Итог - а зачем вам вообще база (в смысле получается только её исполняемые бинарники) в докере? Что вы отсюда хотите получить?

            Я хочу отсюда получить возможность запускать в рамках одной машины десятки/сотни постгресов произвольных версий и, возможно, по разному настроенных. И потом так же просто их бесследно удалять.


    1. bekishev04
      17.04.2023 16:18

      Для разработки почему бы и нет?
      Когда у тебя много проектов, то очень удобно запустить бд для конкретно этого проекта одной командой, а потом так же быстро остановить

      А в случае прода соглашусь


  1. kgenius
    17.04.2023 16:18
    +1

    Стал замечать, что становится много токсичных комментариев к статьям хаба. Причем не негативных/отрицательнах, а именно токсичных. И не зависит причём от тематики. Печально конечно такую тенденцию наблюдать... :-(


    1. klis
      17.04.2023 16:18

      Не переживайте, это, по всей видимости, продлится недолго - обнулить карму я, к сожалению, могу только один раз :)
      По комментариям понятно. А наличие таких статей на хабре вас в целом воодушевляет или какие чувства вы испытываете?


      1. kgenius
        17.04.2023 16:18

        Хабр я читаю читаю постоянно. Конкретно данную статью смотрел обзорно (бегло), т.к. сам специализируюсь на других направлениях.