Django — наиболее часто используемый фреймворк Python для
Требования
Чтобы получить максимальную отдачу от этого руководства, в идеале вы должны иметь представление о следующем:
основы Python
основы
Если у вас нет опыта работы с Django, не бойтесь продолжать изучение этого руководства. Это будет пошаговый процесс, и каждый шаг будет объяснен.
Прежде чем начать, я хочу познакомить вас с вашим новым лучшим союзником — документацией Django. Мы будем ссылаться на него на протяжении всей статьи, поэтому обязательно ознакомьтесь с ним.
Приложение Django для обмена фотографиями
Весь исходный код этого руководства доступен в этом репозитории GitHub.
Сложность проекта зависит от всех функций, которые мы хотим включить. Чем больше функций мы хотим предложить пользователям, тем больше времени нам потребуется на создание и интеграцию всего в уникальный проект.
Принимая это во внимание, мы увидим быстрое различие между тем, что мы собираемся построить, и тем, что мы не создадим.
Что мы собираемся строить
В этом руководстве мы создадим полнофункциональное приложение для обмена фотографиями (внутренняя и внешняя разработка). Наше приложение будет включать в себя следующие функции:
Функциональность базы данных CRUD (создание, чтение, обновление, удаление)
система управления пользователями, чтобы пользователи могли создавать учетную запись, загружать фотографии, просматривать фотографии других людей и редактировать или удалять свои собственные фотографии
простой
Примечание: хотя это приложение и кажется очень похожим на социальную сеть, это не так. Такие приложения, как Instagram или Twitter, очень сложны, и их невозможно описать в одной статье.
Стек технологий
Давайте определим технологии, которые мы собираемся использовать. Мы рассмотрим процесс установки каждого из них, когда нам понадобится его использовать.
На бэкенде Django будет основной структурой приложения. Это позволяет нам определять
Кроме того, мы будем использовать несколько сторонних пакетов для ускорения разработки некоторых функций.
Во внешнем интерфейсе мы будем использовать язык шаблонов Django, который состоит из
Мы также будем использовать Bootstrap 5 (последняя версия на момент написания статьи) для дизайна сайта.
Примечание: вы всегда можете проверить используемые в этом проекте зависимости в файле requirements.txt.
Создайте проект Джанго
Начнем с Джанго!
Прежде всего, убедитесь, что у вас установлен Python 3. В большинстве систем Linux и macOS уже установлен Python, но если вы используете Windows, вы можете ознакомиться с руководством по установке Python 3.
Примечание: в этом руководстве мы будем использовать команды Unix (macOS и Linux). Если вы не можете выполнить их по
В некоторых дистрибутивах Linux pythonкоманда относится к Python 2. В других pythonвообще не существует.
Давайте посмотрим, какую команду Python вам нужно использовать, чтобы следовать дальше. Откройте терминал (в Unix) или окно командной строки (в Windows) и введите python —version:
python —version
# My result
Python 3.9.5
Если у вас есть версия Python выше 3.6, вы готовы к работе. Если у вас нет подходящей версии Python, вы можете получить сообщение, подобное одному из этих:
Command 'python’ not found
Python 2.7.18
Команда Python, которую вам нужно выполнить, чтобы следовать этому руководству, будет python3:
python3 —version
Python 3.9.5
Виртуальные среды
Виртуальная среда — это изолированная среда Python, которая включает в себя все файлы, необходимые для запуска программы Python.
Виртуальные среды являются важной частью любого проекта Python (и Django), поскольку они позволяют нам управлять зависимостями (внешними пакетами, от которых зависит проект) и делиться ими с другими людьми.
Чтобы создать нативную виртуальную среду, мы будем использовать встроенный модуль venv, доступный в Python 3.6 или более поздней версии.
Следующая команда создаст виртуальную среду с именем.venv (вы можете выбрать другое имя, если хотите):
python -m venv.venv
Если вы используете Ubuntu Linux или любой другой дистрибутив на основе Debian, возможно, вы получите следующее сообщение:
The virtual environment was not created successfully because pip is not available...
Чтобы решить эту проблему, вы можете запустить следующую команду:
sudo
Если приведенная выше команда не работает, вы можете использовать virtualenv, еще одну библиотеку для работы с виртуальными средами:
virtualenv.venv
После запуска этой команды появится папка с именем.venv (или именем, которое вы выбрали).
Все пакеты, которые мы устанавливаем, будут помещены в этот каталог.
Чтобы активировать виртуальную среду, вам нужно выполнить определенную команду в зависимости от вашей ОС. Вы можете обратиться к таблице ниже (извлеченной из документации Python).
Платформа Оболочка Команда для активации виртуальной среды
POSIX баш/зш $ источник.venv/bin/активировать
рыба $ источник.venv/bin/activate.fish
csh/tcsh $ источник.venv/bin/activate.csh
Ядро PowerShell $.venv/bin/Activate.ps1
Окна cmd.exe C: >.venv\Scripts\activate.bat
PowerShell PS C: >.venv\Scripts\Activate.ps1
Поскольку я использую оболочку bash в операционной системе POSIX, я буду использовать это:
source.venv/bin/activate
Обратите внимание, как.venvподпись добавляется в мою оболочку после того, как я активировал файл virtualenv.
Виртуальная среда активирована
Установка Джанго
Django — это внешний пакет, поэтому нам нужно установить его с помощью pip:
pip install django
# Use pip3 if the command above doesn’t work
pip3 install django
Примечание: мы всегда можем взглянуть на пакеты, установленные в нашем файле venvwith pip freeze.
Далее запустим проект Django с именем configс помощью утилиты командной строки
Здесь configимя проекта, и оно используется в качестве соглашения об именах, чтобы все ваши проекты имели одинаковую структуру. Например, Django cookiecutter использует это условное имя для запуска проекта.
При этом вы можете создать проект с любым другим именем.
После выполнения этих команд у вас должна быть обычная файловая структура проекта Django. Вы можете проверить это с помощью дерева утилит командной строки или любого файлового менеджера.
Примечание: если вы не можете запустить tree, вам необходимо установить его.
$ tree config/
└── config
├── config
│ ├── asgi.py
│ ├── __init__.py
│ ├── settings.py
│ ├── urls.py
│ └── wsgi.py
└── manage.py
Теперь давайте войдем в папку проекта с помощью cdи запустим сервер, чтобы убедиться, что все настроено правильно:
cd config/
python manage.py runserver
Вы увидите предупреждающее сообщение о наличии непримененных миграций. Это совершенно нормальное сообщение, и мы научимся выполнять миграции в разделе «Создание фотомодели «.
Теперь зайдите на localhost:8000 в браузере. Вы должны увидеть культовую страницу поздравления Django.
Страница поздравлений Джанго
Запуск приложения для обмена фотографиями
Файл manage.py имеет те же возможности, что и
Его расположение находится в корневой папке проекта, и каждый раз, когда мы хотим запустить с ним команду, нам нужно войти в каталог проекта.
Не забывайте всегда перечислять файлы каталога, в котором вы находитесь ls, чтобы проверить, находимся ли мы в правильном месте:
$ ls
Имея в виду эти советы, пришло время запустить основное приложение проекта. Для этого мы открываем новую оболочку (чтобы локальный сервер все еще работал) и используем manage.pyкоманду startapp.
Примечание: каждый раз, когда мы открываем новый сеанс оболочки, нам нужно будет снова активировать виртуальную среду.
source.venv/bin/activate
cd config
python manage.py startapp photoapp
В данном случае имя приложения — photoapp. Еще раз, вы можете создать его с любым именем, которое хотите.
Каждый раз, когда мы создаем приложение, мы должны его установить. Мы можем сделать это в config/settings.pyфайле, добавив photoappв INSTALLED_APPSпеременную:
# config/settings.py
INSTALLED_APPS = [
'django.contrib.admin’,
...
# Custom apps
'photoapp’,
]
Далее мы войдем в каталог приложения и создадим пустой urls.pyфайл. Мы можем сделать это, запустив touchили создав его с помощью графического файлового менеджера:
cd photoapp/
touch urls.py
Наконец, давайте включим все шаблоны URL приложения для обмена фотографиями в общий проект. Для этого воспользуемся django.urls.includeфункцией:
# config/urls.py
from django.urls import path, include # Import this function
urlpatterns = [
path ('admin/', admin.site.urls),
# Main app
path ('', include ('photoapp.urls’)),
]
Приведенный выше код будет включать все шаблоны URL photoapp/urls.pyдля проекта.
Если вы посмотрите на оболочку, в которой работает сервер, вы увидите ошибку:
raise ImproperlyConfigured (msg.format (name=self.urlconf_name))...
Это потому, что мы не создали urlpatternsсписок внутри photopp/urls.pyфайла.
Чтобы решить эту проблему, создайте пустой список с именем urlpatterns. Позже мы собираемся заполнить эту переменную путями Django:
# photoapp/urls.py
# Empty patterns
urlpatterns = [
]
Примечание: преимущество использования этого подхода заключается в том, что мы можем сделать фотоприложение многоразовым, включив в него весь необходимый код.
Создание фотомодели
В этом разделе мы собираемся построить схему базы данных нашего приложения. Для этой цели мы будем использовать Django ORM.
Django ORM позволяет создавать и управлять таблицами базы данных без необходимости использовать SQL вручную.
Когда мы пишем модель, она представляет собой таблицу базы данных, а каждый атрибут внутри нее представляет собой столбец.
Поскольку мы будем использовать встроенную систему аутентификации Django, мы можем сосредоточиться на основных функциях приложения. Таким образом, мы избегаем создания собственной системы управления пользователями.
Прежде чем начать, мы собираемся установить некоторые сторонние пакеты
pip install
# config/settings.py
INSTALLED_APPS = [
...
# 3rd party apps
'taggit’,
# Custom apps
'photoapp’,
]
# Django taggit
TAGGIT_CASE_INSENSITIVE = True
Эта TAGGIT_CASE_INSENSITIVEпеременная настраивает теги так, чтобы они были нечувствительны к регистру. Значит PYTHONи pythonбудет так же.
Определим Photoмодель, которая будет основной моделью приложения. Откройте photoapp/models.pyфайл и используйте следующий код:
# photoapp/models.py
from django.db import models
from django.contrib.auth import get_user_model
from taggit.managers import TaggableManager
class Photo (models.Model):
title = models.CharField (max_length=45)
description = models.CharField (max_length=250)
created = models.DateTimeField (auto_now_add=True)
image = models.ImageField (upload_to='photos/')
submitter = models.ForeignKey (get_user_model (), on_delete=models.CASCADE)
tags = TaggableManager ()
def __str__ (self):
return self.title
В приведенном выше блоке кода мы определили Photoмодель. Давайте посмотрим, что делает каждое поле.
Поле titleпредставляет собой CharField и может содержать не более 45 символов.
descriptionэто еще один CharField, но с ограничением в 250 символов.
createdявляется DateTimeField и, как следует из названия, хранит дату и час создания фотографии.
imageявляется ImageField. Он загружает изображения media/photosи сохраняет
submitter— это ForeignKey, что означает связь с пользователем и загруженной фотографией. Таким образом, мы можем отфильтровать, какой пользователь загрузил фотографию.
Наконец, tagsэто TaggableManager, который позволяет нам классифицировать темы по тегам.
С другой стороны, __str__метод указывает, как каждый объект будет отображаться в админке. Позже мы настроим администратора и создадим наши первые объекты.
Чтобы создать базу данных на основе созданной нами модели, нам сначала нужно выполнить миграции, а затем запустить их.
Войдите в корневой каталог проекта и используйте manage.pyскрипт со следующими аргументами:
python manage.py makemigrations
python manage.py migrate
Команда makemigrationsсоздаст файл миграции на основе Photoмодели.
Примечание. Миграции — это скрипты Python, которые производят изменения в базе данных на основе моделей.
Мы можем точно увидеть, что происходит с этой миграцией, открыв photoapp/migrations/0001_initial.pyфайл:
# photoapp/migrations/0001_initial.py
# imports...
class Migration (migrations.Migration):
initial = True
dependencies = [
('taggit’, '0003_taggeditem_add_unique_index’),
migrations.swappable_dependency (settings.AUTH_USER_MODEL),
]
operations = [
migrations.CreateModel (
name='Photo’,
fields=[
('id’, models.BigAutoField (auto_created=True, primary_key=True, serialize=False, verbose_name='ID’)),
....
Совет: никогда не изменяйте файл миграции вручную. Все миграции должны быть автоматически сгенерированы Django.
Команда migrateсоздает таблицы базы данных, выполняя все миграции.
После выполнения этих двух команд вы должны увидеть базу данных SQLite в корневой папке проекта. Если мы проверим его с помощью DB Browser, мы увидим все поля, связанные с Photoмоделью.
Визуализатор SQLite
Управление медиафайлами в разработке
Приложение для обмена фотографиями сильно зависит от медиафайлов. Все дело в обмене изображениями, не так ли?
Медиафайлы в Django — это все файлы, загруженные пользователем. На данный момент мы собираемся настроить медиафайлы в разработке, так как мы будем взаимодействовать с приложением только через локальный сервер.
Чтобы включить медиафайлы в разработке, мы создаем переменные MEDIA_URL и MEDIA_ROOT внутри файла настроек. Кроме того, нам нужно изменить urlpatternsобщий проект для обслуживания медиафайлов с локального сервера.
# config/settings.py
# Other settings...
MEDIA_URL = '/media/'
MEDIA_ROOT = BASE_DIR / 'media/'
MEDIA_URL— это
С другой стороны, MEDIA_ROOTэто путь, указывающий на папку, в которую будут помещены все медиафайлы.
Помните, что, поскольку мы используем библиотеку pathlib, мы можем объединять пути с /.
Мы можем представить MEDIA_ROOTсебе физическое хранилище, куда будут загружены изображения, и MEDIA_
Если мы хотим, чтобы Django управлял медиафайлами, нам нужно изменить
# config/urls.py
# New imports
from django.conf import settings
from django.conf.urls.static import static
urlpatterns = [
path ('admin/', admin.site.urls),
# Main app
path ('', include ('photoapp.urls’)),
] + static (settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
С учетом этого абсолютный URL загружаемых фотографий будет таким: http: //localhost:8000/media/photos/. Это потому, что мы устанавливаем upload_toатрибут как photos/.
Примечание: принимать загруженные файлы от пользователя может быть опасно. Ознакомьтесь с этим списком соображений безопасности.
При работе с общедоступным приложением мы должны быть осторожны с медиафайлами. Мы можем пострадать от
На данный момент вы можете забыть о проблемах безопасности, так как мы работаем с проектом разработки и ImageFieldпринимаем только заранее определенный набор расширений.
Вы можете проверить эти действительные расширения, запустив следующий код в оболочке Django (убедившись, что venvон активирован):
$ python manage.py shell
>>> from django.core.validators import get_available_image_extensions
>>> get_available_image_extensions ()
['blp’, 'bmp’, 'dib’, 'bufr’, 'cur’, 'pcx’, 'dcx’, 'dds’, 'ps’, 'eps’, 'fit’, 'fits’, 'fli’, 'flc’, 'ftc’, 'ftu’, 'gbr’, 'gif’, 'grib’, 'h5', 'hdf’, 'png’, 'apng’, 'jp2', 'j2k’, 'jpc’, 'jpf’, 'jpx’, 'j2c’, 'icns’, 'ico’, 'im’, 'iim’, 'tif’, 'tiff’, 'jfif’, 'jpe’, 'jpg’, 'jpeg’, 'mpg’, 'mpeg’, 'mpo’, 'msp’, 'palm’, 'pcd’, 'pdf’, 'pxr’, 'pbm’, 'pgm’, 'ppm’, 'pnm’, 'psd’, 'bw’, 'rgb’, 'rgba’, 'sgi’, 'ras’, 'tga’, 'icb’, 'vda’, 'vst’, 'webp’, 'wmf’, 'emf’, 'xbm’, 'xpm’]
Тестирование моделей с помощью Django Admin
Администратор Django — это встроенный интерфейс, в котором пользователи с правами администратора могут выполнять операции CRUD с зарегистрированными моделями проекта.
Теперь, когда мы создали фотомодель и настроили медиафайлы, пришло время создать наш первый Photoобъект через страницу администрирования.
Для этого мы должны зарегистрировать Photoмодель на странице администратора. Давайте откроем photoapp/admin.py, импортируем модель Photo и передадим ее в качестве параметра admin.site.registerфункции:
# photoapp/admin.py
from django.contrib import admin
from.models import Photo # We import the photo model
# Register your models here.
admin.site.register (Photo)
Затем пришло время создать суперпользователя, чтобы иметь доступ к странице администратора. Мы можем сделать это с помощью следующей команды:
python manage.py createsuperuser
Username: daniel
Email address:
Password:
Password (again):
Superuser created successfully
На данный момент вы можете оставить суперпользователя без электронной почты, так как мы используем пользователя авторизации по умолчанию.
После создания суперпользователя перейдите в браузер и перейдите по адресу http: //localhost:8000/admin.
Он перенаправит вас на страницу входа, где вам нужно будет ввести свои учетные данные (те, с которыми вы создали пользователя).
Страница входа администратора Django
После ввода наших учетных данных у нас будет доступ к простой панели инструментов, где мы можем начать создавать фотографии. Просто щелкните раздел «Фотографии», а затем кнопку «Добавить «.
Панель инструментов Джанго
Вот как выглядит заполнение полей создания.
Заполнение контента
Загрузить изображение можно простым перетаскиванием.
Загрузка изображений
После нажатия кнопки «Сохранить «мы увидим панель со всеми созданными фотографиями.
Фото приборной панели
Обработка
Мы определили схему базы данных рабочего приложения и даже создали некоторые объекты с помощью администратора Django. Но мы не коснулись самой важной части любого
В этом разделе мы собираемся создать представления приложения для обмена фотографиями.
В широком смысле представление — это вызываемый объект Python (класс или функция), который принимает запрос и возвращает ответ.
Согласно документации Django, мы должны поместить все наши представления в файл с именем views.pyвнутри каждого приложения. Этот файл уже был создан, когда мы запускали приложение.
У нас есть два основных способа создания представлений: использование представлений на основе функций (FBV) или представлений на основе классов (CBV).
CBV — лучший способ повторного использования кода, применяя возможности наследования классов Python в наших представлениях.
В нашем приложении мы будем использовать общие представления, которые позволяют нам создавать простые операции CRUD, наследуя предварительно созданные классы Django.
Прежде чем начать, мы импортируем все, что нам нужно для создания представлений. Откройте photoapp/views.pyфайл и вставьте код ниже:
# photoapp/views.py
from django.shortcuts import get_object_or_404
from django.core.exceptions import PermissionDenied
from django.views.generic import ListView, DetailView, CreateView, UpdateView, DeleteView
from django.contrib.auth.mixins import LoginRequiredMixin, UserPassesTestMixin
from django.urls import reverse_lazy
from.models import Photo
Давайте посмотрим, что мы импортируем сюда:
get_object_or_404— это ярлык, который позволяет нам извлекать объект из базы данных, предотвращая DoesNotExistsошибку и вызывая исключение HTTP 404.
PermissionDeniedвызвать исключение HTTP 403 при вызове.
Готовые genericпредставления помогают нам создавать функциональные возможности CRUD с помощью нескольких строк кода.
Мы будем использовать LoginRequiredMixinи UserPassesTestMixinдля утверждения, что у пользователей есть правильные разрешения при доступе к представлению.
reverse_lazyиспользуется в CBV для перенаправления пользователей на определенный
Нам нужно импортировать Photo, чтобы получить и обновить строки базы данных (объекты фотографий).
Примечание. Вы можете получить доступ к файлу views.py на GitHub.
Просмотры списков фотографий
Общее представление списка поможет нам отобразить многие объекты модели. Мы сравним его с более DetailViewпоздним.
В этом разделе мы собираемся создать два основных представления. Передает PhotoListViewв качестве контекста все фотографии, загруженные любым пользователем, и PhotoTagListViewпринимает тег тега в качестве аргумента для отображения фотографий.
В приведенном ниже коде определяется PhotoListViewнаследование от ListView:
# photoapp/views.py
class PhotoListView (ListView):
model = Photo
template_name = 'photoapp/list.html’
context_object_name = 'photos’
Помните, вы всегда можете проверить исходный код любого класса Django в официальном репозитории GitHub.
Затем мы определяем модель, из которой мы считываем данные, шаблон, который мы собираемся использовать (позже мы создадим внешний интерфейс), и имя объекта контекста, который мы можем использовать для доступа к данным в шаблоне.
Теперь пришло время объявить PhotoTagListView. Это представление немного сложнее, так как мы должны играть с методами get_queryset () и: get_context_data ()
# photoapp/views.py
class PhotoListView (ListView):...
class PhotoTagListView (PhotoListView):
template_name = 'photoapp/taglist.html’
# Custom method
def get_tag (self):
return self.kwargs.get ('tag’)
def get_queryset (self):
return self.model.objects.filter (tags__slug=self.get_tag ())
def get_context_data (self, **kwargs):
context = super ().get_context_data (**kwargs)
context[«tag"] = self.get_tag ()
return context
Здесь мы наследуем все атрибуты файла PhotoListView. Это означает, что мы используем то же самое modelи context_object_name, но меняем template_name.
Это представление может показаться таким же, как и предыдущее, за исключением того, что мы имеем дело с пользовательскими методами.
Мы создаем пользовательский метод get_tagдля получения слага тега из ответа, который Django собирается принять и вернуть. Мы делаем это так, потому что собираемся использовать эту функцию в двух местах.
Метод get_querysetнастроен на возврат self.model.objects.all () по умолчанию. Мы изменили его, чтобы возвращались только фотообъекты, помеченные слагом, переданным в
Наконец, get_context_dataбыл изменен, чтобы также возвращать тег, переданный в
Подробный просмотр фото
Это простое DetailViewпредставление, которое отображает все данные, относящиеся к уникальной фотографии. Это включает в себя заголовок, описание и теги нужной фотографии:
# photoapp/views.py
class PhotoListView (ListView):...
class PhotoTagListView (PhotoListView):...
class PhotoDetailView (DetailView):
model = Photo
template_name = 'photoapp/detail.html’
context_object_name = 'photo’
Мы делаем почти тот же процесс, что и с представлениями списка. Единственное отличие состоит в том, что мы возвращаем один объект вместо многих и используем другой шаблон.
Создать просмотр фотографий
Это представление позволяет пользователям создавать фотообъекты, только если они вошли в систему. Мы не хотим, чтобы анонимные пользователи могли загружать контент на нашу платформу. Это было бы страшно!
Самый простой способ защитить эту функциональность с помощью Django — создать класс, который наследуется от CreateViewи LoginRequiredMixin. Проверяет, вошел ли пользователь в систему. LoginRequiredMixinЕсли пользователь не вошел в систему, он перенаправляется на страницу входа (которую мы создадим позже):
# photoapp/views.py
class PhotoListView (ListView):...
class PhotoTagListView (PhotoListView):...
class PhotoDetailView (DetailView):...
class PhotoCreateView (LoginRequiredMixin, CreateView):
model = Photo
fields = ['title’, 'description’, 'image’, 'tags’]
template_name = 'photoapp/create.html’
success_url = reverse_lazy ('photo: list’)
def form_valid (self, form):
form.instance.submitter = self.request.user
return super ().form_valid (form)
В этом представлении Django создаст форму с полями, titleи description.imagetags
Мы также используем sucess_urlатрибут. Пользователи будут перенаправлены на панель управления фотографиями, если создание фотографии прошло успешно.
Если мы внимательно посмотрим на этот form_validметод, мы заметим, что он настраивает пользователя, который делает запрос, в качестве отправителя формы с фотографией.
Обновление и удаление просмотров фотографий
Мы хотим, чтобы пользователи могли изменять или удалять фотографии только в том случае, если они являются отправителями.
Обработка условной аутентификации может быть затруднена, если мы используем CBV. Однако мы можем использовать TestMixins для выполнения этой задачи.
Давайте создадим тестовый миксин UserIsSubmitter, который проверяет, действительно ли пользователь, пытающийся обновить или удалить фотографию, отправил ее:
# photoapp/views.py
class PhotoListView (ListView):...
class PhotoTagListView (PhotoListView):...
class PhotoDetailView (DetailView):...
class PhotoCreateView (LoginRequiredMixin, CreateView):...
class UserIsSubmitter (UserPassesTestMixin):
# Custom method
def get_photo (self):
return get_object_or_404 (Photo, pk=self.kwargs.get ('pk’))
def test_func (self):
if self.request.user.is_authenticated:
return self.request.user == self.get_photo ().submitter
else:
raise PermissionDenied ('Sorry you are not allowed here’)
Затем мы определили тестовую функцию. Он вернет true только в том случае, если пользователь вошел в систему и является отправителем фотографии.
Если пользователь не вошел в систему, это вызовет исключение PermissionDenied.
С другой стороны, PhotoUpdateViewи PhotoDeleteViewявляются дочерними элементами созданного нами миксина, а также UpdateViewи DeleteViewсоответственно:
# photoapp/views.py
class PhotoListView (ListView):...
class PhotoTagListView (PhotoListView):...
class PhotoDetailView (DetailView):...
class PhotoCreateView (LoginRequiredMixin, CreateView):...
class UserIsSubmitter (UserPassesTestMixin):...
class PhotoUpdateView (UserIsSubmitter, UpdateView):
template_name = 'photoapp/update.html’
model = Photo
fields = ['title’, 'description’, 'tags’]
success_url = reverse_lazy ('photo: list’)
class PhotoDeleteView (UserIsSubmitter, DeleteView):
template_name = 'photoapp/delete.html’
model = Photo
success_url = reverse_lazy ('photo: list’)
PhotoUpdateViewнаследует функцию тестирования от UserIsSubmitterмиксина и функцию обновления от UpdateViewфайла.
Атрибут fieldsопределяет поля, которые пользователь сможет редактировать. Мы не хотим, чтобы менялось изображение, ни дата создания, ни отправитель.
С другой стороны, PhotoDeleteViewтакже наследует тестовую функцию, но удаляет фотографию вместо ее обновления.
Оба представления перенаправляют пользователя на
Это все для просмотров. Теперь давайте создадим простое приложение для аутентификации и завершим проект.
Мы почти там. Мы уже определили схему базы данных и то, как пользователь будет создавать и обновлять фотографии. Давайте посмотрим, как настроить
Вы помните, когда мы создали пустую urlpatternsпеременную в начале проекта? Пришло время заселить его!
# photoapp/urls.py
from django.urls import path
from.views import (
PhotoListView,
PhotoTagListView,
PhotoDetailView,
PhotoCreateView,
PhotoUpdateView,
PhotoDeleteView
)
Функция пути получает два аргумента, routeи viewи необязательный аргумент, nameкоторый используется как часть пространства имен:
# photoapp/urls.py
app_name = 'photo’
urlpatterns = [
path ('', PhotoListView.as_view (), name='list’),
path ('tag/
path ('photo/
path ('photo/create/', PhotoCreateView.as_view (), name='create’),
path ('photo/
path ('photo/
]
Объясняя эту конфигурацию, app_nameпеременная объявляет пространство имен приложения.
Это означает, что независимо от того, используем ли мы reverseфункцию в представлениях или {% url%}тег в шаблонах, нам нужно использовать следующее пространство имен:
photo: <
Если вы хотите узнать больше о том, как работает диспетчер
Система аутентификации
В этом проекте мы будем использовать систему аутентификации Django по умолчанию.
Это связано с тем, что наша главная цель — как можно скорее получить функциональное приложение. Однако мы создадим собственное приложение, потому что хотим добавить в проект функцию регистрации.
Сначала мы создаем usersприложение и выполняем тот же процесс установки, что и с photoapp:
python manage.py startapp users
# config/settings.py
INSTALLED_APPS = [
...
# 3rd party apps
'taggit’,
# Custom apps
'photoapp’,
'users’,
]
Далее мы создаем urls.pyфайл так же, как мы делали это с
cd users/
touch urls.py
Затем мы включаем
# config/urls.py
urlpatterns = [
path ('admin/', admin.site.urls),
# Main app
path ('', include ('photoapp.urls’)),
# Auth app
path ('users/', include ('users.urls’)),
] + static (settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
Затем мы пишем a, SignUpViewчтобы позволить пользователю зарегистрироваться через сайт:
# users/views.py
from django.views.generic import CreateView
from django.contrib.auth import authenticate, login
from django.contrib.auth.forms import UserCreationForm
from django.urls import reverse_lazy
class SignUpView (CreateView):
template_name = 'users/signup.html’
form_class = UserCreationForm
success_url = reverse_lazy ('photo: list’)
def form_valid (self, form):
to_return = super ().form_valid (form)
user = authenticate (
username=form.cleaned_data["username"],
password=form.cleaned_data["password1»],
)
login (self.request, user)
return to_return
Это представление является CreateView и работает со встроенной формой UserCreationForm для создания нового пользователя.
Мы используем этот form_validметод для входа пользователей перед перенаправлением их на панель управления фотографиями.
Мы создадим представление входа, потому что мы хотим использовать настраиваемый шаблон для отображения страницы входа. Для этого импортируем встроенный LoginViewи наследуемся от него:
# Previous imports
from django.contrib.auth.views import LoginView
class SignUpView (CreateView):...
class CustomLoginView (LoginView):
template_name = 'users/login.html’
Наконец, пришло время создать маршрутизацию URL:
# users/urls.py
from django.urls import path
from django.contrib.auth.views import LogoutView
from.views import SignUpView, CustomLoginView
app_name = 'user’
urlpatterns = [
path ('signup/', SignUpView.as_view (), name='signup’),
path ('login/', CustomLoginView.as_view (), name='login’),
path ('logout/', LogoutView.as_view (), name='logout’),
]
Еще раз, мы используем app_nameпеременную. Таким образом, пространство имен пользовательского приложения будет таким:
user: <
Мы настраиваем три URL. И signup/используют login/созданные нами пользовательские представления, но logout/
Прежде чем продолжить, давайте настроим перенаправления аутентификации в config/settings.pyфайле:
# Other settings...
USE_TZ = True
# Django Authentication
LOGIN_URL = 'user: login’
LOGIN_REDIRECT_URL = 'photo: list’
LOGOUT_REDIRECT_URL = 'photo: list’
Это сообщает Django, что
Передняя часть
После создания серверной части (то, что пользователь не может видеть) с помощью Django пришло время создать переднюю часть (то, что видит пользователь).
Для этой цели мы будем использовать язык шаблонов Django и Bootstrap 5. Это позволяет нам динамически генерировать HTML и выводить разные выходные данные в зависимости от состояния нашей базы данных. Мы можем сэкономить много кода, работая с наследованием шаблонов. Использование Bootstrap 5 означает, что мы не будем использовать статические файлы.
Пишем базовый шаблон
В этом разделе мы собираемся создать base.htmlфайл, который является шаблоном, от которого будут наследоваться все остальные.
Для этого мы должны изменить DIRSключ внутри TEMPLATESпеременной, расположенной в файле настроек:
# config/settings.py
TEMPLATES = [
{
# Options...
'DIRS’: [BASE_DIR / 'templates’],
'APP_DIRS’: True,
# More options
},
]
По умолчанию Django ищет файлы шаблонов в templates/папке каждого приложения.
Например, шаблоны приложения для обмена фотографиями можно найти в файлах photoapp/templates. То же самое и с приложением пользователей (users/templates).
Назначая DIRSключ [BASE_DIR / 'templates’], мы говорим Django также искать шаблоны внутри папки с именем templates.
Создайте каталог templatesв корне проекта (где находится manage.pyфайл) и коснитесь шаблонов base.htmlи: navbar.html
ls
# manage.py
mkdir templates && cd templates
touch base.html navbar.html
Заключительные шаблоны нашего проекта можно найти в любом из этих трех каталогов:
.
├── photoapp
│ └── templates
│ └── photoapp
├── templates
└── users
└── templates
└── users
Помните, что вы всегда можете проверить структуру проекта в репозитории GitHub.
Внутри base.htmlшаблона мы настроим базовую структуру HTML, некоторые метатеги, ссылки на загрузочную CDN и блоки, которые будут использовать другие шаблоны:
<! DOCTYPE html>
http-equiv="X-UA-Compatible" content="IE=edge" />
<link
href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0/dist/css/bootstrap.min.css"
rel="stylesheet"
integrity="sha384-wEmeIV1mKuiNpC+IOBjI7aAzPcEZeedi5yW5f2yOq55WWLwNGmvvx4Um1vskeMj0"
crossorigin="anonymous"
/>
<link
rel="stylesheet"
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.3/css/all.min.css"
integrity="sha512-iBBXm8fW90+nuLcSKlbmrPcLa0OT92xO1BIsZ+ywDWZCvqsWgccV3gFoRBv0z+8dLJgyAHIhR35VZc2oM/gI1w=="
crossorigin="anonymous"
/>
{% include 'navbar.html’%}
{% block body%}
{% endblock body%}
crossorigin="anonymous" >
Тег {% include%} (как следует из названия) включает в себя весь код выбранного шаблона внутри base.htmlфайла.
Поэтому весь код, присутствующий внутри navbar.html, будет помещен в начало тела.
Примечание: здесь много HTML и Bootstrap. Не стесняйтесь копировать все это, так как это не основная цель урока.
Ниже приведен код
Photo App
<button
class="navbar-toggler"
type="button"
>
<div
class="collapse navbar-collapse flex-row-reverse"
id="navbarTogglerDemo02"
>
{% if user.is_authenticated%}
{% else%}
{% endif%}
Вот как будет отображаться шаблон, когда пользователь войдет в систему.
Navbar, когда пользователь вошел в систему
Ниже показано, что отображается, когда пользователь не вошел в систему.
Панель навигации, когда пользователь не вошел в систему
Не волнуйтесь, если вы получите сообщение об ошибке в своем браузере. Мы еще не создали шаблоны для обмена фотографиями.
Шаблоны для обмена фотографиями
Мы собираемся написать все файлы, необходимые в приложении для обмена фотографиями. Это включает в себя шаблоны, используемые для выполнения операций CRUD.
Все эти шаблоны будут расширять base.htmlшаблон и будут расположены в photoapp/templates/photoappкаталоге.
Но прежде чем работать с формами в шаблонах, мы воспользуемся хрустящими формами Django для стилизации нашего приложения:
pip install
Еще раз, crispy_formsэто приложение Django, и нам нужно включить его в INSTALLED_APPSсписок:
# config/settings.py
INSTALLED_APPS = [
...
# 3rd party apps
'taggit’,
'crispy_forms’,
# Custom apps
'photoapp’,
'users’,
]
# Indicates the frontend framework django crispy forms will use
CRISPY_TEMPLATE_PACK = 'bootstrap4'
Мы используем пакет шаблонов Bootstrap 4, потому что классы форм Bootstrap совместимы между
Возможно, вы помните, что мы использовали следующие имена шаблонов в photoapp/views.py:
'photoapp/list.html’
'photoapp/taglist.html’
'photoapp/detail.html’
'photoapp/create.html’
'photoapp/update.html’
'photoapp/delete.html’
Это означает, что все эти шаблоны будут расположены в photoapp/templates/photoapp.
Чтобы создать эту папку, перейдите в приложение для обмена фотографиями и создайте каталог templates/, а внутри него создайте еще одну папку с именем photoapp/:
cd photoapp/
mkdir -p templates/photoapp/
cd templates/photoapp/
Теперь создайте все шаблоны, которые мы объявили в представлениях:
touch list.html taglist.html detail.html create.html update.html delete.html
Шаблоны списков
Будет list.htmlнаследоваться от base.htmlшаблона, и поэтому вся структура HTML появится в исходном коде:
{% extends 'base.html’%}
{% block body%}
{% for photo in photos%}
{% endfor%}
{% endblock body%}
Мы используем тег шаблона для цикла, который перебирает фотографии и отображает их с помощью строк и столбцов Bootstrap.
Не забудьте создать несколько фотообъектов в админке Django.
Посетите localhost:8000/, чтобы увидеть, как выглядит шаблон.
Шаблон списка
Шаблон taglist.htmlунаследуется от list.htmlтолько что созданного нами:
{% extends 'photoapp/list.html’%}
{% block body%}
Photos with the tag {{tag}}
{{ block.super }}
{% endblock body%}
Мы просто немного модифицируем этот шаблон. Вот почему мы вызываем {{ block.super }}, который содержит весь код внутри блока body list.htmlшаблона.
codeПрежде чем продолжить, создайте пару объектов с тегом.
Перейдите на localhost:8000/tag/code/, где код — это слаг тега.
Тег шаблона списка
Помните, что
'localhost: //8000/tag/
Здесь
Детальный фотошаблон
Давайте отредактируем detail.htmlшаблон, чтобы увидеть наши фотографии в деталях:
{% extends 'base.html’%}
{% block body%}
{{ photo.title }}
Uploaded on: {{photo.created}}
By {{photo.submitter.username}}
{% if user == photo.submitter%}
{% endif%}
More about this photo:
{% for tag in photo.tags.all%}
{% endfor%}
- {{tag.name}}
{{ photo.description }}
{% endblock body%}
Давайте посмотрим, как выглядит шаблон, прежде чем углубляться в функциональность. Подпишитесь на локальный хост: 8000/photo/1.
Фото в деталях
Здесь мы получаем доступ к свойствам фотографии из шаблонов через точечную нотацию. Это потому, что photo.submitter.usernameравно daniel.
Мы реализуем небольшую логику, чтобы отображать ссылки для обновления или удаления фотографии, если пользователь также является отправителем.
Наконец, мы показываем все теги фотографии, повторяющиеся photo.tags.all.
Создайте шаблон фотографии
Следующий шаблон будет включать хрустящую форму, чтобы нам не приходилось отображать формы вручную. Django сделает это за нас:
{% extends 'base.html’%}
{% load crispy_forms_tags%}
{% block body%}
Add photo
{% endblock body%}
Каждый раз, когда мы используем хрустящие формы, нам нужно загружать теги с{% load crispy_forms_tags%}.
Крайне важно включить enctype="multipart/form-data", потому что если мы этого не сделаем, файлы не будут загружены. Вот действительно хороший ответ на последствия его использования в формах.
Каждая форма Django должна включать в себя {% csrf_token%}внутреннюю часть. Вы можете узнать больше об этом теге на странице «Защита от подделки межсайтовых запросов «.
Обратите внимание, как мы просто отображаем форму с помощью {{form|crispy}}. Если вы знаете, что такое каналы в Linux, мы делаем именно это, перенаправляя форму, предоставленную представлением, на crispyфильтр.
Перейдите по URL- адресу добавления фотографии, чтобы проверить, загружена ли фотография.
Загрузка фото
Если все прошло хорошо, мы должны увидеть добавленную фотографию в панели инструментов.
Добавлено фото
Обновление и удаление шаблонов
Давайте закончим приложение для обмена фотографиями, прежде чем перейти к шаблонам аутентификации.
Следующий updateшаблон представляет собой простую форму, в которой пользователь может обновить title, descriptionи tagsфотографии:
{% extends 'base.html’%}
{% load crispy_forms_tags%}
{% block body%}
Edit photo {{photo}}
{% endblock body%}
Мы можем посмотреть, как это выглядит на localhost:8000/photo/1/update.
Обновление фотографии
Мы также хотим дать пользователям возможность удалить фотографию. С помощью следующего шаблона они могут решить, удалять фотографию или нет:
{% extends 'base.html’%}
{% block body%}
You are going to delete: «<i
>{{ photo }}</i
>
«
Are you sure, you want to delete the photo?
<form
action=""
method="post"
class="d-flex flex-column align-items-center justify-content-center"
>
{% csrf_token%}
<a href="{% url 'photo:detail' photo.id %}" class="btn btn-primary"
>Cancel</a
>
This action is irreversible
{% endblock body%}
Страница удаления будет выглядеть так.
Удалить шаблон
Если пользователь решит отменить, он будет перенаправлен на страницу сведений об этой фотографии.
Шаблоны аутентификации пользователя
Цель этого раздела — написать все шаблоны, связанные с аутентификацией. Мы напишем signup.htmlи login.htmlшаблоны.
Как и в приложении для обмена фотографиями, все следующие шаблоны будут расположены в двойной структуре папок: users/templates/users/.
Войдите в приложение пользователей и создайте папки, в которых будут находиться шаблоны:
# Enter to the project root directory
cd... /... /... /
cd users/
mkdir -p templates/users/
Создайте файлы шаблонов регистрации и входа в эту папку:
cd templates/users/
touch signup.html login.html
Ниже приведен код шаблона для signup.htmlшаблона:
{% extends 'base.html’%}
{% load crispy_forms_tags%}
{% block body%}
{% comment%} Already Registered {% endcomment%}
Already Registered?
Login
{% endblock body%}
Мы можем проверить это в браузере по адресу localhost:8000/users/signup.
Страница регистрации
И последнее, но не менее важное: напишите шаблон входа в систему:
{% extends 'base.html’%}
{% load crispy_forms_tags%}
{% block body%}
{% comment%} Already Registered {% endcomment%}
Don’t have an account?
Create account
{% endblock body%}
Страница авторизации
Шаблоны Django позволяют нам сэкономить много времени, повторно используя один и тот же
Идеально! Теперь у вас есть полностью работающее приложение. Попробуйте использовать его, модифицировать или даже расширить его функциональность.
Подводя итоги
Поздравляем! Вы создали полноценный проект с нуля.
Django — наиболее часто используемый
Он имеет множество встроенных функций, которые ускоряют процесс разработки, таких как рендеринг шаблонов на стороне сервера, представления на основе классов и формы моделей.
Django также предлагает несколько сторонних пакетов, которые дают вам возможность использовать чужое приложение. Например, проект работает с формами Django taggit и Django crispy.
В этом уроке мы рассмотрели следующее:
Джанго
Встроенная система аутентификации Django
как управлять медиафайлами в Django
использование Django taggit для классификации контента
реализация форм Django с хрустящими формами
написание шаблонов Django с помощью Bootstrap 5
Лучший способ продолжать учиться и совершенствоваться, применяя полученные знания в новых и сложных проектах. Удачи!