Часть III
Это заключительная часть серии из трех частей. В первой части мы рассмотрели концепции представлений на основе функций и представлений на основе классов и некоторые различия между этими концепциями, во второй части мы создали приложение, используя представление на основе функций, а в этой заключительной части мы создадим то же приложение с теми же функциями, но на этот раз с использованием подхода представлений на основе классов.
Необходимым условием для получения максимальной пользы от этой статьи будет рабочее понимание структуры шаблона «Модель-Виды» Django, как начать проект и приложение, и, наконец, базовое понимание представлений, основанных на функциях Django.
ПРЕДСТАВЛЕНИЯ НА ОСНОВЕ КЛАССОВ
Представления на основе классов — это просто представления Django, написанные как классы python, они обеспечивают объектно-ориентированный способ представления кода.
Одним из основных преимуществ представлений на основе классов является использование наследования; вы можете наследовать другой класс, и он может быть изменен для различных целей.
Ниже перечислены некоторые преимущества, которые дает использование представлений на основе классов.
1. Наследование; многократно используемые и DRY (не повторяйтесь) коды.
2. Устранение избыточных кодов.
3. Разделяйте каждый код по методу POST или GET.
Представления, основанные на классах, действительно мощные и замечательные, но за счет простоты.
Даже такая мелочь, как пропуск прямой косой черты в вашем urls.py
может привести к ошибке, представления на основе классов заставляют вас делать все правильно.
Класс представления
Можно сказать, что это великий папа всех остальных представлений, ListView
, UpdateView
, DetailView
… в какой-то момент все они наследуются от этого представления.
Класс представления TaskList
class TaskList(LoginRequiredMixin, ListView):
model = Task
template_name = '../templates/tasklist.html'
context_object_name = 'tasks'
# login_url = 'login' An alternative to LOGIN_URL = 'login' in settings.py
def get_context_data(self):
context = super(TaskList, self).get_context_data()
context['tasks'] = context['tasks'].filter(user=self.request.user)
context['count'] = context['tasks'].filter(completed=False).count()
search_input = self.request.GET.get('search-area') or ''
if search_input:
context['tasks'] = context['tasks'].filter(title__icontains=search_input)
context['search_input'] = search_input
return context
Этот класс наследуется от LoginRequiredMixin
и Listview
.
LoginRequiredMixin
нуждается в url входа для отправки не аутентифицированных пользователей, вы можете достичь этого двумя способами
- добавить
login_url = '/login/'
в каждый класс, где требуетсяLoginRequiredMixin
. - добавить стандартный
LOGIN_URL = 'login'
вsettings.py
, от которого наследуется каждый login url
Разница между login_url
и redirect_field_name
Имеет дело с url, на который вы хотите перевести пользователя, если определенное условие выполнено или нет.
Имеет дело с полем, для которого установлен параметр по умолчанию =next
.
Как и в названии, для просмотра шаблона этой функции представления пользователь должен быть зарегистрированным пользователем.
Большинство представлений на основе классов (если не все) должны иметь атрибут model.
имя шаблона по умолчанию для этого представления task_list.html
мы переопределим это, создав каталог для всех шаблонов и создадим файл шаблона tasklist.html
имя контекста по умолчанию для объектов этого представления object_list
мы также переопределим его и дадим нашему объекту контекста имя tasks
get_context_data
аналогично контекстному словарю представлений на основе функций context = {}
.
В представлении на основе классов у нас есть два способа передачи данных в контекст.
get_context_data
Мы используем функцию get_context_data
, когда хотим изменить объекты в нашем шаблоне (добавить дополнительные элементы в наши шаблоны).
Мы фильтруем задачу по запрошенному пользователю, а также фильтруем задачу запрошенного пользователя по статусу завершения completed=False
, считаем эту отфильтрованную приписку и сохраняем объект.
Функциональность поиска
Мы добавляем функцию поиска к нашей задаче, как мы это делали в нашем представлении, основанном на функциях, поэтому метод запроса из нашей формы поиска будет содержать либо поиск фактического слова, либо пустой поиск, мы хотим, чтобы для обоих условий выполнялось одно и то же действие;
Итак, если поиск (пустой или нет) выполнен, отфильтруйте контекст задачи, но на этот раз по title
и включите search_input
в контекстный словарь
title__icontains=search_input
, если пользователь выполняет поиск, мы хотим отфильтровать поиск на этот раз по названию.
icontains
V contains
Мы используем контекстный словарь для объектов, которые мы собираемся использовать с нашим шаблонизатором.
Функция представления TaskDetail
class TaskDetail(LoginRequiredMixin, DetailView):
model = Task
template_name = '../templates/taskdetail.html'
context_object_name = 'task'
Наследует от DetailView
, такие подходы, как представления на основе классов, помогают уменьшить количество DRY-кодов, снова мы определяем атрибут модели, шаблон и имя для наших контекстных объектов.
Эта функция представления принимает идентификатор PrimaryKey
, мы не включаем его при создании нашей функции, представление Django на основе классов делает это за нас, мы просто передаем его в наш файл urls.py
.
Функция представления TaskEdit
class TaskEdit(LoginRequiredMixin, UpdateView):
model = Task
template_name = '../templates/taskedit.html'
fields = ['title', 'description', 'completed']
success_url = reverse_lazy('tasklist')
Унаследованная от UpdateView
, эта функция представления имеет атрибут fields, а также возвращает экземпляр отправленной формы.
поля, как следует из названия, являются полями HTML, которые будут отображаться во фронтенде нашего приложения, нам не нужно создавать экземпляр этой формы, опять же Django’s class based view обрабатывает это за нас, какая красота!
После успешного создания формы, куда нам перенаправить пользователя? На этот раз мы используем основанное на классах представление Django reverse_lazy
, чтобы перенаправить пользователя обратно на урлы, с которых он пришел.
Функция представления TaskDelete
class TaskDelete(LoginRequiredMixin, DeleteView):
model = Task
template_name = '../templates/taskdelete.html'
context_object_name = 'task'
success_url = reverse_lazy('tasklist')
Эта функция похожа на TaskEdit
с некоторыми особенностями; не имеет атрибута fields и не возвращает экземпляр какой-либо формы, принимает PrimaryKey
удаляемой задачи и под капотом выполняет функцию delete()
, которую мы не видим.
Функция просмотра TaskCreate
class TaskCreate(LoginRequiredMixin, CreateView):
model = Task
template_name = '../templates/taskcreate.html'
fields = ['title', 'description']
success_url = reverse_lazy('tasklist')
def form_valid(self, form):
form.instance.user = self.request.user
return super(TaskCreate, self).form_valid(form)
Очень похожа на TaskEdit
, фактически они оба имеют одного родителя views.generic.edit
, мы добавляем твик к этому классу, изменяя форму; мы назначаем каждого пользователя на его созданную задачу.
Функция super может быть использована для получения доступа к унаследованным методам — от родительского или дочернего класса — которые были перезаписаны в объекте класса, все это большая грамматика, что означает, что функция super()
позволяет функции, в которой она используется, использовать методы вышестоящего класса.
Функция представления CustomLogin
class CustomLogin(LoginView):
redirect_authenticated_user = True
template_name = '../templates/login.html'
form_class = CleanForm
# next_page = 'tasklist' Alternative to the get_success_url
def get_success_url(self):
return reverse_lazy('tasklist')
Наследуется от LoginView
и имеет AunthenticationForm
как form_class
по умолчанию.
Мы хотим запретить уже аутентифицированным пользователям повторно входить в систему, для этого мы установим атрибут redirected_authenticated_user
этого класса в True, чтобы пользователь, прошедший аутентификацию, не мог быть аутентифицирован снова.
Перед входом пользователя в систему мы выполняем операцию очистки, подробнее о том, как мы это сделали, мы расскажем ниже.
next_page =
определяет, куда должен перейти аутентифицированный пользователь, этот атрибут и get_success_url
выполняют одну и ту же функцию.
Функция регистрации просмотра
class Register(FormView):
form_class = UserCreationForm
success_url = reverse_lazy('logout')
template_name = '../templates/register.html'
# Function for a valid form
def form_valid(self, form):
user = form.save(commit=False)
user.username = user.username.lower()
user = form.save()
if user is not None:
login(self.request, user)
return redirect('logout')
return super(Register, self).form_valid(form)
# Function to redirect authenticated user
def get(self, request):
if self.request.user.is_authenticated:
return redirect('tasklist')
return super(Register, self).get(request)
Наследуя модель FromView
, модель также имеет UserCreationForm
в качестве класса формы для создания пользователей в Django.
Мы сделаем несколько изменений в нашей UserCreationForm
, если форма действительна, мы сделаем ложное сохранение, чтобы очистить наши данные, убедиться, что они не чувствительны к регистру, сохранить пользователя после, вернуть этого созданного пользователя на страницу выхода из системы после того, как он был создан.
Мы хотим иметь возможность перенаправлять аутентифицированных пользователей, хотя этот класс представления не имеет такого атрибута, поэтому мы создаем его, используя get(self, request)
перенаправляем аутентифицированного пользователя обратно на страницу tasklist
, если он пытается зарегистрироваться после аутентификации, и, наконец, возвращаем класс с помощью суперфункции, которая просто продолжает все, что должна была сделать эта функция.
CleanForm in forms.py
from django.contrib.auth.forms import AuthenticationForm
class CleanForm(AuthenticationForm):
def clean_username(self):
return self.cleaned_data['username'].lower()
Поскольку мы знаем, что наш LoginView
имеет класс from под названием AuthenticationForm
, мы хотим немного подправить эту форму, очистив имя пользователя так же, как мы это делали с нашими представлениями на основе функций.
Разное
Self
Миксины
Это просто классы, которые содержат методы, используемые другими классами. Мы используем миксины, когда хотим добавить определенную функцию, которая будет доступна в нескольких дочерних объектах, они должны использоваться для решения одной конкретной задачи, в представлениях на основе функций для этого есть decorators
.
Разница между ModelForm
, FormView
и CreateView
В Django ModelForm
используется для прямого преобразования модели в Django форму.
Представление, которое может быть использовано для различных целей и не ограничивается созданием объектов, не обязательно наследуется от вашей пользовательской модели, оно обычно используется для отображения и проверки формы (при регистрации в представлениях, основанных на классах, где я в основном использую его). Его поля не обязательно должны быть созданы в models.py
.
В основном используется, когда вы хотите создавать объекты (не ограничивается только этим), использует встроенную ModelForm
.
Ниже приведен github repo полного проекта.
kanyi-v-1.1
Ниже приведена ссылка на то, где этот проект был развернут.
Kanyi-v-1.1