Получение связанных объектов через теги в Django

Моя цель - создать раздел "Рекомендуемые продукты" на моем веб-сайте электронной коммерции при доступе к отдельной странице продукта.

У меня есть несколько продуктов, которые имеют несколько пользовательских тегов в админке. Система маркировки представляет собой комбинацию django-taggit а также modelcluster, как подробно описано в документах Wagtail-CMS.

Я пытаюсь сделать так, чтобы при доступе к странице продукта Django просматривал все другие продукты с одинаковыми / похожими тегами и перечислял их в разделе "Рекомендуемые продукты", основываясь на количестве идентичных тегов. django-taggit Документы, кажется, решают эту проблему в своем API с помощью get_related() функции, согласно их документам.

Я изо всех сил пытаюсь заставить это работать, однако я продолжаю сталкиваться с ошибками, последнее Exception Type: KeyError at /categories/test-category/test-product/ Exception Value: (15,), Вот мой код до сих пор:

class ProductTag(TaggedItemBase):
    content_object = ParentalKey('Product', related_name='tagged_items')

class Product(Page):
    ...

    tags = ClusterTaggableManager(through=ProductTag, blank=True)

def get_context(self, request):
    context = super(Product, self).get_context(request)

    current_tags = self.tags
    related_products = Product.objects.filter(current_tags.similar_objects())

    context['related_products'] = related_products
    return context

РЕДАКТИРОВАТЬ | Полная трассировка ошибок ниже:

Environment:


Request Method: GET
Request URL: http://127.0.0.1:8000/categories/test-category/test-product/

Django Version: 1.11.5
Python Version: 3.5.2
Installed Applications:
['home',
 'search',
 'products',
 'wagtail.wagtailforms',
 'wagtail.wagtailredirects',
 'wagtail.wagtailembeds',
 'wagtail.wagtailsites',
 'wagtail.wagtailusers',
 'wagtail.wagtailsnippets',
 'wagtail.wagtaildocs',
 'wagtail.wagtailimages',
 'wagtail.wagtailsearch',
 'wagtail.wagtailadmin',
 'wagtail.wagtailcore',
 'modelcluster',
 'taggit',
 'django.contrib.admin',
 'django.contrib.auth',
 'django.contrib.contenttypes',
 'django.contrib.sessions',
 'django.contrib.messages',
 'django.contrib.staticfiles']
Installed Middleware:
['django.contrib.sessions.middleware.SessionMiddleware',
 'django.middleware.common.CommonMiddleware',
 'django.middleware.csrf.CsrfViewMiddleware',
 'django.contrib.auth.middleware.AuthenticationMiddleware',
 'django.contrib.auth.middleware.SessionAuthenticationMiddleware',
 'django.contrib.messages.middleware.MessageMiddleware',
 'django.middleware.clickjacking.XFrameOptionsMiddleware',
 'django.middleware.security.SecurityMiddleware',
 'wagtail.wagtailcore.middleware.SiteMiddleware',
 'wagtail.wagtailredirects.middleware.RedirectMiddleware']



Traceback:

File "C:\Users\ddl_9\Envs\fstvl\lib\site-packages\django\core\handlers\exception.py" in inner
  41.             response = get_response(request)

File "C:\Users\ddl_9\Envs\fstvl\lib\site-packages\django\core\handlers\base.py" in _get_response
  187.                 response = self.process_exception_by_middleware(e, request)

File "C:\Users\ddl_9\Envs\fstvl\lib\site-packages\django\core\handlers\base.py" in _get_response
  185.                 response = wrapped_callback(request, *callback_args, **callback_kwargs)

File "C:\Users\ddl_9\Envs\fstvl\lib\site-packages\wagtail\wagtailcore\views.py" in serve
  26.     return page.serve(request, *args, **kwargs)

File "C:\Users\ddl_9\Envs\fstvl\lib\site-packages\wagtail\wagtailcore\models.py" in serve
  773.             self.get_context(request, *args, **kwargs)

File "C:\Users\ddl_9\Desktop\fstvl\products\models.py" in get_context
  143.      related_products = current_tags.similar_objects()

File "C:\Users\ddl_9\Envs\fstvl\lib\site-packages\taggit\utils.py" in inner
  146.         return func(self, *args, **kwargs)

File "C:\Users\ddl_9\Envs\fstvl\lib\site-packages\taggit\managers.py" in similar_objects
  350.                 tuple(result[k] for k in lookup_keys)

Exception Type: KeyError at /categories/test-category/test-product/
Exception Value: (15,)

Если я пытаюсь получить доступ к другим страницам продукта, я получаю ту же ошибку, но с другим значением исключения. Функция ожидает ключ от dict, но по какой-то причине ей вместо этого дают значение... Может ли это быть проблемой совместимости с кодом?

2 ответа

Решение

Итак, после долгих исследований и поисков я нашел решение, однако это работает только для Django> = 1.9.

Пользователь Github nickhudkins столкнулся с той же проблемой и отредактировал similar_objects() функция для разрешения KeyError, как подробно описано в его билете.

Решение состоит в том, чтобы пойти в taggit managers.py и отредактируйте функцию следующим образом (+ обозначает добавление строк и - удаление их).

             objs = rel_model._default_manager.filter(**{
                  "%s__in" % remote_field.field_name: [r["content_object"] for r in qs]
              })
 +            actual_remote_field_name = remote_field.field_name
 +            if VERSION > (1, 9):
 +                actual_remote_field_name = f.target_field.get_attname()
 +            else:
 +                actual_remote_field_name = f.related_field.get_attname()
              for obj in objs:
 -                items[(getattr(obj, remote_field.field_name),)] = obj
 +                items[(getattr(obj, actual_remote_field_name),)] = obj
          else:
              preload = {}
              for result in qs:

Если вы не хотите исправлять django-taggitДругим возможным решением является использование raw SQL запрос Похоже на это:

ArticlePage.objects.raw('select a.page_ptr_id, p.title, count(at.tag_id) as tag_count from article_articlepage a join wagtailcore_page p on a.page_ptr_id = p.id join article_articletag at on at.content_object_id = a.page_ptr_id join taggit_tag t on t.id = at.tag_id where tag_id in (1, 2, 3) group by (page_ptr_id, p.id) order by tag_count desc');

ArticlePage - моя модель

ArticleTag - м2м модель для моих тегов (унаследовано от TaggedItemBase)

wagtailcore_page - базовая трясогузка для страниц

taggit_tag - Таблица тегов Taggit

(1, 2, 3) - просто пример идентификатора тега

Надеюсь, поможет! Не стесняйтесь адаптировать его к вашим потребностям.

Другие вопросы по тегам