автор:HelloGitHub-Dream Chaser
Пример кода, задействованный в этой статье, был синхронно обновлен доРепозиторий HelloGitHub-Team
В процессе разработки веб-сайта, хотя некоторые функции представления имеют дело с разными объектами, общая логика их кода одинакова. Например, блог и форум обычно отображают серию списков статей или списков сообщений на главной странице. Для функции просмотра, которая обрабатывает домашнюю страницу, хотя одним из обрабатываемых объектов является статья, а другим — пост, процесс его обработки очень похож: сначала список статей или постов извлекается из базы данных, а затем данные передаются в шаблон и отображают шаблон. Поэтому django извлек те же самые логические коды и написал ряд функций общего представления, а именно представление на основе общего класса.
Использование представлений классов является рекомендуемой практикой django.После того, как вы ознакомитесь с использованием представлений классов, вы сможете сократить повторяющийся код функций представления и сэкономить время разработки. Далее давайте изменим функцию представления в приложении блога на общее представление на основе классов.
ListView
В нашем блог-приложении есть несколько функций просмотра, которые получают список статей (Post) из базы данных:
blog/views.py
def index(request):
# ...
def archive(request, year, month):
# ...
def category(request, pk):
# ...
def tag(request, pk):
# ...
Все эти функции просмотра получают список статей (Post) из базы данных, разница лишь в том, что список получаемых статей может быть другим. Напримерindex
Получить список всех статей,category
Получить список статей в категории.
Перепишите функцию просмотра индекса в представление класса.
Для такого вида представления, которое получает данные списка моделей (например, список постов здесь) из базы данных, Django предоставляет специальныйListView
вид класса. Давайте посмотрим на примерListView
способ использования. Мы сначала ставимindex
Функция просмотра преобразована в функцию просмотра класса.
blog/views.py
from django.views.generic import ListView
class IndexView(ListView):
model = Post
template_name = 'blog/index.html'
context_object_name = 'post_list'
要写一个类视图,首先需要继承 django 提供的某个类视图。至于继承哪个类视图,需要根据你的视图功能而定。 как здесьIndexView
Функция состоит в том, чтобы получить список статей (Post) из базы данных,ListView
Это получение определенных данных списка моделей из базы данных, поэтомуIndexView
наследоватьListView
.
Затем через некоторые атрибуты указать, что должна делать эта функция представления Здесь мы указываем три атрибута:
- модель: указать модель как
Post
, сообщая django, что модель, которую я хочу получить,Post
. - template_name: задает шаблон для рендеринга этого представления.
- context_object_name: указывает имя переменной для сохранения полученных данных списка моделей, эта переменная будет передана в шаблон.
Если это все еще немного сложно понять, вы можете также объединить код представления класса сindex
Сравните код функции просмотра:
blog/views.py
def index(request):
post_list = Post.objects.all()
return render(request, 'blog/index.html', context={'post_list': post_list})
index
Сначала функция просмотра проходитPost.objects.all()
Получите данные списка статей (Post) из базы данных и сохраните их вpost_list
в переменной. И в классе посмотреть на этот процессListView
Уже сделал это за нас. мы просто говоримListView
Модель, полученная из базы данных,Post
, вместоComment
или любую другую модель, т.е. указаниеmodel = Post
. Сохраните полученный список данных модели вpost_list
, т.е. указатьcontext_object_name = 'post_list'
. Затем визуализируйте файл шаблона blog/index.html,index
Использовать функцию просмотраrender
функция. Но этот процессListView
Это уже сделано за нас, нам просто нужно указать, какой шаблон отображать.
Следующим шагом является преобразование представления класса в представление функции. Зачем вам нужно преобразовать представление класса в представление функции?
Давайте посмотрим на конфигурацию URL для блога:
blog/urls.py
app_name = 'blog'
urlpatterns = [
path('', views.index, name='index'),
...
]
Как упоминалось ранее, каждый URL-адрес соответствует функции представления, поэтому, когда пользователь посещает URL-адрес, Django знает, какую функцию представления вызывать для обработки запроса. Шаблоны URL-адресов настраиваются в Django черезurl
Функция привязывает URL к функции просмотра. Напримерpath('', views.index, name='index')
, первый параметр которого — это шаблон URL, а второй — функция просмотра.index
. правильноurl
Для функций значение, переданное в качестве второго параметра, должно быть функцией. а такжеIndexView
является классом и не может быть заменен напрямуюindex
функция. К счастью, преобразовать представление класса в представление функции очень просто, просто вызовите функцию представления класса.as_view()
метод (что касаетсяas_view
Как именно метод преобразует класс в функцию, в настоящее время не нужно беспокоиться, его просто нужно вызвать при настройке шаблона URL.as_view
метод подойдет. Для конкретной реализации мы разработаем колонку для анализа исходного кода представления классов в будущем, и тогда мы сможем увидеть магию, используемую django).
Теперь введите конфигурацию URLindex
заменить представление представлением классаIndexView
:
blog/urls.py
app_name = 'blog'
urlpatterns = [
path('', views.IndexView.as_view(), name='index'),
...
]
Посетите домашнюю страницу, вы можете видеть, что на домашней странице по-прежнему отображается список всех статей, и используйте функцию просмотра.index
Эффект точно такой же.
Перепишите функцию представления категории в представление класса
category
Функцией просмотра также является получение данных списка статей из базы данных, но ее иindex
Отличие функции просмотра в том, что она получает все статьи определенной категории. следовательноcategory
В функции просмотра есть еще один шаг, то есть сначала вам нужно получить категорию из базы данных на основе идентификатора категории, полученного из URL-адреса, а затем использоватьfilter
Функция отфильтровывает все статьи в этой категории. Давайте посмотрим, как должно быть написано представление класса в этом случае:
blog/views.py
class CategoryView(ListView):
model = Post
template_name = 'blog/index.html'
context_object_name = 'post_list'
def get_queryset(self):
cate = get_object_or_404(Category, pk=self.kwargs.get('pk'))
return super(CategoryView, self).get_queryset().filter(category=cate)
а такжеIndexView
Разница в том, что мы переопределяем родительский классget_queryset
метод. Этот метод по умолчанию получает все данные списка указанной модели. Чтобы получить данные списка статей в указанной категории, мы переопределяем этот метод и меняем его поведение по умолчанию.
Во-первых, получить категорию на основе идентификатора категории (также известного как pk), полученного из URL-адреса, который аналогиченcategory
Процесс в функции просмотра такой же. Обратите внимание, однако, что в представлении класса значение параметра пути, полученное из URL-адреса, сохраняется в экземпляреkwargs
В атрибуте (который является словарем) значения параметров, не являющихся путями, хранятся в экземпляреargs
свойства (которые представляют собой список). Итак, мы сделалиself.kwargs.get('pk')
чтобы получить значение идентификатора категории, полученное из URL-адреса. Затем мы вызываем родительский классget_queryset
Метод получает список всех статей, а затем вызывает возвращенный результат.filter
метод для фильтрации всех статей в этой категории и возврата.
Кроме того, мы можем видетьCategoryView
значения свойств, указанные в классе иIndexView
точно такие же, поэтому, если вы хотите сохранить код дальше, вы даже можете напрямую наследоватьIndexView
:
class CategoryView(IndexView):
def get_queryset(self):
cate = get_object_or_404(Category, pk=self.kwargs.get('pk'))
return super(CategoryView, self).get_queryset().filter(category=cate)
Затем в конфигурации URL поместитеcategory
заменить представление представлением классаCategoryView
:
blog/urls.py
app_name = 'blog'
urlpatterns = [
...
path('categories/<int:pk>/', views.CategoryView.as_view(), name='category'),
]
Посетите одну из следующих страниц категорий, вы увидите, что список всех статей в категории по-прежнему отображается, и используйте функцию просмотра.category
Эффект точно такой же.
Перепишите функции представления архива и тегов в представления класса.
Здесь не о чем говорить, применяйте то, чему вы научились, и оставьте задачу вам.
DetailView
Помимо получения данных списка моделей из базы данных, также общим требованием является получение данных одной записи модели из базы данных. Например, для просмотра сведений о статье необходимо получить запись этой статьи из базы данных, а затем отобразить шаблон. Для этого типа требований django предоставляетDetailView
вид класса. Далее мы будемdetail
Функция представления преобразуется в эквивалентное представление классаPostDetailView
, код показан ниже:
blog/views.py
from django.views.generic import ListView, DetailView
# 记得在顶部导入 DetailView
class PostDetailView(DetailView):
# 这些属性的含义和 ListView 是一样的
model = Post
template_name = 'blog/detail.html'
context_object_name = 'post'
def get(self, request, *args, **kwargs):
# 覆写 get 方法的目的是因为每当文章被访问一次,就得将文章阅读量 +1
# get 方法返回的是一个 HttpResponse 实例
# 之所以需要先调用父类的 get 方法,是因为只有当 get 方法被调用后,
# 才有 self.object 属性,其值为 Post 模型实例,即被访问的文章 post
response = super(PostDetailView, self).get(request, *args, **kwargs)
# 将文章阅读量 +1
# 注意 self.object 的值就是被访问的文章 post
self.object.increase_views()
# 视图必须返回一个 HttpResponse 对象
return response
def get_object(self, queryset=None):
# 覆写 get_object 方法的目的是因为需要对 post 的 body 值进行渲染
post = super().get_object(queryset=None)
md = markdown.Markdown(extensions=[
'markdown.extensions.extra',
'markdown.extensions.codehilite',
# 记得在顶部引入 TocExtension 和 slugify
TocExtension(slugify=slugify),
])
post.body = md.convert(post.body)
m = re.search(r'<div class="toc">\s*<ul>(.*)</ul>\s*</div>', md.toc, re.S)
post.toc = m.group(1) if m is not None else ''
return post
PostDetailView
Немного сложнее, в основном эквивалентноdetail
Функция просмотра по своей сути сложнее, давайте сравним ее пошагово.detail
Объясняется код в функции просмотра.
Сначала мыPostDetailView
В классе указываются значения некоторых свойств, смысл этих свойств иListView
То же самое в , и здесь повторяться не буду.
Затем мы перезаписываемget
метод. Это соответствуетdetail
Часть кода в функции просмотра, добавляющая 1 к чтению поста. На самом деле можно просто поставитьget
вызов метода какdetail
Просмотр вызова функции.
Потом мы воспроизвелиget_object
метод. Это соответствуетdetail
В функции просмотра статья получается по id статьи (то есть pk), а затем выполняется кодовая часть парсинга Markdown над post.body статьи.
Вас может смутить такое количество методов, для простоты понимания можно просто поставитьget
метод какdetail
функции просмотра, как и для других, таких какget_object
,get_context_data
являются вспомогательными методами, которые заканчиваются вget
вызываются методы, причина, по которой вы не видите, что они вызываются здесь, заключается в том, что они неявноsuper(PostDetailView, self).get(request, *args, **kwargs)
родительский классget
вызов метода. Окончательный HTTP-ответ, передаваемый браузеру,get
метод возвращенHttpResponse
объект.
Все еще не можешь понять? Я могу сказать так много, не прибегая к исходному коду. Если вы хотите освоить и использовать class view гибко, вы должны внимательно прочитать исходный код class view.Я тоже долго выгрыз исходный код.В будущем я разработаю специальный анализ исходного кода представления класса, и тогда у вас будет более глубокое понимание представления класса. Кроме того, вот объяснение представления класса в официальном документе django, хотя я думаю, что эта часть документа не очень ясна в отношении представления класса, но она также заслуживает ссылки.Обзор представлений на основе классов.
Классовое представление деталей статьи также было написано, аналогично нужно настроить его в urls.py, чтобы преобразовать исходное функциональное представление.detail
Перейдите в режим просмотра классов, я думаю, вы уже должны знать, как это сделать.
После настройки представления страницы сведений посетите сведения о статье, и вы увидите, что результат, возвращаемый страницей, точно такой же, как и представление функции.На этом этапе представление класса было преобразовано. Поскольку представление класса и представление функции полностью эквивалентны, а представление класса имеет много преимуществ, таких как повторное использование кода, поэтому, как только представление будет задействовано в будущем, мы будем использовать представление класса для его реализации.
«Объяснение серии проектов с открытым исходным кодом»——Пусть больше не боятся люди, интересующиеся проектами с открытым исходным кодом, и пусть инициаторы проектов с открытым исходным кодом больше не остаются в одиночестве. Следите за нашими статьями, и вы откроете для себя радости программирования, насколько легко им пользоваться, и узнаете, как легко участвовать в проектах с открытым исходным кодом. Добро пожаловать, чтобы оставить сообщение, чтобы связаться с нами, присоединиться к нам, позволить большему количеству людей влюбиться в открытый исходный код и внести свой вклад в открытый исходный код~