Расширить django-taggit
3 ноября 2016 г. 10:02
Потребовалось мне улучшить отображение django-taggit в админке. Делается это путём расширения приложения, которое достаточно хорошо описано в официальной документации. Но тем не менее я решил показать на примере, как можно кастомизировать отображение тегов приложения taggit в админке.
Поставленные задачи:
- Добавить колонку "Количество элементов" на страницу списка тегов для того, чтобы удобно было смотреть каких тегов меньше всего. Владея этой информацией, можно, например, добавить ещё статей с этими тегами.
- Убрать пустые "Элементы с меткой", которые добавляются по умолчанию на странице редактирования тега.
- Отобразить "Смотреть на сайте" как для "Тега" (Метки), так и для "Элемента с меткой".
Решение:
Для того чтобы в админке отображалась ссылка "Смотреть на сайте" для самого тега:
и для inline элемента:
нужно создать свой Tag и TaggedItem (дефолтный Tag и TaggedItem можно найти в приложении taggit/models.py) и добавить get_absolute_url(). Django, если видит, что существует данный метод, то автоматически добавляет ссылку "Смотреть на сайте". Для того чтобы сохранить полную функциональность TaggedItemBase (я имею в виду метод tags_for(cls, model, instance=None, **extra_filters), который есть в TaggedItemBase), нужно создать свой TaggedItemBase. Полный код приводится ниже:
# models.py
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models
from django.db.models import permalink
from django.http import Http404
from taggit.managers import TaggableManager
from taggit.models import GenericTaggedItemBase, TagBase, ItemBase
from django.utils.translation import ugettext_lazy as _
class MyTag(TagBase):
@permalink
def get_absolute_url(self):
return 'tag_page', [self.slug, ]
class Meta:
verbose_name = _("Tag")
verbose_name_plural = _("Tags")
class MyTaggedItemBase(ItemBase):
tag = models.ForeignKey(MyTag, related_name="tag_items", on_delete=models.CASCADE)
@property
def name(self):
return self.tag.name
class Meta:
abstract = True
@classmethod
def tags_for(cls, model, instance=None, **extra_filters):
kwargs = extra_filters or {}
if instance is not None:
kwargs.update({
'%s__content_object' % cls.tag_relname(): instance
})
return cls.tag_model().objects.filter(**kwargs)
kwargs.update({
'%s__content_object__isnull' % cls.tag_relname(): False
})
return cls.tag_model().objects.filter(**kwargs).distinct()
class MyTaggedItem(GenericTaggedItemBase, MyTaggedItemBase):
def get_absolute_url(self):
if not hasattr(self.content_object, 'get_absolute_url'):
raise Http404
return self.content_object.get_absolute_url()
class Meta:
verbose_name = _("Tagged Item")
verbose_name_plural = _("Tagged Items")
index_together = [
["content_type", "object_id"],
]
В классе MyTaggedItem если self.content_object не имеет get_absolute_url(), то просто бросаем исключение Http404.
Мы не наследуемся от TaggedItem, так как не будут работать index_together, а также verbose_name в Meta классе. К тому же нам нужно унаследоваться от MyTaggedItemBase.
Затем изменим админку для taggit:
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.contrib import admin
from taggit.models import Tag
from taggit.admin import TagAdmin
from spec.models import MyTaggedItem
admin.site.unregister(Tag)
class TaggedItemInline(admin.StackedInline):
model = MyTaggedItem
extra = 0 # убирает пустые "Элементы с меткой" (Задача 2)
@admin.register(Tag)
class CustomTagAdmin(TagAdmin):
inlines = (TaggedItemInline, )
list_display = ('name', 'slug', 'item_count')
def item_count(self, obj):
count = obj.tag_items.count()
if count:
return count # Выводит количество "Элементов с меткой" (Задача 1)
return '<img alt="False" src="/static/admin/img/icon-no.gif" />'
item_count.short_description = 'Количество элементов'
item_count.allow_tags = True
Метод item_count(self, obj) выводит количество "Элементов с меткой", если количество не равно нулю. Иначе, выводит стандартную джанговскую иконку False для boolean полей. Иконка захаркодена, но что поделать. Если знаете способ лучше, пожалуйста, сообщите :) А чтобы иконка отображалась, позволяем использование html-тегов: item_count.allow_tags = True.
Все задачи выполнены!
P.S. Если определён свой TaggedItem и не задан related_name в поле tag, то уже обращение к объектам тега будет примерно так tag.myapp_mytaggeditem_items.all().
Похожие статьи:
- Расширить django-taggit
- Отсортировать теги по имени, используя django-taggit и django-taggit-labels
- Миграции не создаются, ошибка dependencies references nonexistent parent node
- Сохранение тегов (taggit) при публикации страницы в django-cms
- Unable to get repr for <class 'django.db.models.query.QuerySet'>. Поиск по тегам в плагинах django
Представляю вашему вниманию книгу, написанную моим близким другом Максимом Макуриным: Секреты эффективного управления ассортиментом.
Книга предназначается для широкого круга читателей и, по мнению автора, будет полезна специалистам отдела закупок и логистики, категорийным и финансовым менеджерам, менеджерам по продажам, аналитикам, руководителям и директорам, в компетенции которых принятие решений по управлению ассортиментом.
Комментарии: 0