В этом руководстве я рассмотрю простое приложение для заметок, построенное на основе функциональных представлений (FBV), и преобразую их в представления на основе классов (CBV).
Этот пост будет использован в качестве руководства для учебника на YouTube, поэтому я рекомендую посмотреть полный видеоурок и обратиться к исходному коду.
Наши представления на основе функций
Давайте начнем с краткого обзора представлений, которые мы имеем в настоящее время.
Наш файл представлений содержит представления для выполнения основных CRUD-операций по созданию, чтению, обновлению и удалению заметок.
def TaskList(request):
if request.method == 'GET':
tasks = Task.objects.all().order_by('-updated')
context = {'tasks':tasks}
return render(request, 'base/index.html', context)
if request.method == 'POST':
task = Task.objects.create(
body=request.POST.get('body')
)
task.save()
return redirect('tasks')
## ------------------------------------------------------
def TaskDetail(request, pk):
if request.method == 'GET':
task = Task.objects.get(id=pk)
context = {'task':task}
return render(request, 'base/task.html', context)
if request.method == 'POST':
task = Task.objects.get(id=pk)
task.body = request.POST.get('body')
task.save()
return redirect('tasks')
## ------------------------------------------------------
def TaskDelete(request, pk):
task = Task.objects.get(id=pk)
if request.method == 'POST':
task.delete()
return redirect('tasks')
context = {'task':task}
return render(request, 'base/delete.html', context)
Сохранение необработанных представлений на основе классов
Представления на основе классов имеют определенный уровень сложности не потому, что их сложно использовать, а потому, что для них существует уровень абстракции, который затрудняет понимание того, что именно происходит и что нам нужно сделать, чтобы изменить их. Django предоставляет нам ряд встроенных представлений для использования, что способствует быстрой разработке, но до того, как вы узнаете все тонкости и нюансы представлений, это может запутать вас, поскольку под капотом находится много магии.
Поэтому вместо того, чтобы использовать встроенные представления, я буду делать все по-простому и расширять только базовое представление, которое дает нам Django, и писать всю логику с нуля, чтобы вы могли увидеть, чем представления на основе классов отличаются от представлений на основе функций.
Несколько моментов о представлениях на основе классов
Прежде чем мы начнем, я хочу, чтобы вы узнали несколько вещей о представлениях на основе классов.
Расширение базового класса View
Каждое представление на основе классов расширяет базовый класс View
. Поскольку мы не используем никаких других встроенных представлений, убедитесь, что вы импортировали View
и передали «View» каждому классу:
from django.views import View
...
class OurView(View):
Разделение по http-методам
При использовании представлений на основе классов мы разделяем наш код на HTTP-глаголы. Поэтому вместо того, чтобы делать что-то вроде if request.method == 'POST'
, мы просто изменяем метод post
, предоставляемый классом View
, и позволяем этому методу позаботиться обо всем, что происходит при запросе post
. То же самое относится к запросам get
.
Например:
class OurView(View):
def get(self, request):
pass
def post(self, request):
pass
Давайте начнем с нашего первого представления.
Представление TaskList
Давайте закомментируем представление TaskList
и перестроим его с нуля.
Теперь мы перепишем представление как класс и унаследуем от класса View
. Также добавим два метода в этот новый класс (get
& post
) и обязательно передадим self
перед request
в каждом методе.
Когда у нас есть класс и два метода, давайте извлечем логику из нашего представления, основанного на функциях, и добавим ее в новый класс в соответствии с каждым методом http следующим образом:
from django.views import View
....
class TaskList(View):
def get(self, request):
tasks = Task.objects.all().order_by('-updated')
context = {'tasks':tasks}
return render(request, 'base/index.html', context)
def post(self, request):
task = Task.objects.create(
body=request.POST.get('body')
)
task.save()
return redirect('tasks')
Теперь, чтобы использовать это представление, нам нужно сослаться на класс в urls.py и затем использовать метод as_view()
.
path('', views.TaskList.as_view(), name="tasks"),
И вот так мы преобразовали наше первое представление на основе функций в представление на основе классов!
Представление TaskDetail
Теперь сделаем то же самое для TaskDetail
. Опять же, мы закомментируем наше представление, основанное на функциях, и извлечем и разделим всю имеющуюся у нас логику на http-методы.
class TaskDetail(View):
def get(self, request, pk):
task = Task.objects.get(id=pk)
context = {'task':task}
return render(request, 'base/task.html', context)
def post(self, request, pk):
task = Task.objects.get(id=pk)
task.body = request.POST.get('body')
task.save()
return redirect('tasks')
Затем добавьте as_view()
к пути url для вызова этого представления.
path('<str:pk>/', views.TaskDetail.as_view(), name="task"),
ЗадачаУдаление представления
На этом этапе, я уверен, вы начинаете видеть закономерность, поэтому давайте сделаем то же самое, что и раньше, с представлением удаления.
class TaskDelete(View):
def get(self, request, pk):
task = Task.objects.get(id=pk)
context = {'task':task}
return render(request, 'base/delete.html', context)
def post(self, request, pk):
task = Task.objects.get(id=pk)
task.delete()
return redirect('tasks')
path('<str:pk>/delete/', views.TaskDelete.as_view(), name="delete"),
Итак, давайте вспомним, что мы делали.
Для каждого вида мы:
- Изменили
def
наclass
. - Расширили базовый класс
View
. - Разделили логику по методам
http
и добавилиself
перед запросом - Добавлено
as_view()
к каждому представлению вurls.py
.