- Создали репозиторий
- Создали проект Django_316
- Установили зависимости
pip install django==4.2 - Сохранили зависимости в файл
reqirements.txtкомандойpip freeze > requirements.txt
Развернуть проект на локальной машине:
- Склонировать репозиторий командой
git clone git@github.com:TOP-Python316/django_316.git - Перейти в папку проекта
cd django_316 - Создать виртуальное окружение
python -m venv venv - Активировать виртуальное окружение
source venv/bin/activate - Установить зависимости
pip install -r requirements.txt
-
Создать проект
django-admin startproject anki .Этой командой мы создадим проект с именемankiв текущей директории. Точка в конце команды означает, что проект будет создан в текущей директории, без создания дополнительной директории с именем проекта. -
Запуск проекта
python manage.py runserverДля запуска проекта, вам нужно использовать терминал, и находясь в директории проекта, на одном уровне с файломmanage.py, выполнить командуpython manage.py runserverДля остановки сервера используйте комбинацию клавишCtrl+C
Команды терминала:
python manage.py runserver- запуск сервераcd- смена директорииcd..- переход на уровень вышеls- просмотр содержимого директорииpwd- показать текущую директорию
- Создание приложения
python manage.py startapp cardsПосле создания приложения, вам нужно зарегистрировать его в файлеsettings.pyв разделеINSTALLED_APPSБез этого, полноценно, приложение не будет работать.
from django.http import HttpResponse
def main(request):
return HttpResponse("Hello, world!") # вернет страничку с надписью "Hello, world!" на русском языке.Чтобы представление заработало, его нужно зарегистрировать в файле urls.py конфигурации проекта.
path('', views.main),Теперь, если вы перейдете на главную страницу сайта, то увидите надпись "Hello, world!"
Для этого нам нужно создать новый маршрут, с конвертом int, который будет принимать ID карточки.
path('cards/<int:card_id>/', views.card_detail),А так же функцию, которая будет обрабатывать запрос и возвращать страницу с детальной информацией о карточке.
def card_by_id(request, card_id):
return HttpResponse(f"Карточка с ID {card_id}")- Создали еще одно представление
get_all_cardsв файлеviews.py - Создали файл
urls.pyв директории приложенияcards - Зарегистрировали новый файл
urls.pyв файлеurls.pyконфигурации проекта с помощью функцииinclude - Зарегистрировали маршруты без префикса
cards/в файлеurls.pyприложенияcards - Удалили маршруты
cards/из файлаurls.pyконфигурации проекта
- Создали папку
templatesв директории приложенияcards - Создали файл
catalog.htmlв директорииtemplates/cards - Переписали функцию
get_all_cardsв файлеviews.pyтак, чтобы она возвращала страницуcatalog.htmlиспользуя функциюrenderиз модуляdjango.shortcuts
commit: lesson_46: рендер первого шаблона
- Создали словарь с данными в
views.pyи передали его в шаблон
info = {
"users_count": 100600,
"cards_count": 100600,
}- Вставили данные в шаблон
catalog.htmlс помощью шаблонного языка Django - Подключили BS5 по CDN и стилизовали страницу
commit: lesson_46: передал первые данные в шаблон и подключил BS5
- Проверили, что можем передать экземпляр класса, и вывести его атрибуты в шаблоне
- Проверили, что можно передать только словарь
- Передали список и вывели его в шаблоне
- Передали список меню и познакомились с конструкцией
{% for item in menu %}
commit: lesson_46: первый цикл в шаблоне
- Сделали
<hr>после каждого элемента списка, кроме последнего
commit: lesson_46: первый тег if в шаблоне
- Передали в шаблон список словарей, где каждый словарь содержит url и title
- Осталось протестировать шаблонный тег
url!
commit: lesson_46: сделал ссылки в меню кликабельными
- Откройте "Edit Configurations": В PyCharm перейдите в меню "Run" -> "Edit Configurations" для настройки новой конфигурации запуска.
- Добавление новой конфигурации: Нажмите на плюсик (+) и выберите тип конфигурации для Python.
- Заполнение полей конфигурации:
- Название: Дайте конфигурации понятное имя, чтобы вы могли легко идентифицировать её среди других конфигураций.
- Рабочая директория: Укажите директорию вашего проекта Django. Это папка, где находится файл
manage.py. - Интерпретатор языка: Выберите интерпретатор Python для вашего виртуального окружения, если вы его используете, или глобальный интерпретатор, если виртуальное окружение не настроено.
- Script path: Укажите путь к файлу
manage.pyв вашем проекте Django. - Параметры: Введите
runserver, чтобы запустить разработческий сервер Django.
commit: lesson_47: настроили запуск django-сервера по кнопке
- Описали маршруты /catalog, catalog/int:card_id/, catalog/slug:slug и создали соответствующие представления в файле views.py
- catalog возвращает HttpResponse("Каталог карточек")
- get_card_by_id возвращает HttpResponse(f"Карточка {card_id}")
- get_category_by_name возвращает HttpResponse(f"Карточка {slug}")
commit: lesson_47: добавили новые маршруты
Изменил пути и функции для дальнейшего развития проекта.
commit: lesson_47: изменение структуры путей
- Создали базовый шаблон
base.htmlв папкеtemplates - Указали кастомный, нестандартный путь для Джанго в файле
settings.pyв разделеTEMPLATES - Прописали там
BASE_DIR / 'templates', - Подключили базовый шаблон для теста функции
mainв файлеviews.py
commit: lesson_47: создали базовый шаблон base.html
- Описали блок
contentв базовом шаблонеbase.html - Создали шаблон
main.htmlв папкеtemplates, который расширяет базовый шаблон через{% extends %} - Переопределили блок
contentв шаблонеmain.htmlчерез{% block %} - Подключили шаблон
main.htmlв функцииmainв файлеviews.py
commit: lesson_47: создали шаблон main.html и расширили базовый шаблон
- Создали каталог
includesв папкеtemplatesв корне проекта - Создали шаблон
nav_menu.htmlв папкеincludes - Написали навигационное меню в шаблоне
nav_menu.html - Использовали шаблонный тег
{% url %}который позволяет создавать ссылки на страницы по их именам в файлеurls.py - Подключили шаблон
nav_menu.htmlв базовом шаблонеbase.htmlчерез{% include %} - Добавили датасет с карточками и меню, чтобы проверить работу шаблона
commit: lesson_47: создали шаблон nav_menu.html и подключили его в базовом шаблоне
- Модифицировали все шаблоны, и сделали так, чтобы они наследовались от базового шаблона
- Модфицировали соответствующие функции в файле
views.py, чтобы они возвращали нужные шаблоны и принимали данные для меню - Наладили рендер меню во всех шаблонах, и получили "сквозное" меню на всех страницах
commit: lesson_48: модифицировалb все шаблоны и функции в views.py — сквозная навигация
- Создали
includesв папкеtemplatesв приложенииcards - Внутри создали шаблон
card_preview.html - Шаблон
card_preview.htmlпринимает на вход словарь с данными о карточке и возвращает карточку, которая будет вставлена в каталог карточек в шаблонеcatalog.htmlв цикле
commit: lesson_48: начали работу над каталогом карточек и динамической вставкой данных в шаблон
- Добавили шаблон
card_detail.htmlв папкеtemplates/cards - Доделали
includeв шаблонеcatalog.htmlи вставили в него карточки из словаря - Обновили функцию
get_detail_card_by_id— сделали поиск карточки по ID в словаре и возврат шаблонаcard_detail.htmlИЛИ 404
commit: lesson_48: доделали каталог карточек и детальное отображение карточки по ID
- Создали тег шаблона
markdown_to_htmlчерезsimple_tagв файлеcards/templatetags/markdown_to_html.py - Протестировали его в представлении
card_detailв шаблонеcard_detail.html
commit: lesson_48: создали собственный тег шаблона markdown_to_html через simple_tag
- Создали папку
staticв приложенииcards - Создали папку
cardsв папкеstatic - В ней создали папку
cssи файлmain.css, а так же папкуjsи файлmain.js - Создали тестовые стили и скрипт
- Подключили статику в шаблоне
base.htmlчерез тег{% load static %}и тег{% static %} - Подключили стили и скрипт в шаблоне
base.html - Проверили работу статики на всех страницах
commit: lesson_48: подключили статику в шаблоне base.html
Посмотрели на работу следующих фильтров в шаблоне card_preview.html:
lengthtruncatecharsjoin
Так же, в шаблон был добавлен цикл для вывода тегов карточки.
commit: lesson_48: работа с фильтрами в шаблонах
HOTFIX: templatetags перенесён в cards из cards/templates
commit: lesson_48: исправлена ошибка местонахождения templatetags
тестовое изменение для создания коммита
commit: lesson_48: тестовое изменение для создания коммита
тестовое изменение для создания коммита II
commit: lesson_48: тестовое изменение для создания коммита II
- Создали второй вариант шаблонного тега
markdown_to_htmlчерезinclusion_tagв файлеcards/templatetags/markdown_to_html.py - Создали шаблон
markdown_to_html.htmlв папкеtemplates/cards - Протестировали его в представлении
card_detailв шаблонеcard_detail.html - Сравнили работу двух вариантов шаблонного тега
commit: lesson_48: добавление второго варианта фильтра (inclusion_tag)
-
Выполнили миграции командой
python manage.py migrateЭто создало служебные таблицы в базе данных, которые используются для работы с пользователями, сессиями, административной панелью и т.д. -
Создали суперпользователя командой
python manage.py createsuperuser
commit: lesson_49: применили первые миграции и создали админа
- Создали миграцию командой
python manage.py makemigrations - Применили миграции командой
python manage.py migrate
- Установка
Shell Plusкомандойpip install django-extensions - Добавление
django_extensionsвINSTALLED_APPSв файлеsettings.py - Запуск
Shell Plusкомандойpython manage.py shell_plus(для отображения SQL запросов в консоли -python manage.py shell_plus --print-sql - Для того, чтобы начать работать с моделью
Cardв интерактивной оболочке Django, нужно выполнить командуpython manage.py shell_plus
commit: lesson_49: создали первую модель и установили Shell Plus
-
Создание записи card = Card(question='Пайтон или Питон?!', answer='Пайтон') card.save()
-
Чтение записи card = Card.objects.get(pk=1) Мы можем добыть любые данные из записи, просто обратившись к атрибутам модели: card.question card.answer card.upload_date
-
Обновление записи card = Card.objects.get(pk=1) card.question = 'Питон или Пайтон?!!'
-
Удаление записи card = Card.objects.get(pk=1) card.delete()
-
Как можно откатить миграции?
- Целиком для приложения
cardsкомандойpython manage.py migrate cards zero - Вернуться к конкретной миграции
python manage.py migrate cards 0001_initial
commit: lesson_49: базовые CRUD Операции с моделью Card
- Создали файл
admin.pyв приложенииcards(если его нет) - Зарегистрировали модель
Cardв административной панели settings.pyLANGUAGE_CODE = 'ru-ru'- для русского языка в админке
from django.contrib import admin
from .models import Card
admin.site.register(Card)
class CardAdmin(admin.ModelAdmin):
pass- создаем суперпользователя если он ещё не был создан
python manage.py createsuperuser
commit: lesson_49: подключили модель Card в административной панели
all()- возвращает все объекты моделиfilter()- возвращает объекты, которые соответствуют условиям фильтрацииget()- возвращает объект, который соответствует условиям фильтрацииexclude()- возвращает объекты, которые НЕ соответствуют условиям фильтрацииorder_by()- возвращает объекты, отсортированные по указанному полюfirst()- возвращает первый объект из выборкиlast()- возвращает последний объект из выборкиcount()- возвращает количество объектов в выборкеexists()- возвращает True, если хотя бы один объект соответствует условиям фильтрацииdelete()- удаляет объекты, которые соответствуют условиям фильтрацииupdate()- обновляет объекты, которые соответствуют условиям фильтрации
- Получили все карточки
Card.objects.all()- получаем ленивый запросLIMIT 21НО!
for card in Card.objects.all():
print(card.question)Этот код не вызовет дополнительных запросов к базе данных, так как all()
возвращает QuerySet, который хранит в себе все объекты модели, которые соответствуют условиям фильтрации.
2. Получили карточку по ID Card.objects.get(pk=1)
3. Получили все карточки с вопросом "Пайтон или Питон?!" Card.objects.filter(question='Пайтон или Питон?')
4. Получили первую карточку с вопросом "Пайтон или Питон?!" Card.objects.filter(question='Пайтон или Питон?').first()
5. Получаем с помощью лукапа contains все карточки с вопросом, содержащим слово "или" Card.objects.filter(question__contains='или')
6. Считаем карточки с вопросом "Пайтон или Питон?!" Card.objects.filter(question='Пайтон или Питон?').count()
7. Считаем все карточки Card.objects.all().count()
8. Получаем карточки добавленные во вторник Card.objects.filter(upload_date__week_day=3)
commit: lesson_49: методы объектного менеджера objects
добавили новые маршруты, добавили стили и иконки, добавили адаптивность
https://icons.getbootstrap.com/ - иконки для BS5
Их надо подключить по ссылке в шаблоне base.html
commit: lesson_50: сделали симпатичную вёрстку
- В файле
views.pyв функцииcatalogизменили возврат словаря на возврат списка карточек из БД - В файле-вставке
include/card_preview.htmlизменили вставку данных id карточки наcard.id(что соответствует полю id в БД)
commit: lesson_50: сделали чтение из БД в каталоге карточек
- В файле
views.pyв функцииget_detail_card_by_idизменили возврат словаря на возврат карточки из БД - В файлах
card_detail.html,card_preview.htmlизменили вставку данных просмотров и добавления в избранное наcard.viewsиcard.adds(что соответствует полям views и adds в БД)
commit: lesson_50: сделали детальное отображение карточки из БД по ID
- добавил примеры для настройки отображения админки в
cards/admin.pyсначала задаётся класс, который добавляет модель в админку потом этот класс связывается с админкой черезadmin.site.register()либо сразу через декоратор@admin.register(Card)
1-ый вариант:
class CardAdmin(admin.ModelAdmin):
pass
admin.site.register(Card, CardAdmin)2-ой вариант:
@admin.register(Card)
class CardAdmin(admin.ModelAdmin):
passcommit: lesson_50: добавили примеры для настройки отображения админки
- Добавили поле
tagsв модельCard - Создали миграцию командой
python manage.py makemigrations - Применили миграцию командой
python manage.py migrate - Проверили что Django ORM преобразует JSON в список
commit: lesson_50: добавили теги в модель Card
sort- ключ для указания типа сортировки с возможными значениями:date,views,adds.order- опциональный ключ для указания направления сортировки с возможными значениями:asc,desc. По умолчаниюdesc.
- Сортировка по дате добавления в убывающем порядке (по умолчанию):
/cards/catalog/ - Сортировка по количеству просмотров в убывающем порядке:
/cards/catalog/?sort=views - Сортировка по количеству добавлений в возрастающем порядке:
/cards/catalog/?sort=adds&order=asc - Сортировка по дате добавления в возрастающем порядке:
/cards/catalog/?sort=date&order=asc
commit: lesson_50: сделали сортировку для каталога
- Еще раз пробежались по лукапам
commit: lesson_50: get_object_or_404 для детального отображения карточки по ID
- импортировали F-объект
- сделали счётчик просмотров карточки через F-объект
commit: lesson_51: рассмотрели F-объект
PRAGMA foreign_keys = 0;
--Создание временной таблицы без столбца UserID
CREATE TABLE sqlitestudio_temp_table AS SELECT CardID, Question, Answer, CategoryID, UploadDate, Views, Favorites FROM Cards;
--Удаление оригинальной таблицы Cards
DROP TABLE Cards;
--Создание новой таблицы Cards без столбца UserID
CREATE TABLE Cards (
CardID INTEGER PRIMARY KEY AUTOINCREMENT,
Question TEXT NOT NULL,
Answer TEXT NOT NULL,
CategoryID INTEGER,
UploadDate DATETIME DEFAULT (datetime('now')),
Views INTEGER DEFAULT (0),
Favorites INTEGER DEFAULT (0),
FOREIGN KEY (CategoryID) REFERENCES Categories (CategoryID) ON DELETE SET NULL ON UPDATE CASCADE
);
--Удаление временной таблицы
DROP TABLE sqlitestudio_temp_table;
--Копирование данных обратно в Cards из временной таблицы
INSERT INTO Cards (CardID, Question, Answer, CategoryID, UploadDate, Views, Favorites)
SELECT CardID, Question, Answer, CategoryID, UploadDate, Views, Favorites FROM sqlitestudio_temp_table;
PRAGMA foreign_keys = 1;- описали модель Tag
- описали модель CardTag
- описали модель Category
- переписали модель Card
- старые миграции удалены
- заново применены 18 базовых миграций
- сделана фейковая миграция
python manage.py migrate --fakeдля того чтобы Django "думал", что он сам создал наши новые таблицы
commit: lesson_51: подключили базу данных anki.db
- поменяли в модели CardTag название таблицы с CardsTags на CardTags
- удалили миграцию с прошлого коммита
- сделали миграцию заново
- снова применили фейковую миграцию
- переписали шаблоны под изменившуюся логику модели Tag
commit: lesson_51: поправили шаблоны для отображения из БД
- установили библиотеку
markdown - написали функцию конвертации
MarkDownвHTML - подключили шаблонный тэг
markdown_to_htmlв детальное представление карточки - подключили шаблонный тэг
markdown_to_htmlв отображение каталога карточек - подключили
Highlight.jsдля подсветки синтаксиса
commit: lesson_51: добавили конвертацию MD в HTML и подсветку кода
- добавили маршрут в
cards/urls.pytags/<int:tag_id>/для отображения карточек по конкретному тэгу - написали представление
cards/views.pyget_cards_by_tag - поменяли шаблоны
card_detail.htmlиcard_preview.htmlдля добавления кликабельности тэгам
commit: lesson_51: добавили кликабельные тэги
- убедились в том, что наше приложение генерирует слишком много запросов
commit: lesson_52: установили отладочную панель Django
- включили жадную загрузку и снизили количество запросов с 455 до 2
commit: lesson_52: включили жадную загрузку
- включили кэширование данных
commit: lesson_52: включили кэширование
# Создание новой карточки
new_card = Card.objects.create(question="Что такое Jython", answer="Jython — это реализация Python на Java.")
# Проверка существования тега и создание нового тега, если его не существует
tag_name = "Jython"
new_tag_created = Tag.objects.get_or_create(name=tag_name)
# Правильнее будет так:
# new_tag_created = Tag.objects.get_or_create(name=tag_name)
# вернётся кортеж, где первое значение — нужный объект, а второе — статус создан / не создан
# Создание новой категории
new_category = Category.objects.create(name="Random")
# добавление тэга к карточке
# ??????????# Получение всех карточек
all_cards = Card.objects.all()
# Получение карточки по ID
card = Card.objects.get(id=333)
# Получение всех тегов связанных с карточкой
tags = card.tags.all()
# Получение всех карточек связанных с тегом python
cards_with_tags = Tag.objects.get(name="python").cards.all()
# Получение всех категорий
all_categories = Category.objects.all()# Обновление вопроса в карточке 456
card = Card.objects.get(id=456)
card.question = "Для чего нужен Jython?"
card.save()
# Обновление имение категории
category = Category.objects.get(name="Random")
category.name = "null"
category.save()# Удаление карточки с id 456
card = Card.objects.get(id=456)
card.delete()
# Удаление категории с именем null
category = Category.objects.get(name="null")
category.delete()from django.db.models import Q
# Получение только тех карточек, которые содержат в вопросе слово Java
cards = Card.objects.filter(question__icontains="Java")
# Получение только тех карточек, которые содержат в вопросе ИЛИ в ответе слово Java
cards = Card.objects.filter(Q(question__icontains="Java") | Q(answer__icontains="Java"))
# Получение только тех карточек, которые содержат в вопросе И в ответе слово php
cards = Card.objects.filter(Q(question__icontains="php") & Q(answer__icontains="php"))from django.db.models import F
# Увеличение количества просмотров на 1 для всех карточек
Card.objects.update(views=F("views") + 1)
# Установка количества добавлений в избранное равным количеству просмотров
Card.objects.update(adds=F("views"))
# Добавление 10 просмотров каждой карточке, ответ которой содержит слово SQL
Card.objects.filter(Q(answer__icontains="SQL")).update(views=F("views") + 10)commit: lesson_52: посмотрели запросы Django ORM на CRUD
- добавили поля для отображения в админ. панели с помощью
list_display - пометили поля, которые будут ссылками с помощью
list_display_links - добавили поля по которым будет проводиться поиск с помощью
search_fields - добавили поля по которым будет проводиться фильтрация с помощью
list_filter - изменили модель данных
Card: добавили полеcategory - создали миграцию и применили её с ключом
--fake
commit: lesson_53: провели первоночальную настройку админ. панели
- добавили сортировку по просмотрам по убыванию и по категории по возрастанию с помощью
ordering - изменили количество отображаемых карточек на странице админ. панели с помощью
list_per_page - задали поля, которые можно менять напрямую
list_editable
commit: lesson_53: дополнительные настройки амдин. панели
- познакомились с методом
get_absolute_url - В Django метод
get_absolute_urlиспользуется в моделях для получения URL-адреса, который однозначно идентифицирует объект модели. Полезен для создания ссылок на конкретные модели, например в админ. панели Django или в шаблонах.
commit: lesson_53: get_absolute_url для создания URL-адреса
- поменяли надписи в шапке, тайтле и на экране приветствия админ. панели
commit: lesson_53: изменили заголовок, экран приветствия и шапку админ. панели
- поменяли заголовок, тайтл и приветствие в админ. панели в файле
anki\urls.py - перевели все поля в админ. панели на русский язык с помощью параметра
verbose_nameв каждом поле моделиCard
commit: lesson_53: перевели все поля в админ. панели на русский язык
- В PyCharm зайти в меню и выбрать
Project from Version Control... - Вставить путь до нашего проекта
git@github.com:TOP-Python316/django_316.gitи нажатьClone - Если не было создано виртуальное окружение, то создать его через инструменты PyCharm или с помощью команды
python -m venv venv - Чтобы активировать виртуальное окружение перезагрузите терминал или введите команду
venv\Scripts\activate - Если виртуальное окружение активировано, то в терминале перед приглашением командной строки вы увидите что-то вроде
(venv) - Установить зависимости с помощью команды
pip install -r requierements.txt - Положить в корень проекта таблицу
anki.db - Удалить миграцию
0001_initial.py - Применяем инициирующие миграции Django командой
python manage.py migrate, будут созданы служебные таблицы - Создаём миграцию со структурой нашей БД соответственно моделям из
models.pyс помощью командыpython manage.py makemigrations - Применяем миграцию с ключом
--fakeдля того чтобы Django "думал", что он создал эти таблицы. Командаpython manage.py migrate --fake - Создаём админа с помощью команды
python manage.py createsuperuser, вводим имя, пароль, почту и соглашаемся если пароль слабый
commit: lesson_54: повторили установку проекта
- тип
BooleanFieldиспользуется для хранения булевых значений (TrueилиFalse). - параметр
choicesиспользуется для ограничения возможных значений поля и для удобного отображения этих значений в админке Django. - В данном случае,
choicesзадается с помощьюtuple(map(lambda x: (bool(x[0]), x[1]), Status.choices)).
нам нужно было ограничить значения поля status только двумя возможными состояниями: True (Проверено) и False (Не проверено).
Для этого используется BooleanField, который по своей сути ограничивает значения до двух возможных вариантов.
Status.choicesвозвращает кортеж кортежей вида((0, 'Не проверено'), (1, 'Проверено')).- С помощью
map(lambda x: (bool(x[0]), x[1]), Status.choices)эти значения преобразуются в булевы значения:((False, 'Не проверено'), (True, 'Проверено')). - Это позволяет использовать
BooleanFieldс человеко-читаемыми именами для значений.
commit: lesson_54: добавили поле status
- добавили в админ. панель поле указывающее на наличие кода в ответе карточки
- добавили в админ. панель дополнительные действия: пометить карточки как проверенные и как не проверенные
commit: lesson_54: добавили в админ. панель поле наличие кода и доп. действия
Наследуется от SimpleListFilter, который предоставляет базовую функциональность для создания простых фильтров в админке Django.
Задает название фильтра, которое будет отображаться в админке. В данном случае, это "Наличие кода".
Задает имя параметра, которое будет использоваться в URL для фильтрации. В данном случае, это has_code.
Возвращает кортеж кортежей, где каждый внутренний кортеж состоит из двух элементов: значения параметра и человеко-читаемого названия.
В данном случае, возвращаются два варианта: ('yes', 'Да') и ('no', 'Нет').
Принимает запрос request и исходный набор данных queryset.
В зависимости от значения параметра has_code (которое можно получить с помощью self.value()), фильтрует набор данных.
Если значение параметра has_code равно yes, фильтрует набор данных, чтобы включить только те карточки, в которых поле answer содержит строку с тремя тиками.
Если значение параметра has_code равно no, фильтрует набор данных, чтобы исключить карточки, в которых поле answer содержит строку с тремя тиками.
commit: lesson_54: добавили кастомный фильтр по наличию кода в ответе карточки
- установили
django-jazzminи настроили его pip install django-jazzmin- Добавил
jazzminвINSTALLED_APPSв файлеsettings.py
commit: lesson_54: установил и настроил django-jazzmin
- Сделал копию служебного шаблона
change_form.htmlи вклинились в{% block after_field_sets %} - Добавил в админке карточек кнопку "Создать карточку с тегами"
{% block object-tools-items %}
commit: lesson_55: кастомизация шаблона change_form.html
- добавили маршрут
preview_card_ajax/для загрузки предпросмотра карточки - добавили представление
preview_card_ajaxдля загрузки предпросмотра карточки - добавили JS-код в
change_form_custom.htmlдля загрузки предпросмотра карточки
commit: lesson_55: добавили обновление предпросмотра карточки в админке в реальном времени
- Удалить файл с БД
anki.db - Применить инициирующие миграции, которые создадут системные таблицы
python manage.py migrate - Создать админа
python manage.py createsuperuser - Создать миграции по структурам прописанным в БД
python manage.py makemigrations - Применить миграцию, созданную в предыдущем шаге
python manage.py migrate - Залить данные из
dump.jsonв новую БДpython manage.py loaddata dump.json
commit: lesson_55: загрузили содержимое БД из дампа
- Создали форму не связанную с моделью. Форма для добавления карточек
- Создали представление, обрабатывающее метод POST и возвращающее форму
- Создали шаблон для формы
- Протестировали работу формы
- Проверили валидацию формы
commit: lesson_55: базовая форма для добавления карточек
- Дополнили шаблон с построчным рендером полей ввода
- Добавили категорию как выпадающий список
form.ChoiceField
commit: lesson_55: дополнил шаблон с построчным рендером полей ввода
- вернули жадную загрузку всего каталога карточек
select_relatedиспользуется для оптимизации запросов, когда необходимо получить связанные объекты через "один ко многим" или "один к одному" отношения. Это уменьшает количество запросов к базе данных, выполняя более сложный запрос с JOIN'ами, но возвращая все необходимые данные за один запрос.prefetch_relatedприменяется в случаях, когда связи "многие ко многим" или обратные связи "один ко многим" присутствуют. В отличие отselect_related,prefetch_relatedвыполняет отдельный запрос для каждой связи, но затем объединяет результаты в Python, что может существенно сократить время выполнения запроса при работе с большими объемами данных.
commit: lesson_56: вернули жадную загрузку всего каталога карточек
- Передали классы и атрибуты в форму через класс формы
- Поправили шаблон и перешли на BS-5 с адаптивной версткой
- Добавили обработку формы и сохранение данных в представлении
commit: lesson_56: BS5 и сохранение данных из формы
- Описали собственный класс валидатор
CodeBlockValidator - Подключили его в форме
commit: lesson_56: собственный валидатор CodeBlockValidator
- Написали форму связанную с моделью
- Обновили представление, чтобы оно работало с формой связанной с моделью
- Код получился вдвое короче
- Добавили валидатор для поля
tagsв форме (отсутствие пробелов) - Добавили метод очистки тегов в форме
- Проверили работу формы
commit: lesson_56: форма добавления карточек связанная с моделью
- Базовая форма добавления файла
- Минимальный комплект: класс формы, представление, шаблон
- Получения файла через
chunks()и сохранение его в файловую систему
commit: lesson_56: базовая форма добавления файла
- Модифицировали функцию-представление
catalogв файлеviews.pyтак, чтобы она принимала GET-параметрsearch_query - Добавили в шаблон
catalog.htmlформу для поиска карточек с GET-параметромsearch_queryи радио-кнопками для выбора поля поиска - Протестировали работу поиска
- Добавили отключение кеширования браузера для страницы каталога, чтобы видеть увеличение просмотров в каталоге
commit: lesson_57: добавили поиск по карточкам
- Добавили экземпляр пагинатора в представление
catalogв файлеviews.py - Добавили работу с пагинатором в шаблоне
catalog.html
commit: lesson_57: добавил пагинацию в каталог карточек
- Переписали функцию представления add_card на классовое представление с наследованием от
View
commit: lesson_57: переписали функцию представления add_card на классовое представление
- Переписали about и главную страницу на классовые представления (наследование от
TemplateView) - Создали миксин, который добавляет к контексту меню, подмешали его в один класс
commit: lesson_57: переписали about и главную страницу на TemplateView
- Добавили в AboutView и IndexView атрибут
extra_contextи добавили в него подсчет реального количества карточек и пользователей
commit: lesson_57: добавили в AboutView и IndexView подсчет реального количества карточек и пользователей
- Переписали представление
catalogна классовое представлениеListView - Добавили жадную загрузку связанных объектов
commit: lesson_58: Переписали представление catalog на классовое представление ListView
- Использовали
__iregexдля РАБОЧЕГО регистронезависимого поиска вместо__icontains(актуально для SQLite) - Кешировали каталог силами шаблонизатора
- Использовали
page_obj.paginator.countдля подсчета количества карточек (не иницирует новых запросов к БД) - Использовали переменные для кеша, которые позволяют кешировать разные варианты страницы (по запросам и сортировкам)
{% cache 90 catalog_content page_obj.number sort order search_query %}
commit: lesson_58: доработка каталога и кеширование
- Переписали представление
get_detail_card_by_idна классовое представлениеDetailView - Обновили шаблон
card_detail.htmlдля работы с классовым представлением
commit: lesson_58: get_detail_card_by_id на классовое представление DetailView
- Использовали
from django.core.cache import cacheдля кеширования меню, так как оно делало с каждой страницы по 2 запроса в БД
commit: lesson_58: кеширование меню с помощью cache
- Переписали представление добавления карточки на классовое представление
CreateView-AddCardCreateView(MenuMixin, CreateView)
commit: lesson_58: добавление карточки на классовое представление CreateView
- Добавили представления
UpdateViewиDeleteViewдля редактирования и удаления карточек - А так же удачную правку для тегов, чтобы они на самом деле обновлялись (а не только добавлялись)
- Шаблон для 404 ошибки (работает пока только в боевом режиме
DEBUG=False, не забыть прописатьALLOWED_HOSTS=['*']в settings.py)
commit: lesson_59: UpdateView и DeleteView и 404
- Создали приложение
usersс помощью командыpython manage.py startapp users - Подключили приложение
usersвINSTALLED_APPS - Подготовили маршруты и представления для приложения
users
commit: lesson_59: users app и подготовка маршрутов
- прописали функции-представления для аутентификации и выхода из системы
- создали шаблон для входа в систему
LoginUserForm— форма для входа в систему- протестировали вход и выход из системы
- нашли в браузере куки и сессии
commit: lesson_59: функции-представления для аутентификации и выхода из системы
redirect_field_name= 'next' во вьюшке добавления карточек- так же, добавили миксин
LoginRequiredMixinдля защиты представлений от неавторизованных пользователей - в шаблон
login.htmlдобавилиnextдля перехода на страницу, с которой пришел пользователь<input type="hidden" name="next" value="{{ request.GET.next }}"> - пофиксили редирект при успешной авторизации
return redirect(request.POST.get('next', 'catalog'))— это позволяет переходить на страницу, с которой пришел пользователь после авторизации
commit: lesson_59: защита представлений от неавторизованных пользователей и перенаправление
- добавили в навигационное меню кнопки Вход и Регистрация
commit: lesson_59: добавили в навигационное меню кнопки Вход и Регистрация
- Использовали
LoginViewвместо функцииlogin_user- это классовое представление для входа в систему - В нем использовали служебную форму
AuthenticationFormдля входа в систему - А так же прописали
success_urlдля перехода после успешного входа с проверкой наnext
commit: lesson_60: переписал функцию логина на LoginUser(LoginView)
- Написали свою форму с наследованием от
AuthenticationFormи добавили в нее BS5 стили - Переписали представление выхода из системы на
LogoutUser(LogoutView) - Добавили оформления в шаблон
login.html
commit: lesson_60: своя форма входа и выхода из системы
- Прописал в настройках
LOGIN_URLдля того, чтобы не делать это в каждом защищенном представлении - Убрал
login_urlиз защищенного представления и проверил работу LoginRequiredMixinработает в связке с полем |login_urlиз защищённого представления или с параметромLOGIN_URLиз настроек
commit: lesson_60: LoginRequiredMixin и LOGIN_URL
- добавили автора в модель данных
Cardauthor = models.ForeignKey(get_user_model(), on_delete=models.SET_NULL, related_name='cards', null=True, default=None, verbose_name=_('Автор')) - Добавили пользователя в шаблоны отображения карточек
- Модифицировали
AddCardCreateViewдля добавления карточки, чтобы автором был текущий пользователь
commit: lesson_60: добавил пользователя в описание карточки
class LogoutUser(LogoutView): next_page = reverse_lazy('users:login')- Поправили
urls.pyдля приложенияusersc использованием классаLogoutUser
commit: lesson_60: LogoutUser(LogoutView)
- Регистрация пользователя через простую форму связанную с моделью
RegisterUserForm(forms.ModelForm): - Функция представления
register_userдля регистрации пользователя - Шаблон
register.htmlдля регистрации пользователя - Сообщение спасибо за регистрацию
register_done.html
commit: lesson_60: регистрация пользователя
- Переписали функцию регистрации на класс
RegisterUser(CreateView)— специализированного родителя нет, поэтому используемCreateView - Поправили
urls.pyдля приложенияusersc использованием классаRegisterUser - Переписали старую форму на класс
RegisterUserForm(UserCreationForm)— специлизированный родитель для регистрации пользователя - Протестировали хеширование пароля (Есть!)
- Переписали старую форму на класс
RegisterUserForm(UserCreationForm)— специлизированный родитель для регистрации пользователя - Протестировали хеширование пароля (Есть!)
commit: lesson_61: класс регистрации пользователя RegisterUser
- Создаем файл бэкенда аутентификации
users/authentication.py - Определяем в обственный бэкенд
- Подключаем егонем с в настройках
AUTHENTICATION_BACKENDS - Указываем там стандартный бэкенд
django.contrib.auth.backends.ModelBackendи наш собственныйusers.authentication.EmailAuthBackend - Поправили форму входа
LoginUserForm(подпись что вы можете войти по email или username)
commit: lesson_61: авторизация опционально через email или username
- Создали шаблон
base_profile.htmlкоторый расширяетbase.htmlи служит основой для личного кабинета - Создали шаблон
profile.htmlкоторый расширяетbase_profile.htmlи содержит информацию о пользователе а так же возможность внести изменения в профиль - Создали include
profile_nav.htmlдля навигации по личному кабинету - Создали шаблон
password_change_form.htmlдля изменения пароля - Создали шаблон
password_change_done.htmlдля успешного изменения пароля - Создали шаблон
profile_cards.htmlдля отображения карточек пользователя
users/profile/-ProfileUser- личный кабинет пользователяusers/password_change/-UserPasswordChange- изменение пароля пользователяusers/profile_cards/-UserCardsView- карточки пользователя
UserPasswordChange- изменение пароля пользователя. Наследуется отPasswordChangeView- стандартного класса для изменения пароля. Использует пользовательскую формуUserPasswordChangeForm, которая наследуется отPasswordChangeFormUserPasswordChangeDone- успешное изменение пароля пользователя. Наследуется отTemplateViewUserCardsView- карточки пользователя. Наследуется отListView. Переопределяет методget_querysetдля получения карточек пользователя
commit: lesson_61: начал работу над личным кабинетом
Для этого нам необходимо подготовить целый ряд представлений и шаблонов:
Итого для работы с паролями:
-
PasswordChange
- Родитель:
PasswordChangeView - Атрибуты:
template_name: Указать путь к шаблону формы смены пароля.form_class: Указать класс формы для смены пароля.success_url: Использоватьreverse_lazyдля указания URL-адреса перенаправления после успешной смены пароля.extra_context: Словарь с дополнительным контекстом, например{'title': 'Смена пароля'}.
- Методы:
form_valid: Метод, вызываемый при успешной валидации формы. Может быть переопределен для добавления дополнительной логики.
- Родитель:
-
PasswordChangeDone
- Родитель:
TemplateView - Атрибуты:
template_name: Указать путь к шаблону страницы, подтверждающей успешное изменение пароля.extra_context: Словарь с дополнительным контекстом, например{'title': 'Пароль успешно изменен'}.
- Родитель:
-
PasswordReset
- Родитель:
PasswordResetView - Атрибуты:
template_name: Указать путь к шаблону формы запроса на сброс пароля.form_class: Указать класс формы для запроса сброса пароля.email_template_name: Путь к шаблону email, который будет отправлен для сброса пароля.success_url: Использоватьreverse_lazyдля указания URL-адреса перенаправления после запроса на сброс.subject_template_name: Путь к шаблону темы email.
- Методы:
form_valid: Метод для дополнительной обработки после отправки формы.
- Родитель:
-
PasswordResetDone
- Родитель:
TemplateView - Атрибуты:
template_name: Указать путь к шаблону страницы, подтверждающей отправку инструкций по сбросу пароля.extra_context: Словарь с дополнительным контекстом, например{'title': 'Инструкции отправлены'}.
- Родитель:
-
PasswordResetConfirm
- Родитель:
PasswordResetConfirmView - Атрибуты:
template_name: Указать путь к шаблону формы для ввода нового пароля.form_class: Указать класс формы для ввода нового пароля.success_url: Использоватьreverse_lazyдля указания URL-адреса перенаправления после успешного сброса пароля.
- Методы:
form_valid: Метод для дополнительной обработки после успешной смены пароля.
- Родитель:
-
PasswordResetComplete
- Родитель:
TemplateView - Атрибуты:
template_name: Указать путь к шаблону страницы, подтверждающей успешное обновление пароля.extra_context: Словарь с дополнительным контекстом, например{'title': 'Пароль успешно обновлен'}.
- Родитель:
reverse_lazy('name_of_route'): Используется для отложенного получения URL по имени маршрута.form_valid(form): Вызывается, когда форма проходит валидацию. Обычно используется для переопределения стандартной логики, например, для выполнения дополнительных действий с объектом перед его сохранением.
Эти элементы должны быть включены в классы и методы для обеспечения функциональности смены и восстановления пароля, а также управления потоком пользователя в приложении Django.
| Класс | Файл | Родитель | Описание | Использование |
|---|---|---|---|---|
PasswordChange |
views.py |
PasswordChangeView |
Класс для смены пароля аутентифицированного пользователя. | Смена пароля |
PasswordChangeDone |
views.py |
TemplateView |
Отображает страницу об успешном изменении пароля. | Подтверждение смены пароля |
PasswordReset |
views.py |
PasswordResetView |
Обработчик для инициирования процесса сброса пароля. | Восстановление пароля |
PasswordResetDone |
views.py |
TemplateView |
Отображает страницу, подтверждающую отправку инструкций. | Подтверждение отправки письма |
PasswordResetConfirm |
views.py |
PasswordResetConfirmView |
Позволяет пользователю ввести новый пароль после сброса. | Ввод нового пароля |
PasswordResetComplete |
views.py |
TemplateView |
Отображает страницу об успешном обновлении пароля. | Успешное обновление пароля |
Шаблоны сброса пароля Django:
password_reset_email.html: используется для отправки электронного письма с ссылкой для сброса пароля.password_reset_form.html: используется для отображения формы сброса пароля.password_reset_confirm.html: используется для отображения страницы подтверждения сброса пароля.password_reset_done.html: используется для отображения страницы с сообщением о том, что пароль был успешно сброшен.password_change_email.html: используется для отправки электронного письма с уведомлением о смене пароля.password_change_form.html: используется для отображения формы изменения пароля.password_change_done.html: используется для отображения страницы с сообщением о том, что пароль был успешно изменен.
Описание каждого шаблона:
-
password_reset_email.html:
- Этот шаблон используется для отправки электронного письма с ссылкой для сброса пароля.
- Шаблон должен содержать ссылку, которая направляет пользователя на страницу сброса пароля.
- Ссылка должна содержать уникальный идентификатор пользователя и токен сброса пароля.
- Шаблон также может содержать сообщение с инструкциями о том, как сбросить пароль.
-
password_reset_form.html:
- Этот шаблон используется для отображения формы сброса пароля.
- Форма должна содержать поля для ввода нового пароля и подтверждения нового пароля.
- Форма должна также содержать скрытое поле с токеном сброса пароля.
- Когда пользователь отправляет форму, Django проверит токен сброса пароля и, если он действителен, сбросит пароль пользователя.
-
password_reset_confirm.html:
- Этот шаблон используется для отображения страницы подтверждения сброса пароля.
- Страница должна содержать сообщение с информацией о том, что пароль пользователя был успешно сброшен.
- Страница также может содержать ссылку, которая направляет пользователя на страницу входа в систему.
-
password_reset_done.html:
- Этот шаблон используется для отображения страницы с сообщением о том, что пароль был успешно сброшен.
- Страница должна содержать сообщение с информацией о том, что пароль пользователя был успешно сброшен.
- Страница также может содержать ссылку, которая направляет пользователя на страницу входа в систему.
-
password_change_email.html:
- Этот шаблон используется для отправки электронного письма с уведомлением о смене пароля.
- Шаблон должен содержать сообщение с информацией о том, что пароль пользователя был изменен.
- Шаблон также может содержать ссылку, которая направляет пользователя на страницу изменения пароля.
-
password_change_form.html:
- Этот шаблон используется для отображения формы изменения пароля.
- Форма должна содержать поля для ввода текущего пароля, нового пароля и подтверждения нового пароля.
- Когда пользователь отправляет форму, Django проверит текущий пароль пользователя и, если он верен, изменит пароль пользователя.
-
password_change_done.html:
- Этот шаблон используется для отображения страницы с сообщением о том, что пароль был успешно изменен.
- Страница должна содержать сообщение с информацией о том, что пароль пользователя был успешно изменен.
- Страница также может содержать ссылку, которая направляет пользователя на страницу входа в систему.
commit: lesson_62: промежуточный коммит восстановление пароля через email
from django.contrib.auth.models import AbstractUser
from django.db import models
class User(AbstractUser):
photo = models.ImageField(
upload_to='users/images/%Y/%m/%d',
null=True,
blank=True,
verbose_name='Аватар'
)
date_birth = models.DateField(
null=True,
blank=True,
verbose_name='Дата рождения'
)
groups = models.ManyToManyField(
'auth.Group',
related_name='custom_user_set',
blank=True,
verbose_name='groups',
)
user_permissions = models.ManyToManyField(
'auth.Permission',
related_name='custom_user_set',
blank=True,
verbose_name='user permissions',
)
def __str__(self):
return self.usernameВ Django, AbstractUser - это базовый класс для модели пользователя, который включает в себя большинство полей и методов, необходимых для аутентификации и авторизации пользователей. Он включает такие поля, как username, password, email, first_name, last_name, is_staff, is_active, date_joined и другие.
Когда вы создаете свой собственный класс User, наследуясь от AbstractUser, вы переопределяете стандартную модель пользователя Django. Это позволяет вам добавить дополнительные поля, такие как photo и date_birth, которые не включены в стандартную модель пользователя.
Ваш класс User включает следующие поля:
photo: Это полеImageField, которое позволяет пользователям загружать фотографии. Параметрupload_toуказывает, где эти фотографии должны быть сохранены. В данном случае, они сохраняются в подкаталогеusers/images/%Y/%m/%d/каталогаMEDIA_ROOT. Параметрыblank=True, null=Trueуказывают, что это поле не является обязательным.date_birth: Это полеDateTimeField, которое позволяет пользователям указывать свою дату рождения. Оно также не является обязательным.
Причина, по которой вы используете наследование от AbstractUser, а не связь "один к одному" с другой моделью для хранения дополнительной информации о пользователе, заключается в том, что это делает вашу модель пользователя более гибкой и удобной в использовании. Вместо того чтобы каждый раз, когда вам нужна дополнительная информация о пользователе, получать ее из связанной модели, вы можете просто обратиться к полям photo и date_birth напрямую, как если бы они были частью стандартной модели пользователя.
В Django, параметр upload_to в поле ImageField или FileField используется для указания подкаталога внутри MEDIA_ROOT, где будут сохраняться загруженные файлы.
Строка 'users/images/%Y/%m/%d/' в upload_to определяет путь к подкаталогу, где будут сохраняться файлы. В этом пути используются специальные символы %Y, %m и %d, которые заменяются на текущий год, месяц и день соответственно. Это позволяет автоматически организовать загруженные файлы по датам, что может быть полезно, если вы ожидаете большое количество загружаемых файлов.
Таким образом, если пользователь загрузит файл 5 июля 2022 года, файл будет сохранен в подкаталоге users/images/2022/07/05/ каталога MEDIA_ROOT.
Пожалуйста, учтите, что MEDIA_ROOT должен быть предварительно определен в настройках вашего Django проекта. Это корневой каталог, где Django будет сохранять все загруженные файлы.
- Установим pillow для работы с изображениями
pip install pillow - Обновим requirements.txt
pip freeze > requirements.txt - Подключим новую модель пользователя в настройках
AUTH_USER_MODEL = 'users.User'
- Создал новые миграции.
- Применил миграции.
ВАЖНО:
Сначала создаём миграции, применяем их, и только потом подключаем новую модель пользователя в settings.py — AUTH_USER_MODEL = 'users.User'
commit: lesson_62: расширил модель пользователя
- MEDIA_ROOT - корневой каталог для загружаемых файлов
- MEDIA_URL - URL, по которому можно получить доступ к загружаемым файлам
MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')commit: lesson_62: расширил модель пользователя
- Правки в главный
urls.pyдля отображения медиафайлов
from django.conf.urls.static import static
from django.conf import settings
if settings.DEBUG:
import debug_toolbar
urlpatterns = [
path('__debug__/', include(debug_toolbar.urls)),
# другие URL-паттерны
] + urlpatterns
# Добавляем обработку медиафайлов
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)- Правки в
nav_menu.htmlдля кликабельности username
<a class="nav-link" href="{% url 'users:profile' %}">{{ user.username }}</a>А так же мелкие правки в стили для отображения фотографии пользователя
commit: lesson_62: добавили аватар в профиле
Отсутствовал маршрут в urls.py для UserPasswordChangeDone
Добавили его и протестировали работу смены пароля
commit: lesson_62: доделал смену пароля в ЛК
- Маршрут для сброса пароля
- Маршрут для подтверждения сброса пароля
- Маршрут для ввода нового пароля
- Маршрут для завершения сброса пароля
Настраиваем EMAIL_BACKEND для вывода в консоль
EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'#TODO Скинуть курс по Docker от Стасчука #TODO Скинуть видео по интернет магазину на Django
Сделали восстановление пароля через email
commit: lesson_62: восстановление пароля через email
- Регистрация на TimeWeb. https://timeweb.cloud/r/pj17346
- Выбор тарифа и создание виртуального сервера.
- Покупка домена и настройка его на TimeWeb.
- Подгтовка проекта к деплою
- Убедитесь что в проекте нет лишних файлов и папок.
- Создайте файл
requirements.txtс зависимостями проекта. - Если вы создавали
.envфайл, добавьте его в.gitignore. - Убедитесь что
.env.exampleсодержит все необходимые переменные. - Если в вашей БД есть контент, создайте дамп БД
- Можете прогнать тест. Просто склонируйте проект в соседнюю папку и попробуйте запустить.
- Команды для подготовки приложения к запуску на сервере
- Деплой
commit: lesson_63: подготовка к деплою
DNS (Domain Name System) — это фундаментальная технология, которая делает Интернет доступным и удобным для пользователей. Представьте себе, что DNS — это своего рода телефонная книга Интернета, которая позволяет вам находить веб-сайты и другие ресурсы по удобным для запоминания именам, а не по сложным числовым адресам. Давайте рассмотрим, почему DNS так важен и как он работает, с помощью интересных аналогий и примеров.
-
Удобство для пользователей:
- Представьте, что вместо ввода www.example.com вам нужно запомнить и вводить что-то вроде 93.184.216.34. Это было бы очень неудобно и затруднительно. DNS позволяет использовать легко запоминающиеся доменные имена, что делает навигацию по Интернету гораздо проще.
-
Гибкость и управление:
- DNS позволяет владельцам веб-сайтов и других онлайн-ресурсов легко управлять своими доменными именами и IP-адресами. Например, если ваш веб-сайт переезжает на новый сервер с другим IP-адресом, вам нужно просто обновить записи DNS, и пользователи будут автоматически перенаправлены на новый сервер.
-
Распределение нагрузки и отказоустойчивость:
- DNS может направлять трафик на разные серверы в зависимости от географического положения пользователя или текущей нагрузки на серверы. Это помогает распределить нагрузку и обеспечить высокую доступность веб-сайтов и других онлайн-сервисов.
-
Безопасность:
- DNSSEC (DNS Security Extensions) добавляет уровень безопасности, защищая DNS-запросы от подделки и других атак. Это помогает предотвратить перенаправление пользователей на поддельные веб-сайты.
Представьте, что вы хотите посетить веб-сайт www.example.com. Вот что происходит за кулисами:
-
Запрос к рекурсивному DNS-серверу:
- Ваш браузер отправляет запрос к рекурсивному DNS-серверу, который обычно предоставляется вашим интернет-провайдером или настроен в вашей операционной системе.
-
Запрос к корневому DNS-серверу:
- Если рекурсивный DNS-сервер не знает IP-адреса для www.example.com, он отправляет запрос к корневому DNS-серверу. Корневой сервер отвечает, что за доменом .com отвечает TLD-сервер.
-
Запрос к TLD-серверу:
- Рекурсивный DNS-сервер отправляет запрос к TLD-серверу для домена .com. TLD-сервер отвечает, что за доменом example.com отвечает авторитетный DNS-сервер.
-
Запрос к авторитетному DNS-серверу:
- Рекурсивный DNS-сервер отправляет запрос к авторитетному DNS-серверу для домена example.com. Авторитетный сервер отвечает IP-адресом для www.example.com.
-
Ответ пользователю:
- Рекурсивный DNS-сервер возвращает IP-адрес вашему браузеру, и браузер устанавливает соединение с веб-сервером по этому IP-адресу.
-
История DNS:
- DNS был разработан в 1980-х годах, когда Интернет только начинал развиваться. До этого использовался файл hosts, который содержал список всех доменных имен и соответствующих им IP-адресов. По мере роста Интернета этот подход стал неэффективным, и была разработана распределенная система DNS.
-
Корневые DNS-серверы:
- В мире существует всего 13 корневых DNS-серверов, которые управляют корневой зоной DNS. Эти серверы распределены по всему миру и обеспечивают высокую доступность и отказоустойчивость.
-
DNS-кэширование:
- Рекурсивные DNS-серверы кэшируют ответы на запросы, чтобы ускорить последующие запросы. Это снижает нагрузку на авторитетные серверы и улучшает производительность.
-
DNS-атаки:
- DNS может быть уязвим для различных атак, таких как DNS-спуфинг (подделка DNS-ответов) и DDoS-атаки (распределенные атаки типа "отказ в обслуживании"). Для защиты от таких атак используются технологии, такие как DNSSEC и Anycast.
DNS — это невидимый герой Интернета, который работает в фоновом режиме, обеспечивая надежное и удобное преобразование доменных имен в IP-адреса. Без DNS Интернет был бы гораздо менее удобным и доступным для пользователей.
commit: lesson_63: информация о DNS
Docker — это платформа для разработки, доставки и эксплуатации приложений, которая использует контейнеризацию для упрощения процесса управления приложениями и их зависимостями. Концепция контейнеризации позволяет упаковывать приложения и их зависимости в изолированные контейнеры, которые могут быть легко перемещены и запущены на любом сервере или в любой среде.
Docker — это инструмент, который позволяет создавать, развертывать и управлять контейнерами. Он предоставляет API и интерфейс командной строки для управления контейнерами, а также экосистему инструментов и сервисов для упрощения работы с контейнерами.
-
Docker Engine:
- Основной компонент Docker, который управляет контейнерами. Docker Engine включает в себя Docker Daemon (демон Docker), который выполняет основные операции, такие как создание и управление контейнерами.
-
Docker CLI (Command Line Interface):
- Интерфейс командной строки для взаимодействия с Docker Engine. Позволяет пользователям выполнять команды для создания, запуска, остановки и управления контейнерами.
-
Docker Hub:
- Облачный реестр, который хранит и распространяет Docker-образы. Docker Hub позволяет пользователям находить, загружать и публиковать Docker-образы.
-
Docker Compose:
- Инструмент для определения и запуска многоконтейнерных Docker-приложений. Docker Compose использует YAML-файлы для описания конфигурации приложений и их зависимостей.
-
Docker Swarm:
- Встроенный инструмент для оркестрации контейнеров, который позволяет создавать и управлять кластерами Docker-контейнеров.
Контейнеризация — это метод виртуализации на уровне операционной системы, который позволяет запускать и изолировать приложения и их зависимости в контейнерах. Контейнеры обеспечивают изоляцию, но используют общий ядро операционной системы, что делает их более легковесными по сравнению с виртуальными машинами.
-
Изоляция:
- Контейнеры изолируют приложения и их зависимости друг от друга, что позволяет избежать конфликтов и проблем с совместимостью.
-
Портативность:
- Контейнеры могут быть перемещены и запущены на любом сервере или в любой среде, где установлен Docker. Это упрощает процесс развертывания и миграции приложений.
-
Легковесность:
- Контейнеры используют общий ядро операционной системы, что делает их более легковесными по сравнению с виртуальными машинами. Это позволяет запускать больше контейнеров на одном сервере.
-
Скорость:
- Контейнеры запускаются быстрее, чем виртуальные машины, так как они не требуют загрузки полной операционной системы.
-
Упрощение разработки и тестирования:
- Контейнеры позволяют разработчикам создавать и тестировать приложения в изолированных средах, что упрощает процесс разработки и тестирования.
Предположим, что у вас есть веб-приложение, которое требует веб-сервер (например, Nginx), базу данных (например, MySQL) и приложение на Python. Вы можете использовать Docker для создания контейнеров для каждого из этих компонентов и управлять ими с помощью Docker Compose.
-
Создание Docker-образов:
- Создайте Dockerfile для каждого компонента вашего приложения. Dockerfile описывает, как создать Docker-образ для конкретного компонента.
-
Создание Docker Compose файла:
- Создайте файл docker-compose.yml, который описывает конфигурацию вашего приложения и его зависимостей.
version: '3' services: web: image: nginx ports: - "80:80" volumes: - ./html:/usr/share/nginx/html db: image: mysql environment: MYSQL_ROOT_PASSWORD: example app: build: ./app depends_on: - db
- Запуск приложения:
- Используйте команду docker-compose up для запуска вашего приложения и его зависимостей.
commit: lesson_63: информация о Docker
- Настройка
DEBUGвsettings.pyдля отладочного режима. Чтобы на сервере не отображались отладочные сообщения, установитеDEBUG = Falseи добавьте домен сервера в списокALLOWED_HOSTS. DEBUG = os.getenv('DEBUG') - Настройка
ALLOWED_HOSTSвsettings.pyдля домена cardslurm.ru. ALLOWED_HOSTS - это список хостов, которые могут обращаться к нашему сайту ALLOWED_HOSTS = ['cardslurm.ru', 'www.cardslurm.ru', 'localhost', '127.0.0.1'] - Настройка CSRF_TRUSTED_ORIGINS в
settings.pyдля безопасной работы с формами. CSRF_TRUSTED_ORIGINS - это список доменов, с которых можно отправлять POST-запросы без токена CSRF CSRF_TRUSTED_ORIGINS = ['https://cardslurm.ru', 'https://www.cardslurm.ru'] - Добавление IF DEBUG для отладочной панели Django.
INTERNAL_IPS - это список IP-адресов, с которых можно получить доступ к отладочной панели Django
if DEBUG:
INTERNAL_IPS = [ '127.0.0.1', ] commit:lesson_64: дополнительная настройка для работы проекта