{"id":15064704,"url":"https://github.com/gspvk/djangodrf-blog","last_synced_at":"2026-01-02T23:05:16.544Z","repository":{"id":253456210,"uuid":"843453671","full_name":"GSPVK/DjangoDRF-blog","owner":"GSPVK","description":"Django/DRF blog app","archived":false,"fork":false,"pushed_at":"2024-11-12T18:20:58.000Z","size":776,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-01-22T10:14:34.207Z","etag":null,"topics":["celery","django","docker","drf","nginx","postgresql","rabbitmq","redis"],"latest_commit_sha":null,"homepage":"https://djangoblog.space/","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/GSPVK.png","metadata":{"files":{"readme":"README-ru.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-08-16T14:48:56.000Z","updated_at":"2024-11-12T18:21:02.000Z","dependencies_parsed_at":"2024-08-29T22:29:36.849Z","dependency_job_id":null,"html_url":"https://github.com/GSPVK/DjangoDRF-blog","commit_stats":null,"previous_names":["gspvk/djangodrf-blog"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/GSPVK%2FDjangoDRF-blog","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/GSPVK%2FDjangoDRF-blog/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/GSPVK%2FDjangoDRF-blog/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/GSPVK%2FDjangoDRF-blog/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/GSPVK","download_url":"https://codeload.github.com/GSPVK/DjangoDRF-blog/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":243790999,"owners_count":20348385,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["celery","django","docker","drf","nginx","postgresql","rabbitmq","redis"],"created_at":"2024-09-25T00:25:22.197Z","updated_at":"2026-01-02T23:05:16.446Z","avatar_url":"https://github.com/GSPVK.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Language\n- **ru** **Русский**\n- **en** [English](README.md)\n\n# Блоговый веб-сервис\n[![Build status](https://github.com/GSPVK/DjangoDRF-blog/actions/workflows/django.yml/badge.svg?branch=master)](https://github.com/GSPVK/DjangoDRF-blog/actions/workflows/django.yml)\n[![Python](https://img.shields.io/badge/Python-3.12-blue)]()\n[![Django](https://img.shields.io/badge/Django-5.1-blue)]()\n[![DRF](https://img.shields.io/badge/DRF-3.15.2-blue)]()\n[![Coverage Status](https://img.shields.io/badge/coverage-98%25-brightgreen.svg)]()\n\nПроект построен на стеке **Django** и **Django REST Framework (DRF)**. Особенность проекта заключается в демонстрации двух различных подходов к реализации \nодинакового функционала: с помощью классического Django и через API, созданный с помощью DRF.\n\n**Демо-сайт доступен по адресу:** https://djangoblog.space/\n\n# Содержание\n- [Описание](#-два-подхода-к-реализации-функционала)\n- [Возможности](#-кратко-о-возможностях)\n- [UML diagram](#uml-diagram)\n- [Использованные технологии](#-использованные-технологии)\n- [Расширения и приложения](#расширения-и-приложения)\n- [Перед установкой](#перед-установкой)\n- [Установка](#установка)\n- [Хотите что-то предложить?](#хотите-что-то-предложить)\n\n## Два подхода к реализации функционала:\nПроект позволяет сравнить два способа реализации одного и того же функционала. Вы можете увидеть, как решаются одни и те же задачи \nс использованием стандартных представлений, форм и шаблонов в классическом Django и с использованием сериализаторов, вьюсетов и роутеров в DRF.\n\n## Кратко о возможностях:\n\n- **Система пользователей**:\\\nРегистрация, аутентификация, профили для пользователей.\n\n- **Посты**:\\\nПубликация, редактирование и удаление постов (весь CRUD).\n\n- **Категории**:\\\nПосты классифицируются по категориям.\n\n- **Комментарии**:\\\nВозможность оставлять комментарии к постам. Ответы на комментарии (дерево комментариев).\n\n- **Форматирование**:\\\nФорматирование и sanitize текста постов и комментариев обеспечивается с помощью [django-ckeditor](https://django-ckeditor.readthedocs.io/en/latest/) и [django-bleach](https://django-bleach.readthedocs.io/en/latest/).\n\n- **Рейтинг**:\\\nПользователи могут оценивать посты и комментарии (лайк/нейтрально/дизлайк).\n\n- **Подписки и фид**:\\\nПользователи могут подписываться как на других пользователей так и на категории. Из этого формируется фид.\n\n- **Избранное**:\\\nПользователи могут добавлять посты в избранное.\n\n## UML diagram\n![db_schema.png](db_schema.png)\n\n## Использованные технологии\n- [**Django**](https://www.djangoproject.com/) Веб-фреймворк\n- [**Django REST Framework (DRF)**](https://www.django-rest-framework.org/) API фреймворк\n  \n\n- [**PostgreSQL**](https://www.postgresql.org/) Основная БД\n- [**Redis**](https://redis.io/) БД для кэширования\n  \n\n- [**Celery**](https://docs.celeryproject.org/en/stable/) Асинхронный планировщик задач\n- [**RabbitMQ**](https://www.rabbitmq.com/) Брокер сообщений\n  \n\n- [**Docker**](https://www.docker.com/) Контейнеризация\n- [**Nginx**](https://nginx.org/en/) Веб-сервер. В проекте используется [данный образ](https://hub.docker.com/r/jwilder/nginx-proxy/)\n- [**Gunicorn**](https://docs.gunicorn.org/en/stable/) WSGI HTTP-сервер\n  \n\n- [**Bootstrap**](https://getbootstrap.com/) CSS фреймворк\n\n## Расширения и приложения\nЗдесь описаны некоторые (само собой не все) пакеты, приложения и достойные упоминания функции.\n\n- **Packages and extensions**:\n    - **[django-debug-toolbar](https://github.com/jazzband/django-debug-toolbar)** - дебаг-панель для сайта.\n    - **[jazzmin](https://django-jazzmin.readthedocs.io/)** - кастомная админка\n    - **[django-ckeditor](https://django-ckeditor.readthedocs.io/en/latest/)** - WYSIWYG html редактор текста.\n    - **[django-bleach](https://django-bleach.readthedocs.io/en/latest/)** - валидация и очистка html.\n    - **[simplejwt](https://django-rest-framework-simplejwt.readthedocs.io/en/latest/)** - JWT бэкенд аутентификации для API.\n    - **[django celery results](https://pypi.org/project/django-celery-results/)** - хранит результаты работы Celery в БД.\n    - **[flower](https://flower.readthedocs.io/en/latest/)** - веб-мониторинг для Celery.\n  \n\n- **Django apps**:\n    - `api` - приложение объединяющее API функционал.\n    - `blog` - основное приложение блога.\n    - `users` - приложение пользователей.\n    - `common` - приложение содержащее общий (не относящийся к какому-то конкретному приложению) функционал.\n    - `rating` - несёт в себе функционал для оценивая комментариев и постов.\n    - `subscriptions` - функционал для подписок на юзеров/категории и формирование фида исходя из подписок.\n\n\n- **Стоит упомянуть**:\n    - `create_default_groups` - команда manage.py приложения blog. Создаёт 2 группы - bloggers и readers, даёт разрешение блоггерам на создание постов (разрешение проверяется в шаблоне blog/post_list (line 34)).\n    - Кастомный бэкенд авторизации. Пользователь может залогиниться либо с помощью юзернейма либо посредством e-mail.\n    - Кастомные менеджеры для моделей `blog.Post` и `blog.Comment`, в которых выполняется оптимизированная загрузка списка постов/комментариев и добавление необходимых аннотаций (оценка, в избранном ли и т.д.) для request.user (если таковой имеется).\n    - Сигналы приложения Blog:\n        - Так как фильтрация по категориям закэширована (дабы избежать лишних запросов к редко меняющейся таблице) существует сигнал `update_category_cache` срабатывающей при редактировании таблицы Category. \n        - При присвоении пользователю группы Bloggers создаётся инстанс в модели Author (`create_or_delete_blog_author`). При удалении из группы инстанс, соответственно, удаляется. \n        - Суперюзеры сразу становятся блоггерами (`blog.signals.ensure_superusers_have_blogger_group_membership`)\n    - Сигналы приложения Common:\n        - Содержит модуль сигналов для работы с CKEditor. Сигналы анализируют какие картинки были добавлены/удалены из поста и выполняют необходимые действия (привязка/отвязка картинки к посту(-ам) в БД, удаление картинок с сервера)\n    - Интеграция с CKEditor (расположена в приложении Common):\n        - Модель `CKEditorPostImages` хранящая uri картинок в одном поле и посты, к которым прикреплена картинка посредством m2m связи, в другом поле.\n        - Middleware `CKEditorPostMiddleware`, который отлавливает картинки загруженные через редактор и делает ресайз (отправляя в Celery соответствующую задачу) при превышении заданного размера (full hd).\n        - Описанные выше сигналы.\n    - Сообщения об ошибках:\n        - Django Рендерит страницы для ошибок 400, 403, 404, 500 (шаблоны расположены в директории `templates/`)\n        - nginx. Отлавливает ошибки 50x. Шаблон ошибок nginx сконфигурирован в файле `nginx/50x.html` и [соответствующем volume](https://github.com/nginx-proxy/nginx-proxy/tree/main/docs#custom-error-page) (`./docker/nginx/custom_50x.html:/usr/share/nginx/html/errors/50x.html:ro`). \n\n## Перед установкой\nВ проекте предусмотрено 3 compose файла:\n- [**docker-compose.debug.yml**](docker-compose.debug.yml) - дебаг конфигурация. В ней отсутствует nginx и сертификация. Имеет свои volumes и другой entrypoint (docker/scripts/debug-server-entrypoint.sh) \nв котором отсутствует gunicorn в пользу стандартного django сервера. Запускается на портах 80:80.\n- [**docker-compose.staging.yml**](docker-compose.staging.yml) - конфигурация, запускающая процесс сертификации в [staging environment](https://letsencrypt.org/docs/staging-environment/) дабы убедиться, что всё настроено корректно и процесс сертификации успешен.\n- [**docker.compose.prod.yml**](docker-compose.prod.yml) - конфигурация для запуска в прод. При первом запуске попытается получить уже настоящий сертификат.\n  \n#### **ВАЖНО!** \n- При переключении между debug и prod не забывайте менять значение переменной DEBUG в .env (!)\n- При наличии проблем с конфигурацией nginx, проверьте как у вас сгенерирована конфигурация с помощью команды `docker exec nginx-proxy cat /etc/nginx/conf.d/default.conf`\n\n#### **Сертификация, подробнее**\n`VIRTUAL_HOST` (и `VIRTUAL_PORT`) необходимы для того, чтобы `nginx-proxy` мог автоматически создавать конфигурацию обратного прокси.\n`LETSENCRYPT_HOST` используется для того, чтобы `nginx-proxy-companion` мог выпустить сертификат Let's Encrypt для вашего домена.\nПоскольку приложение Django будет прослушивать порт 8000, мы также устанавливаем переменную окружения `VIRTUAL_PORT`.\nТом `/var/run/docker.sock:/tmp/docker.sock:ro` в `docker-compose.staging.yml` используется для отслеживания вновь зарегистрированных или удалённых контейнеров.\n\nКонтейнер ACME должен делить следующие тома с nginx-proxy:\n\n    certs:/etc/nginx/certs хранит сертификаты, приватные ключи и ключи учетных записей ACME.\n    html:/usr/share/nginx/html записывает файлы для проверки подлинности через http-01.\n    vhost:/etc/nginx/vhost.d изменяет конфигурацию виртуальных хостов.\n\n`VIRTUAL_HOST` должен включать только ваш основной домен. Если у вас есть `www.example.com`, он должен быть задан как `example.com`.\nЭто связано с тем, что при генерации сертификатов certbot будет использовать ваш основной домен для создания сертификата, который будет действителен \nкак для домена с www, так и для домена без www.\n\n## Установка\n#### Клонируйте репозиторий на свой ПК и перейдите в директорию проекта:\n```\n$ git clone https://github.com/GSPVK/DjangoDRF-blog\n$ cd DjangoDRF-blog\n```\n\n### Для простых тестов \nПросто выполните следующие 5 команд и всё:\n```shell\n$ poetry install\n$ poetry run python manage.py migrate\n$ poetry run python manage.py create_default_groups\n$ poetry run python manage.py createsuperuser\n$ poetry run python manage.py runserver\n```\n\n#### Скопируйте файл .env.example и переименуйте его в .env:\n\n```sh\ncp .env.example .env\n```\n\n### Docker\n#### Переменные окружения\nДля успешного процесса сертификации вам так же нужно определить следующие переменные для сервиса `web` в файлах [docker-compose.staging.yml](docker-compose.staging.yml) и [docker-compose.prod.yml](docker-compose.prod.yml)\n- `VIRTUAL_HOST=\u003cyour_domain.com\u003e`\n- `VIRTUAL_PORT=\u003csame_as_exposed_port\u003e`\n- `LETSENCRYPT_HOST=\u003cyour_domain.com\u003e`\n- `LETSENCRYPT_EMAIL=\u003cyour_email\u003e`\n#### Соберите проект:\n1. Запустите проект в докере и попытайтесь получить тестовый сертификат. Если у вас получилось - переходите к следующему шагу. Если нет - устраните ошибки.\n```sh\ndocker compose -f docker-compose.staging.yml up\n``` \n\n2. Остановите сервис.\n```sh \ndocker compose -f docker-compose.staging.yml down\n```\n\n3. Теперь вы можете запустить prod версию:\n```sh \ndocker compose -f docker-compose.prod.yml up\n```\n\n#### (Опционально) Установите фикстуры\n```sh\ndocker compose -f \u003cИСПОЛЬЗУЕМЫЙ-COMPOSE.YML\u003e exec web poetry run python manage.py loaddata fixtures/fixtures.json\n```\n\n#### Создайте администратора:\n```sh\ndocker compose -f \u003cИСПОЛЬЗУЕМЫЙ-COMPOSE.YML\u003e exec -it web /bin/sh\npoetry run python manage.py createsuperuser\n```\n\n## Хотите что-то предложить?\nЕсли вы видите что-то, что можно улучшить, вы можете открыть issue или pull-request. Ваш вклад приветствуется!","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgspvk%2Fdjangodrf-blog","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgspvk%2Fdjangodrf-blog","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgspvk%2Fdjangodrf-blog/lists"}