Добавление тегов

После внедрения системы комментариев мы создадим способ маркировки наших записей(постов). Мы включим в наш проект сторонний компонент 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 работает следующим образом:

  1. Представление принимает необязательный параметр tag_slug , имеющий значение по умолчанию None. Этот параметр будет находиться в URL-адресе.
  2. Внутри представления мы строим исходный запрос(QuerySet), извлекая все опубликованные записи, и если имеется заданный тег, далее мы получаем тег с заданным slug с помощью фукции get_object_or_404().
  3. Затем мы отфильтруем список записей с заданным тегом. Поскольку это отношение «многие ко многим», мы должны фильтровать теги, содержащиеся в данном списке, который в нашем случае содержит только один элемент.

Наконец, измените функцию 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/в браузере и щелкните на любой тег. Список записей, отфильтрованных по этому тегу, отобразятся следующим образом:

results matching ""

    No results matching ""