В этой лекции мы начнем разработку функции домашней страницы, В процессе разработки вы изучите использование класса общего представления, пагинатора объектов подкачки и внешнего ключа ForeignKey в Django.
Демонстрация эффекта
Общая функция
Каждый может пройтиДемонстрационный адрес веб-сайтаПосмотрите на производительность главной страницы. Что касается нашей домашней страницы, она относительно проста и щедра, что делает ее понятной с первого взгляда. Цель моего дизайна — позволить всем сосредоточиться на изучении django вместо того, чтобы уделять слишком много внимания причудливым эффектам страницы.
Разбираем домашнюю страницу на 4 модуля малого бизнеса для разработки, а именно: отображение списка, функция пейджинга, функция поиска и функция классификации. Далее мы разработаем и объясним эти четыре функциональных модуля соответственно.
идеи развития
Основная идея разработки функции: сначала создать новое приложение, затем проанализировать бизнес, связанный с функцией, чтобы проанализировать необходимые поля базы данных, затем написать модель, а затем этап отображения, настроить функцию просмотра. через маршрутизацию URL, чтобы преобразовать данные в дисплей модели.
ок, создаем приложение через команду с именем video. После выполнения django создаст для нас новую папку с видео.
python3 manage.py startapp video
Под данное приложение разработаны следующие функциональные модули (видео).
модель
Здесь нам нужно построить две модели, а именно классификацию и видео. Они имеют отношение «многие к одному» (одна категория соответствует нескольким видео, а одно видео соответствует одной категории).
Сначала напишите таблицу классификации, в разделе model.py мы вводим следующий код. Поля имеют заголовок (название категории) и статус (включен)
class Classification(models.Model):
list_display = ("title",)
title = models.CharField(max_length=100,blank=True, null=True)
status = models.BooleanField(default=True)
class Meta:
db_table = "v_classification"
Поле Описание
- Название категории. Тип данных — CharField, максимальная длина — max_length=100, допускается пустое значение null=True.
- статус включен. Тип данных — BooleanField, значение по умолчанию — default=True.
- db_table имя таблицы
Затем пишем модель Video.В соответствии с бизнесом сайта настраиваем такие поля, как title (заголовок), desc (описание), classification (классификация), file (видеофайл), cover (обложка) и status (статус публикации). . Где классификацией является поле внешнего ключа ForeignKey, указывающее, что одна категория соответствует нескольким видео, а одно видео соответствует одной категории (многие к одному).
class Video(models.Model):
STATUS_CHOICES = (
('0', '发布中'),
('1', '未发布'),
)
title = models.CharField(max_length=100,blank=True, null=True)
desc = models.CharField(max_length=255,blank=True, null=True)
classification = models.ForeignKey(Classification, on_delete=models.CASCADE, null=True)
file = models.FileField(max_length=255)
cover = models.ImageField(upload_to='cover/',blank=True, null=True)
status = models.CharField(max_length=1 ,choices=STATUS_CHOICES, blank=True, null=True)
create_time = models.DateTimeField(auto_now_add=True, blank=True, max_length=20)
Поле Описание
- название Название видео. Тип данных — charField, максимальная длина — max_length=100, допустимо значение null null=True
- desc описание видео. Тип данных — charField, максимальная длина — max_length=255, допускается null=True.
- адрес файла видеофайла. Тип данных — fileField. В нем хранится адрес видеофайла. Мы подробно объясним загрузку видео в управлении видео позже.
- обложка Обложка видео. Тип данных — ImageField. Каталог хранения: upload_to='cover/', что позволяет пустое значение null=True
- статус Статус видео. является состоянием выбора и использует выбор для установки кортежа с множественным выбором.
- create_time Время создания. Тип данных — DateTimeField. Установить время автоматической генерации auto_now_add=True
ForeignKey указывает на отношение «один ко многим». Например, связь между нашими видео и категориями здесь: видео может соответствовать только одной категории, и в одной категории может быть несколько видео. Для получения дополнительной информации о ForeinkKey см.Официальное введение ForeignKey
отображение списка
Для доступа к домашней странице необходимо сначала настроить маршрутизацию. Создайте файл urls.py под видео и напишите следующий код
from django.urls import path
from . import views
app_name = 'video'
urlpatterns = [
path('index', views.IndexView.as_view(), name='index'),
]
Оператор пути представляет часть информации о маршрутизации. Таким образом, мы можем ввести 127.0.0.1:8000/video/index в браузере, чтобы получить доступ к домашней странице.
Отображение данных списка очень просто.Для его отображения мы используем встроенный класс шаблона представления ListView в django.Сначала мы пишем класс IndexView в view.py и используем его для отображения данных списка. Введите следующий код
class IndexView(generic.ListView):
model = Video
template_name = 'video/index.html'
context_object_name = 'video_list'
Здесь мы используем класс общего представления ListView, предоставленный django. ListView очень прост в использовании. Нам нужно всего лишь настроить несколько строк кода для отображения данных в базе данных во внешнем интерфейсе. Например, в приведенном выше коде мы настраиваем
- model = Video, действующий на модели Video
- template_name = 'video/index.html' , который указывает ListView использовать созданный нами файл шаблона.
- context_object_name = 'video_list' , имя переменной контекста, сообщает ListView, что в файле внешнего шаблона это имя переменной может использоваться для отображения данных.
После этого мы создаем каталог видео в папке шаблонов для хранения файлов шаблонов, связанных с видео.Сначала мы создаем файл домашней страницы index.html. И отображать только что полученные данные.
<div class="ui grid">
{% for item in video_list %}
<div class="four wide column">
<div class="ui card">
<a class="image">
{% thumbnail item.cover "300x200" crop="center" as im %}
<img class="ui image" src="{{ im.url }}">
{% empty %}
{% endthumbnail %}
<i class="large play icon v-play-icon"></i>
</a>
<div class="content">
<a class="header">{{ item.title }}</a>
<div class="meta">
<span class="date">发布于{{ item.create_time|time_since}}</span>
</div>
<div class="description">
{{ item.view_count}}次观看
</div>
</div>
</div>
</div>
{% empty %}
<h3>暂无数据</h3>
{% endfor %}
</div>
Визуализируйте video_list во внешнем интерфейсе через цикл for. Здесь мы используем джанговстроенные теги, например, для инструкции, пустой инструкции. Это очень распространенные операторы в django. Мы будем часто сталкиваться с ним в последующих уроках.
Кроме того, тег thumbnail используется для отображения изображения,thumbnailЭто очень часто используемая библиотека Python, которая часто используется для отображения изображений.
Результаты отображения следующие
Функция классификации
Прежде чем писать функцию классификации, давайте изучим функцию обратного вызова get_context_data() Это функция в классе представления ListView В функцию get_context_data() вы можете передать некоторыедополнительный контентк шаблону. Таким образом, мы можем использовать эту функцию для передачи категориальных данных.
Чтобы использовать его, это легко.
Просто добавьте реализацию get_context_data() в класс IndexView.
class IndexView(generic.ListView):
model = Video
template_name = 'video/index.html'
context_object_name = 'video_list'
def get_context_data(self, *, object_list=None, **kwargs):
context = super(IndexView, self).get_context_data(**kwargs)
classification_list = Classification.objects.filter(status=True).values()
context['classification_list'] = classification_list
return context
В приведенном выше коде мы фильтруем данные классификации из базы данных с помощью Classification.objects.filter(status=True).values(), затем назначаем их классификационному_списку и, наконец, помещаем в контекстный словарь.
Во внешнем шаблоне (templates/video/index.html) вы можете получить данные черезclassification_list. добавить код
<div class="classification">
<a class="ui red label" href="">全部</a>
{% for item in classification_list %}
<a class="ui label" href="">{{ item.title }}</a>
{% endfor %}
</div>
Эффект отображения следующий
Конечно, теперь достигается только эффект отображения категории, нам все еще нужно продолжать добиваться эффекта щелчка, то есть нажимать на разные категории для отображения разных списков видео.
Сначала мы добавляем ссылки href к каждой кнопке категории
<div class="classification">
<a class="ui red label" href="{% url 'home' %}">全部</a>
{% for item in classification_list %}
<a class="ui label" href="?c={{ item.id }}">{{ item.title }}</a>
{% endfor %}
</div>
Добавляя ?c={{item.id}} Здесь c используется для представления идентификатора категории. После нажатия он будет передан классу представления. В классе представления мы используем функцию get_queryset() для получения данных. Назначьте c для c через self.request.GET.get("c", None), чтобы определить, является ли c None, если это None, ответить всем, если есть значение, передать get_object_or_404(Classification, pk=self. c) сначала получите текущий класс, а затем classification.video_set получит данные внешнего ключа.
def get_queryset(self):
self.c = self.request.GET.get("c", None)
if self.c:
classification = get_object_or_404(Classification, pk=self.c)
return classification.video_set.all().order_by('-create_time')
else:
return Video.objects.filter(status=0).order_by('-create_time')
Для получения дополнительной информации о том, как использовать ForeignKey, см.здесь
Функция пейджинга
В Django есть готовые решения для пагинации, и мы, разработчики, многое сохраняем. Если это простая разбивка на страницы, вам нужно только настроить paginate_by для ее достижения.
class IndexView(generic.ListView):
model = Video
template_name = 'video/index.html'
context_object_name = 'video_list'
paginate_by = 12
c = None
- paint_by = 12 отображает 12 элементов на странице
Таким образом, данные подкачки каждой страницы могут отображаться правильно.Теперь давайте улучшим панель номеров страниц внизу.
Список номеров страниц требует, чтобы класс представления и шаблон были завершены вместе, давайте сначала напишем класс представления. Мы уже писали get_context_data ранее, основная функция этой функции — передать шаблону дополнительные данные. Здесь мы используем get_context_data для передачи данных номера страницы.
Сначала мы определяем служебную функцию с именем get_page_list. В корневом каталоге проекта создайте новый файл helpers.py, который используется в качестве глобального класса инструментов для хранения различных функций инструментов. Поместите get_page_list в helpers.py. Эта функция используется для создания списка номеров страниц, и ее можно использовать не только здесь, но и в других местах в будущем.
def get_page_list(paginator, page):
page_list = []
if paginator.num_pages > 10:
if page.number <= 5:
start_page = 1
elif page.number > paginator.num_pages - 5:
start_page = paginator.num_pages - 9
else:
start_page = page.number - 5
for i in range(start_page, start_page + 10):
page_list.append(i)
else:
for i in range(1, paginator.num_pages + 1):
page_list.append(i)
return page_list
Логика пейджинга:
if 页数>=10:
当前页<=5时,起始页为1
当前页>(总页数-5)时,起始页为(总页数-9)
其他情况 起始页为(当前页-5)
Пример:
假设一共16页
情况1: 当前页==5 则页码列表为[1,2,3,4,5,6,7,8,9,10]
情况2: 当前页==8 则页码列表为[3,4,5,6,7,8,9,10,11,12]
情况3: 当前页==15 则页码列表为[7,8,9,10,11,12,13,14,15,16]
Конечно, когда вы увидите эту логику, она будет немного запутанной, рекомендуется прочитать код и протестировать его несколько раз.
Когда мы получаем список номеров страниц, мы продолжаем переписывать функцию get_context_data(). Добавьте полученный classification_list в контекстный словарь.
def get_context_data(self, *, object_list=None, **kwargs):
context = super(IndexView, self).get_context_data(**kwargs)
paginator = context.get('paginator')
page = context.get('page_obj')
page_list = get_page_list(paginator, page)
classification_list = Classification.objects.filter(status=True).values()
context['c'] = self.c
context['classification_list'] = classification_list
context['page_list'] = page_list
return context
Возможно, вы не знакомы с двумя строками кода paginator = context.get('paginator') page = context.get('page_obj'), нам нужно только знать, что context.get('page_obj') возвращает номер текущей страницы , context.get('paginator') возвращает объект подкачки, чего достаточно. Для получения более подробной информации см.официальный.
Когда данные передаются в шаблон, шаблон отвечает за их отображение.
Поскольку функция подкачки используется чаще, ее нужно вынести и упаковать в отдельный файл.Мы создаем новый файл template/base/page_nav.html. Затем в index.html включаем файл.
{% include "base/page_nav.html" %}
Откройте page_nav.html и напишите код
{% if is_paginated %}
<div class="video-page">
<div class="ui circular labels">
{% if page_obj.has_previous %}
<a class="ui circular label" href="?page={{ page_obj.previous_page_number }}{% if c %}&c={{c}}{% endif %}{% if q %}&q={{q}}{% endif %}"><</a>
{% endif %}
{% for i in page_list %}
{% if page_obj.number == i %}
<a class="ui red circular label">{{ i }}</a>
{% else %}
<a class="ui circular label" href="?page={{ i }}{% if c %}&c={{c}}{% endif %}{% if q %}&q={{q}}{% endif %}">{{ i }}</a>
{% endif %}
{% endfor %}
{% if page_obj.has_next %}
<a class="ui circular label" href="?page={{ page_obj.next_page_number }}{% if c %}&c={{c}}{% endif %}{% if q %}&q={{q}}{% endif %}">></a>
{% endif %}
</div>
</div>
{% endif %}
В приведенном выше коде мы использовали несколько атрибутов объекта page_obj: has_previous, previous_page_number, next_page_number. С помощью этих свойств можно добиться сложных эффектов отображения номеров страниц. Среди них мы также добавили этот href
{% if c %}&c={{c}}
Идентификатор, представляющий категорию.
функция поиска
Для реализации поиска нам понадобится окно поиска
Поскольку окно поиска требуется на многих страницах, мы пишем код в файле templates/base/header.html.
<div class="ui small icon input v-video-search">
<input class="prompt" value="{{ q }}" type="text" placeholder="搜索视频" id="v-search">
<i id="search" class="search icon" style="cursor:pointer;"></i>
</div>
Код для нажатия поиска или ввода написан в static/js/header.js.
Также нам необходимо настроить маршрутизацию и добавить строку для поиска маршрута.
app_name = 'video'
urlpatterns = [
path('index', views.IndexView.as_view(), name='index'),
path('search/', views.SearchListView.as_view(), name='search'),
]
Класс представления, на который указывает маршрут поиска, — SearchListView.
Теперь давайте напишем код для SearchListView
class SearchListView(generic.ListView):
model = Video
template_name = 'video/search.html'
context_object_name = 'video_list'
paginate_by = 8
q = ''
def get_queryset(self):
self.q = self.request.GET.get("q","")
return Video.objects.filter(title__contains=self.q).filter(status=0)
def get_context_data(self, *, object_list=None, **kwargs):
context = super(SearchListView, self).get_context_data(**kwargs)
paginator = context.get('paginator')
page = context.get('page_obj')
page_list = get_page_list(paginator, page)
context['page_list'] = page_list
context['q'] = self.q
return context
Код ключа: Video.objects.filter(title__contains=self.q).filter(status=0) title__contains — это значение включения, которое означает, что заголовок запроса содержит записи q. Используйте фильтр, чтобы отфильтровать данные. Здесь написано два уровня фильтрации, первый слой фильтрует ключевые слова для поиска, а второй слой фильтрует видео, которые были выпущены по статусу.
Кроме того, здесь также используется get_context_data для хранения дополнительных данных, включая данные о подкачке и ключевые слова q.
Файл шаблона конфигурации — templates/video/search.html.
Итак, код шаблона написан в search.html.
<div class="ui unstackable items">
{% for item in video_list %}
<div class="item">
<div class="ui tiny image">
{% thumbnail item.cover "300x200" crop="center" as im %}
<img class="ui image" src="{{ im.url }}">
{% empty %}
{% endthumbnail %}
</div>
<div class="middle aligned content">
<a class="header" href="{% url 'video:detail' item.pk %}">{{ item.title }}</a>
</div>
</div>
{% empty %}
<h3>暂无数据</h3>
{% endfor %}
</div>
{% include "base/page_nav.html" %}
Эффект функции поиска