Получение связанных объектов через теги в 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)
- просто пример идентификатора тега
Надеюсь, поможет! Не стесняйтесь адаптировать его к вашим потребностям.