{"id":20589598,"url":"https://github.com/nankuf/blog","last_synced_at":"2026-04-12T14:44:19.436Z","repository":{"id":46616515,"uuid":"413022310","full_name":"NankuF/Blog","owner":"NankuF","description":"Блог по книге \"Django 2 by example\". Антонио Меле.","archived":false,"fork":false,"pushed_at":"2021-12-08T06:56:17.000Z","size":87,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-03-06T13:34:10.025Z","etag":null,"topics":["django","docker-compose","postgresql","python"],"latest_commit_sha":null,"homepage":"","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/NankuF.png","metadata":{"files":{"readme":"README.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}},"created_at":"2021-10-03T08:42:00.000Z","updated_at":"2021-12-08T06:56:20.000Z","dependencies_parsed_at":"2022-09-02T15:10:14.035Z","dependency_job_id":null,"html_url":"https://github.com/NankuF/Blog","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/NankuF/Blog","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/NankuF%2FBlog","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/NankuF%2FBlog/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/NankuF%2FBlog/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/NankuF%2FBlog/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/NankuF","download_url":"https://codeload.github.com/NankuF/Blog/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/NankuF%2FBlog/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":27522057,"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","status":"online","status_checked_at":"2025-12-05T02:00:07.920Z","response_time":54,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"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":["django","docker-compose","postgresql","python"],"created_at":"2024-11-16T07:29:58.576Z","updated_at":"2025-12-05T14:04:32.704Z","avatar_url":"https://github.com/NankuF.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Приложение \"Блог\", сделано по книге \"Django 2 в примерах\" Антонио Меле.\n\n## Список фич для разработчика:\n- Список статей\n- Детальное отображение статьи\n- Формирование каноничного URL\n- Пагинация\n- Комментирование статьи\n- Поделиться статьей по e-mail\n- Теги и фильтрация по тегу\n- Рекомендованные статьи\n- Создание собственных тегов\n- Создание собственных фильтров\n- django-environ\n- Карта сайта\n- RSS для статей\n- Подключение БД PostgreSQL через `docker-compose.yaml`\n- Полнотекстовый поиск с PostgreSQL\n\n\n### Список статей\nЧтобы отобразить список статей необходимо:\n1. Модель\n2. HTML-шаблон\n3. URL-шаблон\n4. View\n\n#### Принцип действия:\nCписок статей - это обыкновенная модель из бд, поля которой отображаются в HTML-шаблоне.\nURL-шаблон используется, чтобы запустить вьюху, по которой будет генерироваться HTML-шаблон.\n\n### Детальное отображение статьи\nДля детального отображения статьи необходимо:\n1. Model `Post`\n2. Метод get_absolute_url в модели `Post`\n3. HTMl-шаблон `detail.html`\n4. URL-шаблон\n5. View `post_detail`\n\n#### Принцип действия:\n- Чтобы отобразить 1 статью из множества, необходимо использовать метод `get` менеджера контекста.\nОднако чтобы отобразить 1 *опубликованную* статью, необходимо вначале изменить менеджер контекста с `objects` на \n`published` написав класс `PublishedManager` и создать поле в модели `Post` - `published = PublishedManager()`\n- Необходимо сформировать каноничный URL, по которому мы будем переходить на страницу детального отображения статьи.\nДля этого в модели `Post` определяем метод `get_absolute_url`, который формирует каноничный URL из полей модели 'Post':\n`publish.year`, `publish.month`, `publish.day`, `slug`\n\n### Формирование каноничного URL\nДля формирования каноничного URL необходимо:\n1. Модель `Post`\n2. Метод `get_absolute_url` с ф-ей `reverse`\n3. HTML-шаблон\n4. URL-шаблон\n\n#### Принцип действия:\nСоздаем модель. Внутри модели создаем метод `get_absolute_url`. В методе используем ф-ю reverse(URL-шаблон, поля модели).\nПрокидываем метод `get_absolute_url` в HTML-шаблон.\nФ-я `reverse` собирает URL по URL-шаблону используя переданные в нее поля модели.\n\n\n### Пагинация\n*Пагинация* - ограничивает кол-во отображаемых статей на странице, с возможностью листать вперед-назад.\n![img.png](img.png) \u003cbr\u003e\n\nЧтобы сделать пагинацию необходимо в приложении blog создать:\n1. Model `Post` \n2. Функция-обработчик (`post_list` in views)\n3. HTML-шаблон для пагинации (`pagination.html`)\n4. HTML-шаблон для списка, к которому применим пагинацию через {% include 'pagination.html' with post=posts %}\n\n#### Принцип действия:\n- Берем список опубликованных статей `Post.publish.all()`, помещаем его в переменную `object_list` и \nпередаем в класс `Paginator`, указав, сколько статей мы хотим отображать на странице - `Paginator(object_list,3)`.\n- Определяем текущую страницу через request - `request.GET.get('page')`\n(в словаре request есть словарь GET, в котором по ключу 'page' определяем номер страницы)\n- Через `try except` определяем, когда все сработало нормально, то показываем те статьи,\nкоторые соответствуют странице взятой из request `posts = paginator.page(page)`,\nи описываем два исключения `EmptyList` - когда пользователь ввел страницу, которая больше максимальной страницы - \nперекидываем его на последнюю страницу `paginator.page(paginator.num_pages)`,\nи `PageNotAnInteger` - когда пользователь ввел не число, то перекидываем его на первую страницу `paginator.page(1)`\n\n### Комментирование статьи\nДля реализации комментирования, нам понадобятся:\n1. Model `Comment`\n2. ModelForm `CommentForm`\n3. HTML-шаблон в котором отображается детально статья и куда мы прокинем форму.\n4. URL-шаблон, по которому будет формироваться view `post_detail`\n5. View `post_detail`\n\n#### Принцип действия:\nЧтобы комментирование статьи работало, нам нужна форма, в которой мы будем писать коммент. После отправки этой формы\nсработает вьюха `post_detail` и комментарий будет отображен на странице через HTML-шаблон.\nИспользуем `ModelForm`, чтобы поля подтянулись из `Model`, тип полей для формы указываем в `Model`.\n\n### Поделиться статьей по e-mail\nДля реализации данной фичи необходимо:\n1. Настройки smtp-сервера в setting.py\n2. View\n3. HTML-шаблон `detail.html` - здесь разместим ссылку на форму.\n4. HTML-шаблон `share.html` - здесь разместим саму форму отправки на e-mail.\n5. URL-шаблон\n6. Form\n\n#### Принцип действия:\n- В Django есть свой `EMAIL_BACKEND`, он позволяет отправлять данные на e-mail.\n- Прописываем `EMAIL_BACKEND` и настройки smtp-сервера в setting.py\n- Создаем форму используя `forms.Form` (т.к нам не нужна модель для отправки статьи на e-mail).\n- Создаем URL-шаблон `path('\u003cint:post_id\u003e/share/', views.post_share, name='post_share')` и вьюху `post_share`.\n- Во вьюхе получаем queryset модели по id переданному на вход ф-и через URL-шаблон.\n- Пишем стандартную логику для отправки письма используя `if request.method == 'POST'` и `is.valid()`\n- Если данные валидны - собираем тело письма для ф-ии `sendmail`, которую мы импортируем из встроенного модуля\n`django.core.mail` и отправляем письмо.\n- Если данные не валидны - показываем пустую форму заново.\n\n### Теги\nДля реализации системы тегов необходимо:\n1. Установить стороннее приложение django-taggit `pip install django-taggit`\n2. Прописать приложение `taggit` в `INSTALLED_APPS`\n3. Добавить в модель `Post` менеджер контекста `TaggableManager`\n4. Сделать миграции\n5. В админке появится строка Tags, в нее добавить теги для поста. ![img_1.png](img_1.png)\n6. URL-шаблон c `slug:tag_slug`\n7. HTML-шаблон `list.html` в котором указываем тег.\n8. View `post_list` с аргументом `tag_slug`\n\n### Рекомендованные статьи\nДанный функционал основан на тегах. Показывает все статьи, в которых есть тег текущей статьи.\n\n### Создание собственных тегов\nЕсть 2 типа тегов:\n- `simple_tag` – обрабатывает данные и возвращает строку;\n- `inclusion_tag` – обрабатывает данные и возвращает сформированный фрагмент шаблона.\u003cbr\u003e\u003cbr\u003e\nДля `inclusion_tag` нужно создавать HTML-файл.\u003cbr\u003e\n`simple_tag` сразу размещается в готовых HTML-шаблонах.\n\n1. В приложении `blog` создаем пакет `templatetags`\n2. В пакете создаем модуль `blog_tags.py`\n3. В модуле создаем собственные теги\n4. Вызываем готовые теги в HTMl-шаблонах \n\n### Создание собственных фильтров\n1. В уже созданном модуле `blog_tags.py` создаем собственный фильтр.\n2. `pip install markdown `(для нашего фильтра это необходимо)\n3. Применяем `{% load blog_tags %}` в HTML-шаблоне.\n4. Применяем фильтр как обычный фильтр в HTML-шаблонах.\n\n### Django-environ для скрытия важных данных\n1. `pip install django-environ`\n2. Создаем файл `.env`\n3. Добавляем `.env` в `.gitignore`\n4. Применяем `django-environ` в `settings.py` и других модулях.\n\n### Карта сайта\nЭта штука нужна для поисковых роботов, для лучшей индексации.\nДелается просто:\n1. В `settings.py` прописываем SITE_ID=1\n2. Там же в `INSTALLED_APPS` добавляем 2 приложения `django.contrib.sites` и `django.contrib.sitemaps`\n3. Делаем миграции\n4. Создаем новый модуль в `blog` - `sitemaps.py`, в нем создаем класс `PostSitemap(Sitemap):`\n5. Модифицируем `mysite/urls.py`, делаем импорты, создаем словарь `sitemaps` и прописываем `path`\n6. В админке в разделе `SITES` меняем `example.com` на домен нашего сайта.\n\n### RSS для статей\nRSS-фид нужен, чтобы пользователи могли подписываться на рассылку статей нашего блога.\n1. Создаем в приложении `blog` модуль `feeds.py`\n2. В `feeds.py` создаем класс `LatestPostsFeed(Feed)`\n3. В `blog/urls.py` создаем `path` для класса `LatestPostsFeed`\n4. В HTML-шаблоне `base.html` добавляем ссылку на `path` - `{% url \"blog:post_feed\" %}`\n\n### Подключение БД PostgreSQL через `docker-compose.yaml`\n1. Создаем `docker-compose.yaml`\n2. Меняем `DATABASES` в `settings.py`, сразу прячем в `.env`\n3. `pip install psycopg2-binary, docker-compose`\n4. `sudo docker-compose up postgres` - запускаем сервис Postgres через docker-compose.\n5. Если порт `5432` занят, меняем на другой в `docker-compose.yaml` и `.env`\n6. Делаем миграции.\n7. Создаем суперюзера.\n8. Наполняем бд заново статьями через админку.\n\n### Полнотекстовый поиск с PostgreSQL\nВажно: Данная реализация работает только с PostgreSQL!\nВ книге описано 4 вида поиска:\n1. Поиск по нескольким полям\n2. Стемминг и ранжирование результатов\n3. Взвешенные запросы\n4. Поиск с помощью триграмм - считается одним из наиболее качественных типов поиска.\u003cbr\u003e\u003cbr\u003e\nВ коде приведен пример для поиска с помощью триграмм.\u003cbr\u003e\nТриграмма – это последовательность из трех символов. Вы можете измерить подобие двух строк,\nподсчитав количество совпадений триграмм.\n- Заходим в postgresql в докере:  `sudo docker exec -it 5242f50a423e bash`\n- `psql -U user postgres`\n- `CREATE EXTENSION pg_trgm;`  - создаем расширение `pg_trgm` необходимое для работы.\n![img_3.png](img_3.png)\n- создаем форму `SearchForm(forms.Form)`\n- создаем ф-ю `post_search` в `views.py`\n- создаем HTML-шаблон `search.html`\n- прописываем `path` до него в `blog/urls.py`\n\nФича реализована криво. При similarity__gt=0.02 УЖЕ не работает.\nМожно раскомментировать Поиск по нескольким полям.\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnankuf%2Fblog","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fnankuf%2Fblog","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnankuf%2Fblog/lists"}