Добавление тегов
После внедрения системы комментариев мы создадим способ маркировки наших записей(постов). Мы включим в наш проект сторонний компонент django-taggit. Можно взглянуть на исходный код компонента здесь:https://github.com/alex/django-taggit
Для начала вам необходимо с помощью pip установить django-taggit:
pip install django-taggit==0.17.1
Затем отредактируйте файл settings.py проекта mysite и добавьте taggit к INSTALLED_APPS:
INSTALLED_APPS = (
# ...
'blog',
'taggit',
)
Откройте файл models.py приложения 'blog' и добавьте диспетчерTaggableManager, предоставленный с помощьюdjango-taggit, в модельPost, следующим образом:
from taggit.managers import TaggableManager
class Post(models.Model):
# ...
tags = TaggableManager()
Диспетчер тегов позволит добавлять, извлекать и удалять теги из объектов.
Выполните следующую команду, чтобы создать миграцию для изменения модели:
python manage.py makemigrations blog
Вы увидите следующее:
Migrations for 'blog':
0003_post_tags.py:
- Add field tags to post
Теперь выполните следующую команду, чтобы создать требуемые таблицы баз данных для django-taggit:
python manage.py migrate
Будут выведены результаты, указывающие на применение миграции:
Applying taggit.0001_initial... OK
Applying taggit.0002_auto_20150616_2121... OK
Applying blog.0003_post_tags... OK
Теперь база данных готова к использованию моделей django-taggit. Откройте терминал с помощью командыpython manage.py shell
и посмотрите, как использовать диспетчер тегов.
Во-первых,мы извлекаем одну из наших записей(одну с ID 1):
>>> from blog.models import Post
>>> post = Post.objects.get(id=1)
Затем добавьте к записи несколько тегов и получите их обратно, чтобы убедиться, что они были успешно добавлены:
>>> post.tags.add('music', 'jazz', 'django')
>>> post.tags.all()
[<Tag: jazz>, <Tag: django>, <Tag: music>]
Теперь, удалите один тег и снова проверьте список тегов:
>>> post.tags.add('music', 'jazz', 'django')
>>> post.tags.all()
[<Tag: jazz>, <Tag: django>, <Tag: music>]
Это было легко, правда? Запустите команду python manage.py runserver
, чтобы снова запустить сервер разработки и откройте в браузере страницуhttp://127.0.0.1:8000/admin/taggit/. В админке теперь отображается список объектов Tag приложения taggit:
Перейдите к http://127.0.0.1:8000/admin/blog/post/ и кликните по любой записи, чтобы отредактировать ее. Вы увидите, что в записи включены новые поля тегов:
Теперь мы собираемся отредактировать записи блога для отображения тегов. Откройте шаблонblog/post/list.htmlи добавьте следующий код HTML под заголовком поста:
<p class="tags">Tags: {{ post.tags.all|join:", " }}</p>
post.tags.all добавляет все теги данного поста, а join разделяет их, в нашем случае запятой. Откройте http://127.0.0.1:8000/blog/ в браузере. В каждом заголовке должно быть видно список тегов:
Теперь мы собираемся отредактировать наше представление post_list, чтобы позволить пользователям найти все записи, помеченные определенным тегом. Откройте файл views.py приложения 'blog', импортируйте модель Tag из django-taggit и измените представление post_list, чтобы при необходимости фильтровать записи по тегу, следующим образом:
from taggit.models import Tag
def post_list(request, tag_slug=None):
object_list = Post.published.all()
tag = None
if tag_slug:
tag = get_object_or_404(Tag, slug=tag_slug)
object_list = object_list.filter(tags__in=[tag])
# ...
Тепер view работает следующим образом:
- Представление принимает необязательный параметр tag_slug , имеющий значение по умолчанию None. Этот параметр будет находиться в URL-адресе.
- Внутри представления мы строим исходный запрос(QuerySet), извлекая все опубликованные записи, и если имеется заданный тег, далее мы получаем тег с заданным slug с помощью фукции get_object_or_404().
- Затем мы отфильтруем список записей с заданным тегом. Поскольку это отношение «многие ко многим», мы должны фильтровать теги, содержащиеся в данном списке, который в нашем случае содержит только один элемент.
Наконец, измените функцию render() в нижней части представления, чтобы передать переменную tag в шаблон, который, теперь должен выглядеть следующим образом:
def post_list(request, tag_slug=None):
object_list = Post.published.all()
tag = None
if tag_slug:
tag = get_object_or_404(Tag, slug=tag_slug)
object_list = object_list.filter(tags__in=[tag])
paginator = Paginator(object_list, 3) # 3 posts in each page
page = request.GET.get('page')
try:
posts = paginator.page(page)
except PageNotAnInteger:
# If page is not an integer deliver the first page
posts = paginator.page(1)
except EmptyPage:
# If page is out of range deliver last page of results
posts = paginator.page(paginator.num_pages)
return render(request, 'blog/post/list.html', {'page': page,
'posts': posts,
'tag': tag})
Откройте файл urls.py приложения 'blog', закомментируйте шаблон URL-адресаPostListView, основанный на базовом классе(class-based), и удалите комментарии в представленииpost_listследующим образом:
url(r'^$', views.post_list, name='post_list'),
# url(r'^$', views.PostListView.as_view(), name='post_list'),
ДобавьтеследующийдополнительныйшаблонURL-адресадлясписказаписейпотегу:
url(r'^tag/(?P<tag_slug>[-\w]+)/$', views.post_list, name='post_list_by_tag'),
Как можно видеть, оба образца указывают на один и тот же view, но мы именуем их по-разному. Первый шаблон будет вызывать post_list view без дополнительных параметров, в то время как второй шаблон будет вызывать представление с параметром tag_slug.
Поскольку мы используем post_list представление, отредактируйте шаблон blog/post/list.html и измените пагинацию, чтобы использовать объект posts следующим образом:
{% include "pagination.html" with page=posts %}
Добавьте следующие строки над циклом{% for %}
:
{% if tag %}
<h2>Posts tagged with "{{ tag.name }}"</h2>
{% endif %
Если пользователь получает доступ к блогу, он увидит список всех постов. Теперь пользователь может отфильтровать записи по тегу. Измените способ отображения тегов в следующих местах:
<p class="tags">
Tags:
{% for tag in post.tags.all %}
<a href="{% url "blog:post_list_by_tag" tag.slug %}">
{{ tag.name }}
</a>
{% if not forloop.last %}, {% endif %}
{% endfor %}
</p>
Теперь мы перейдем по всем тегам записи, отображающей пользовательскую ссылку на URL-адрес для фильтрации записей по этому тегу. Мы строим URL-адрес с тегом , используя имя URL-адреса и тегslugв качестве параметра. Теги разделяются запятыми.
Откройтеhttp://127.0.0.1:8000/blog/в браузере и щелкните на любой тег. Список записей, отфильтрованных по этому тегу, отобразятся следующим образом: