Skip to content

TOP-Python316/django_316

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Django_316 - Учебный проект "Карточки интервального повторения"

Lesson 45

Создали проект Django_316

  1. Создали репозиторий
  2. Создали проект Django_316
  3. Установили зависимости pip install django==4.2
  4. Сохранили зависимости в файл 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 project

  1. Создать проект django-admin startproject anki . Этой командой мы создадим проект с именем anki в текущей директории. Точка в конце команды означает, что проект будет создан в текущей директории, без создания дополнительной директории с именем проекта.

  2. Запуск проекта python manage.py runserver Для запуска проекта, вам нужно использовать терминал, и находясь в директории проекта, на одном уровне с файлом manage.py, выполнить команду python manage.py runserver Для остановки сервера используйте комбинацию клавиш Ctrl+C

Команды терминала:

  • python manage.py runserver - запуск сервера
  • cd - смена директории
  • cd.. - переход на уровень выше
  • ls - просмотр содержимого директории
  • pwd - показать текущую директорию
  1. Создание приложения 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 конфигурации проекта.

Создали первый URL

path('', views.main),

Теперь, если вы перейдете на главную страницу сайта, то увидите надпись "Hello, world!"

Создаем детальное представление карточки по ее ID

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

path('cards/<int:card_id>/', views.card_detail),

А так же функцию, которая будет обрабатывать запрос и возвращать страницу с детальной информацией о карточке.

def card_by_id(request, card_id):
    return HttpResponse(f"Карточка с ID {card_id}")

include и собственный файл urls.py для приложения cards

  1. Создали еще одно представление get_all_cards в файле views.py
  2. Создали файл urls.py в директории приложения cards
  3. Зарегистрировали новый файл urls.py в файле urls.py конфигурации проекта с помощью функции include
  4. Зарегистрировали маршруты без префикса cards/ в файле urls.py приложения cards
  5. Удалили маршруты cards/ из файла urls.py конфигурации проекта

Lesson 46

Знакомство с Django Templates (Шаблоны)

  1. Создали папку templates в директории приложения cards
  2. Создали файл catalog.html в директории templates/cards
  3. Переписали функцию get_all_cards в файле views.py так, чтобы она возвращала страницу catalog.html используя функцию render из модуля django.shortcuts

commit: lesson_46: рендер первого шаблона

Работа с шаблоном

  1. Создали словарь с данными в views.py и передали его в шаблон
info = {
    "users_count": 100600,
    "cards_count": 100600,
}
  1. Вставили данные в шаблон catalog.html с помощью шаблонного языка Django
  2. Подключили BS5 по CDN и стилизовали страницу

commit: lesson_46: передал первые данные в шаблон и подключил BS5

Смотрим типы данных внутри шаблона

  • Проверили, что можем передать экземпляр класса, и вывести его атрибуты в шаблоне
  • Проверили, что можно передать только словарь
  • Передали список и вывели его в шаблоне
  • Передали список меню и познакомились с конструкцией {% for item in menu %}

commit: lesson_46: первый цикл в шаблоне

Посмотрели на тег шаблона if

  • Сделали <hr> после каждого элемента списка, кроме последнего

commit: lesson_46: первый тег if в шаблоне

Сделали ссылки в меню кликабельными

  • Передали в шаблон список словарей, где каждый словарь содержит url и title
  • Осталось протестировать шаблонный тег url!

commit: lesson_46: сделал ссылки в меню кликабельными

Lesson 47

Настройка конфигурации запуска в PyCharm

  1. Откройте "Edit Configurations": В PyCharm перейдите в меню "Run" -> "Edit Configurations" для настройки новой конфигурации запуска.
  2. Добавление новой конфигурации: Нажмите на плюсик (+) и выберите тип конфигурации для Python.
  3. Заполнение полей конфигурации:
    • Название: Дайте конфигурации понятное имя, чтобы вы могли легко идентифицировать её среди других конфигураций.
    • Рабочая директория: Укажите директорию вашего проекта 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: добавили новые маршруты

Изменение структуры cards/url.py и cards/views.py

Изменил пути и функции для дальнейшего развития проекта.

commit: lesson_47: изменение структуры путей

Создание базового шаблона base.html в корне проекта в папке templates

  • Создали базовый шаблон base.html в папке templates
  • Указали кастомный, нестандартный путь для Джанго в файле settings.py в разделе TEMPLATES
  • Прописали там BASE_DIR / 'templates',
  • Подключили базовый шаблон для теста функции main в файле views.py

commit: lesson_47: создали базовый шаблон base.html

Синтаксис блоков в шаблонах. {% block %} и {% extends %}

  • Описали блок content в базовом шаблоне base.html
  • Создали шаблон main.html в папке templates, который расширяет базовый шаблон через {% extends %}
  • Переопределили блок content в шаблоне main.html через {% block %}
  • Подключили шаблон main.html в функции main в файле views.py

commit: lesson_47: создали шаблон main.html и расширили базовый шаблон

Создание шаблона nav_menu.html и подключение его в базовом шаблоне через {% include %}

  • Создали каталог includes в папке templates в корне проекта
  • Создали шаблон nav_menu.html в папке includes
  • Написали навигационное меню в шаблоне nav_menu.html
  • Использовали шаблонный тег {% url %} который позволяет создавать ссылки на страницы по их именам в файле urls.py
  • Подключили шаблон nav_menu.html в базовом шаблоне base.html через {% include %}
  • Добавили датасет с карточками и меню, чтобы проверить работу шаблона

commit: lesson_47: создали шаблон nav_menu.html и подключили его в базовом шаблоне

Lesson 48

Работа с шаблонами about.html, catalog.html, main.html а так же модификация views.py

  • Модифицировали все шаблоны, и сделали так, чтобы они наследовались от базового шаблона
  • Модфицировали соответствующие функции в файле views.py, чтобы они возвращали нужные шаблоны и принимали данные для меню
  • Наладили рендер меню во всех шаблонах, и получили "сквозное" меню на всех страницах

commit: lesson_48: модифицировалb все шаблоны и функции в views.py — сквозная навигация

Начали работу над каталогом карточек (динамическая вставка данных в шаблон, цикл + include)

  • Создали includes в папке templates в приложении cards
  • Внутри создали шаблон card_preview.html
  • Шаблон card_preview.html принимает на вход словарь с данными о карточке и возвращает карточку, которая будет вставлена в каталог карточек в шаблоне catalog.html в цикле

commit: lesson_48: начали работу над каталогом карточек и динамической вставкой данных в шаблон

Продолжили работу над каталогом карточек (динамическая вставка данных в шаблон, цикл + include)

  • Добавили шаблон card_detail.html в папке templates/cards
  • Доделали include в шаблоне catalog.html и вставили в него карточки из словаря
  • Обновили функцию get_detail_card_by_id — сделали поиск карточки по ID в словаре и возврат шаблона card_detail.html ИЛИ 404

commit: lesson_48: доделали каталог карточек и детальное отображение карточки по ID

Собственные шаблонные теги через simple_tag и inclusion_tag

  • Создали тег шаблона 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 и подключили статику в шаблоне base.html

  • Создали папку 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:

  • length
  • truncatechars
  • join

Так же, в шаблон был добавлен цикл для вывода тегов карточки.

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

  • Создали второй вариант шаблонного тега 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)

Lesson 49

Выполнили служебные миграции

  • Выполнили миграции командой python manage.py migrate Это создало служебные таблицы в базе данных, которые используются для работы с пользователями, сессиями, административной панелью и т.д.

  • Создали суперпользователя командой python manage.py createsuperuser

commit: lesson_49: применили первые миграции и создали админа

Сделали первую модель Card и миграции к ней

  • Создали миграцию командой python manage.py makemigrations
  • Применили миграции командой python manage.py migrate

Знакомство с Shell Plus и работа с моделью Card в интерактивной оболочке Django

  • Установка 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

CRUD Операции с этой моделью

  1. Создание записи card = Card(question='Пайтон или Питон?!', answer='Пайтон') card.save()

  2. Чтение записи card = Card.objects.get(pk=1) Мы можем добыть любые данные из записи, просто обратившись к атрибутам модели: card.question card.answer card.upload_date

  3. Обновление записи card = Card.objects.get(pk=1) card.question = 'Питон или Пайтон?!!'

  4. Удаление записи card = Card.objects.get(pk=1) card.delete()

  5. Как можно откатить миграции?

  • Целиком для приложения cards командой python manage.py migrate cards zero
  • Вернуться к конкретной миграции python manage.py migrate cards 0001_initial

commit: lesson_49: базовые CRUD Операции с моделью Card

Подключение модели Card в административной панели

  • Создали файл admin.py в приложении cards (если его нет)
  • Зарегистрировали модель Card в административной панели
  • settings.py LANGUAGE_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 в административной панели

Методы объектного менеджера objects

  • all() - возвращает все объекты модели
  • filter() - возвращает объекты, которые соответствуют условиям фильтрации
  • get() - возвращает объект, который соответствует условиям фильтрации
  • exclude() - возвращает объекты, которые НЕ соответствуют условиям фильтрации
  • order_by() - возвращает объекты, отсортированные по указанному полю
  • first() - возвращает первый объект из выборки
  • last() - возвращает последний объект из выборки
  • count() - возвращает количество объектов в выборке
  • exists() - возвращает True, если хотя бы один объект соответствует условиям фильтрации
  • delete() - удаляет объекты, которые соответствуют условиям фильтрации
  • update() - обновляет объекты, которые соответствуют условиям фильтрации
  1. Получили все карточки 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

Lesson 50

добавили новые маршруты, добавили стили и иконки, добавили адаптивность https://icons.getbootstrap.com/ - иконки для BS5 Их надо подключить по ссылке в шаблоне base.html

commit: lesson_50: сделали симпатичную вёрстку

Сделаем чтение из БД в каталоге карточек

  • В файле views.py в функции catalog изменили возврат словаря на возврат списка карточек из БД
  • В файле-вставке include/card_preview.html изменили вставку данных id карточки на card.id (что соответствует полю id в БД)

commit: lesson_50: сделали чтение из БД в каталоге карточек

Сделаем детальное отображение карточки из БД по ID

  • В файле 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):
    pass

commit: lesson_50: добавили примеры для настройки отображения админки

Добавили теги в модель Card

  • Добавили поле 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.

Примеры URL-запросов

  1. Сортировка по дате добавления в убывающем порядке (по умолчанию): /cards/catalog/
  2. Сортировка по количеству просмотров в убывающем порядке: /cards/catalog/?sort=views
  3. Сортировка по количеству добавлений в возрастающем порядке: /cards/catalog/?sort=adds&order=asc
  4. Сортировка по дате добавления в возрастающем порядке: /cards/catalog/?sort=date&order=asc

commit: lesson_50: сделали сортировку для каталога

Lookups

  • Еще раз пробежались по лукапам

get_object_or_404 для детального отображения карточки по ID

commit: lesson_50: get_object_or_404 для детального отображения карточки по ID

Lesson 51

  • импортировали F-объект
  • сделали счётчик просмотров карточки через F-объект

commit: lesson_51: рассмотрели F-объект

Подготовили базу данных anki.db

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.py tags/<int:tag_id>/ для отображения карточек по конкретному тэгу
  • написали представление cards/views.py get_cards_by_tag
  • поменяли шаблоны card_detail.html и card_preview.html для добавления кликабельности тэгам

commit: lesson_51: добавили кликабельные тэги

Lesson 52

  • убедились в том, что наше приложение генерирует слишком много запросов

commit: lesson_52: установили отладочную панель Django

  • включили жадную загрузку и снизили количество запросов с 455 до 2

commit: lesson_52: включили жадную загрузку

  • включили кэширование данных

commit: lesson_52: включили кэширование

Примеры Django ORM запросов

CREATE

# Создание новой карточки
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")

# добавление тэга к карточке
# ??????????

READ

# Получение всех карточек
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()

UPDATE

# Обновление вопроса в карточке 456
card = Card.objects.get(id=456)
card.question = "Для чего нужен Jython?"
card.save()

# Обновление имение категории
category = Category.objects.get(name="Random")
category.name = "null"
category.save()

DELETE

# Удаление карточки с id 456
card = Card.objects.get(id=456)
card.delete()

# Удаление категории с именем null
category = Category.objects.get(name="null")
category.delete()

Q объекты

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"))

F объекты

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

Lesson 53

  • добавили поля для отображения в админ. панели с помощью 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: перевели все поля в админ. панели на русский язык

Lesson 54

Шаги по установке проекта

  1. В PyCharm зайти в меню и выбрать Project from Version Control...
  2. Вставить путь до нашего проекта git@github.com:TOP-Python316/django_316.git и нажать Clone
  3. Если не было создано виртуальное окружение, то создать его через инструменты PyCharm или с помощью команды python -m venv venv
  4. Чтобы активировать виртуальное окружение перезагрузите терминал или введите команду venv\Scripts\activate
  5. Если виртуальное окружение активировано, то в терминале перед приглашением командной строки вы увидите что-то вроде (venv)
  6. Установить зависимости с помощью команды pip install -r requierements.txt
  7. Положить в корень проекта таблицу anki.db
  8. Удалить миграцию 0001_initial.py
  9. Применяем инициирующие миграции Django командой python manage.py migrate, будут созданы служебные таблицы
  10. Создаём миграцию со структурой нашей БД соответственно моделям из models.py с помощью команды python manage.py makemigrations
  11. Применяем миграцию с ключом --fake для того чтобы Django "думал", что он создал эти таблицы. Команда python manage.py migrate --fake
  12. Создаём админа с помощью команды python manage.py createsuperuser, вводим имя, пароль, почту и соглашаемся если пароль слабый

commit: lesson_54: повторили установку проекта

добавили поле status в модель Card

  • тип 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: добавили в админ. панель поле наличие кода и доп. действия

Класс CardCodeFilter

Наследуется от SimpleListFilter, который предоставляет базовую функциональность для создания простых фильтров в админке Django.

Атрибут title

Задает название фильтра, которое будет отображаться в админке. В данном случае, это "Наличие кода".

Атрибут parameter_name

Задает имя параметра, которое будет использоваться в URL для фильтрации. В данном случае, это has_code.

Метод lookups

Возвращает кортеж кортежей, где каждый внутренний кортеж состоит из двух элементов: значения параметра и человеко-читаемого названия. В данном случае, возвращаются два варианта: ('yes', 'Да') и ('no', 'Нет').

Метод queryset

Принимает запрос 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

Lesson 55

  • Сделал копию служебного шаблона 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: загрузили содержимое БД из дампа

Формы в Django

  • Создали форму не связанную с моделью. Форма для добавления карточек
  • Создали представление, обрабатывающее метод POST и возвращающее форму
  • Создали шаблон для формы
  • Протестировали работу формы
  • Проверили валидацию формы

commit: lesson_55: базовая форма для добавления карточек

  • Дополнили шаблон с построчным рендером полей ввода
  • Добавили категорию как выпадающий список form.ChoiceField

commit: lesson_55: дополнил шаблон с построчным рендером полей ввода

Lesson 56

  • вернули жадную загрузку всего каталога карточек
  • 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: базовая форма добавления файла

Lesson 57

  • Модифицировали функцию-представление 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 подсчет реального количества карточек и пользователей

Lesson 58

ListView

  • Переписали представление 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: доработка каталога и кеширование

DetailView

  • Переписали представление get_detail_card_by_id на классовое представление DetailView
  • Обновили шаблон card_detail.html для работы с классовым представлением

commit: lesson_58: get_detail_card_by_id на классовое представление DetailView

Кеширование MenuMixin

  • Использовали from django.core.cache import cache для кеширования меню, так как оно делало с каждой страницы по 2 запроса в БД

commit: lesson_58: кеширование меню с помощью cache

CreateView

  • Переписали представление добавления карточки на классовое представление CreateView - AddCardCreateView(MenuMixin, CreateView)

commit: lesson_58: добавление карточки на классовое представление CreateView

Lesson 59

UpdateView и DeleteView

  • Добавили представления UpdateView и DeleteView для редактирования и удаления карточек
  • А так же удачную правку для тегов, чтобы они на самом деле обновлялись (а не только добавлялись)
  • Шаблон для 404 ошибки (работает пока только в боевом режиме DEBUG=False, не забыть прописать ALLOWED_HOSTS=['*'] в settings.py)

commit: lesson_59: UpdateView и DeleteView и 404

Users app

  • Создали приложение 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: добавили в навигационное меню кнопки Вход и Регистрация

Lesson 60

Переписали функцию логина на LoginUser(LoginView)

  • Использовали 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

Добавление пользователя в описание карточки

  • добавили автора в модель данных Card author = 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 для приложения users c использованием класса LogoutUser

commit: lesson_60: LogoutUser(LogoutView)

  • Регистрация пользователя через простую форму связанную с моделью RegisterUserForm(forms.ModelForm):
  • Функция представления register_user для регистрации пользователя
  • Шаблон register.html для регистрации пользователя
  • Сообщение спасибо за регистрацию register_done.html

commit: lesson_60: регистрация пользователя

Lesson 61

Класс регистрации пользователя RegisterUser

  • Переписали функцию регистрации на класс RegisterUser(CreateView) — специализированного родителя нет, поэтому используем CreateView
  • Поправили urls.py для приложения users c использованием класса RegisterUser
  • Переписали старую форму на класс RegisterUserForm(UserCreationForm) — специлизированный родитель для регистрации пользователя
  • Протестировали хеширование пароля (Есть!)
  • Переписали старую форму на класс RegisterUserForm(UserCreationForm) — специлизированный родитель для регистрации пользователя
  • Протестировали хеширование пароля (Есть!)

commit: lesson_61: класс регистрации пользователя RegisterUser

Авторизация опционально через email или username

  • Создаем файл бэкенда аутентификации 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, которая наследуется от PasswordChangeForm
  • UserPasswordChangeDone - успешное изменение пароля пользователя. Наследуется от TemplateView
  • UserCardsView - карточки пользователя. Наследуется от ListView. Переопределяет метод get_queryset для получения карточек пользователя

commit: lesson_61: начал работу над личным кабинетом

Lesson 62

Восстановление пароля через email

Для этого нам необходимо подготовить целый ряд представлений и шаблонов:

Итого для работы с паролями:

Классы и их функциональность

  1. PasswordChange

    • Родитель: PasswordChangeView
    • Атрибуты:
      • template_name: Указать путь к шаблону формы смены пароля.
      • form_class: Указать класс формы для смены пароля.
      • success_url: Использовать reverse_lazy для указания URL-адреса перенаправления после успешной смены пароля.
      • extra_context: Словарь с дополнительным контекстом, например {'title': 'Смена пароля'}.
    • Методы:
      • form_valid: Метод, вызываемый при успешной валидации формы. Может быть переопределен для добавления дополнительной логики.
  2. PasswordChangeDone

    • Родитель: TemplateView
    • Атрибуты:
      • template_name: Указать путь к шаблону страницы, подтверждающей успешное изменение пароля.
      • extra_context: Словарь с дополнительным контекстом, например {'title': 'Пароль успешно изменен'}.
  3. PasswordReset

    • Родитель: PasswordResetView
    • Атрибуты:
      • template_name: Указать путь к шаблону формы запроса на сброс пароля.
      • form_class: Указать класс формы для запроса сброса пароля.
      • email_template_name: Путь к шаблону email, который будет отправлен для сброса пароля.
      • success_url: Использовать reverse_lazy для указания URL-адреса перенаправления после запроса на сброс.
      • subject_template_name: Путь к шаблону темы email.
    • Методы:
      • form_valid: Метод для дополнительной обработки после отправки формы.
  4. PasswordResetDone

    • Родитель: TemplateView
    • Атрибуты:
      • template_name: Указать путь к шаблону страницы, подтверждающей отправку инструкций по сбросу пароля.
      • extra_context: Словарь с дополнительным контекстом, например {'title': 'Инструкции отправлены'}.
  5. PasswordResetConfirm

    • Родитель: PasswordResetConfirmView
    • Атрибуты:
      • template_name: Указать путь к шаблону формы для ввода нового пароля.
      • form_class: Указать класс формы для ввода нового пароля.
      • success_url: Использовать reverse_lazy для указания URL-адреса перенаправления после успешного сброса пароля.
    • Методы:
      • form_valid: Метод для дополнительной обработки после успешной смены пароля.
  6. 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.pyAUTH_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: доделал смену пароля в ЛК

Маршруты

  • Маршрут для сброса пароля
  • Маршрут для подтверждения сброса пароля
  • Маршрут для ввода нового пароля
  • Маршрут для завершения сброса пароля

Settings

Настраиваем EMAIL_BACKEND для вывода в консоль

EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'

#TODO Скинуть курс по Docker от Стасчука #TODO Скинуть видео по интернет магазину на Django

Сделали восстановление пароля через email

commit: lesson_62: восстановление пароля через email

Lesson 63

Подготовка к деплою

  1. Регистрация на TimeWeb. https://timeweb.cloud/r/pj17346
  2. Выбор тарифа и создание виртуального сервера.
  3. Покупка домена и настройка его на TimeWeb.
  4. Подгтовка проекта к деплою
    1. Убедитесь что в проекте нет лишних файлов и папок.
    2. Создайте файл requirements.txt с зависимостями проекта.
    3. Если вы создавали .env файл, добавьте его в .gitignore.
    4. Убедитесь что .env.example содержит все необходимые переменные.
    5. Если в вашей БД есть контент, создайте дамп БД
    6. Можете прогнать тест. Просто склонируйте проект в соседнюю папку и попробуйте запустить.
  5. Команды для подготовки приложения к запуску на сервере
  6. Деплой

commit: lesson_63: подготовка к деплою

DNS (Domain Name System) — это фундаментальная технология, которая делает Интернет доступным и удобным для пользователей. Представьте себе, что DNS — это своего рода телефонная книга Интернета, которая позволяет вам находить веб-сайты и другие ресурсы по удобным для запоминания именам, а не по сложным числовым адресам. Давайте рассмотрим, почему DNS так важен и как он работает, с помощью интересных аналогий и примеров.

Почему DNS так важен?

  1. Удобство для пользователей:

    • Представьте, что вместо ввода www.example.com вам нужно запомнить и вводить что-то вроде 93.184.216.34. Это было бы очень неудобно и затруднительно. DNS позволяет использовать легко запоминающиеся доменные имена, что делает навигацию по Интернету гораздо проще.
  2. Гибкость и управление:

    • DNS позволяет владельцам веб-сайтов и других онлайн-ресурсов легко управлять своими доменными именами и IP-адресами. Например, если ваш веб-сайт переезжает на новый сервер с другим IP-адресом, вам нужно просто обновить записи DNS, и пользователи будут автоматически перенаправлены на новый сервер.
  3. Распределение нагрузки и отказоустойчивость:

    • DNS может направлять трафик на разные серверы в зависимости от географического положения пользователя или текущей нагрузки на серверы. Это помогает распределить нагрузку и обеспечить высокую доступность веб-сайтов и других онлайн-сервисов.
  4. Безопасность:

    • DNSSEC (DNS Security Extensions) добавляет уровень безопасности, защищая DNS-запросы от подделки и других атак. Это помогает предотвратить перенаправление пользователей на поддельные веб-сайты.

Как работает DNS?

Представьте, что вы хотите посетить веб-сайт www.example.com. Вот что происходит за кулисами:

  1. Запрос к рекурсивному DNS-серверу:

    • Ваш браузер отправляет запрос к рекурсивному DNS-серверу, который обычно предоставляется вашим интернет-провайдером или настроен в вашей операционной системе.
  2. Запрос к корневому DNS-серверу:

    • Если рекурсивный DNS-сервер не знает IP-адреса для www.example.com, он отправляет запрос к корневому DNS-серверу. Корневой сервер отвечает, что за доменом .com отвечает TLD-сервер.
  3. Запрос к TLD-серверу:

    • Рекурсивный DNS-сервер отправляет запрос к TLD-серверу для домена .com. TLD-сервер отвечает, что за доменом example.com отвечает авторитетный DNS-сервер.
  4. Запрос к авторитетному DNS-серверу:

    • Рекурсивный DNS-сервер отправляет запрос к авторитетному DNS-серверу для домена example.com. Авторитетный сервер отвечает IP-адресом для www.example.com.
  5. Ответ пользователю:

    • Рекурсивный DNS-сервер возвращает IP-адрес вашему браузеру, и браузер устанавливает соединение с веб-сервером по этому IP-адресу.

Интересные факты о DNS

  • История 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?

Docker — это инструмент, который позволяет создавать, развертывать и управлять контейнерами. Он предоставляет API и интерфейс командной строки для управления контейнерами, а также экосистему инструментов и сервисов для упрощения работы с контейнерами.

Основные компоненты Docker

  1. Docker Engine:

    • Основной компонент Docker, который управляет контейнерами. Docker Engine включает в себя Docker Daemon (демон Docker), который выполняет основные операции, такие как создание и управление контейнерами.
  2. Docker CLI (Command Line Interface):

    • Интерфейс командной строки для взаимодействия с Docker Engine. Позволяет пользователям выполнять команды для создания, запуска, остановки и управления контейнерами.
  3. Docker Hub:

    • Облачный реестр, который хранит и распространяет Docker-образы. Docker Hub позволяет пользователям находить, загружать и публиковать Docker-образы.
  4. Docker Compose:

    • Инструмент для определения и запуска многоконтейнерных Docker-приложений. Docker Compose использует YAML-файлы для описания конфигурации приложений и их зависимостей.
  5. Docker Swarm:

    • Встроенный инструмент для оркестрации контейнеров, который позволяет создавать и управлять кластерами Docker-контейнеров.

Концепция контейнеризации

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

Основные преимущества контейнеризации

  1. Изоляция:

    • Контейнеры изолируют приложения и их зависимости друг от друга, что позволяет избежать конфликтов и проблем с совместимостью.
  2. Портативность:

    • Контейнеры могут быть перемещены и запущены на любом сервере или в любой среде, где установлен Docker. Это упрощает процесс развертывания и миграции приложений.
  3. Легковесность:

    • Контейнеры используют общий ядро операционной системы, что делает их более легковесными по сравнению с виртуальными машинами. Это позволяет запускать больше контейнеров на одном сервере.
  4. Скорость:

    • Контейнеры запускаются быстрее, чем виртуальные машины, так как они не требуют загрузки полной операционной системы.
  5. Упрощение разработки и тестирования:

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

Пример использования Docker

Предположим, что у вас есть веб-приложение, которое требует веб-сервер (например, Nginx), базу данных (например, MySQL) и приложение на Python. Вы можете использовать Docker для создания контейнеров для каждого из этих компонентов и управлять ими с помощью Docker Compose.

  1. Создание Docker-образов:

    • Создайте Dockerfile для каждого компонента вашего приложения. Dockerfile описывает, как создать Docker-образ для конкретного компонента.
  2. Создание 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

  1. Запуск приложения:
    • Используйте команду docker-compose up для запуска вашего приложения и его зависимостей.

Заключение

commit: lesson_63: информация о Docker

Lesson 64

  1. Настройка DEBUG в settings.py для отладочного режима. Чтобы на сервере не отображались отладочные сообщения, установите DEBUG = False и добавьте домен сервера в список ALLOWED_HOSTS. DEBUG = os.getenv('DEBUG')
  2. Настройка ALLOWED_HOSTS в settings.py для домена cardslurm.ru. ALLOWED_HOSTS - это список хостов, которые могут обращаться к нашему сайту ALLOWED_HOSTS = ['cardslurm.ru', 'www.cardslurm.ru', 'localhost', '127.0.0.1']
  3. Настройка CSRF_TRUSTED_ORIGINS в settings.py для безопасной работы с формами. CSRF_TRUSTED_ORIGINS - это список доменов, с которых можно отправлять POST-запросы без токена CSRF CSRF_TRUSTED_ORIGINS = ['https://cardslurm.ru', 'https://www.cardslurm.ru']
  4. Добавление IF DEBUG для отладочной панели Django. INTERNAL_IPS - это список IP-адресов, с которых можно получить доступ к отладочной панели Django if DEBUG:
    INTERNAL_IPS = [ '127.0.0.1', ] commit: lesson_64: дополнительная настройка для работы проекта

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Contributors 3

  •  
  •  
  •  

Languages