My goal is to build a "Recommended Products" section in my e-commerce website when accessing an individual product page.
I have a sereis of products which have several user-defined tags in the admin. The tagging system is a combination of django-taggit
and modelcluster
, as detailed in the Wagtail-CMS docs.
I am trying to make it so that when a product page is accessed, Django looks at all other products with the same/similar tags and lists them in the "Recommended Products" section, based on the number of identical tags. The django-taggit
docs seem to address this need in their API with the get_related()
function, as per their docs.
I am struggling to get this working however as I keep on encountering errors, the latest being Exception Type: KeyError at /categories/test-category/test-product/
Exception Value: (15,)
. Here's my code so far:
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
EDIT | Full error traceback below:
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,)
If I try and access other product pages I get the same error, just with a different Exception Value. The function is expecting a key from a dict but for some reason it's being given the value instead... Could this be a compatibility issue with the code?
OK so after much research and tinkering I have found a solution, however this only works for Django >= 1.9.
Github user nickhudkins ran into the same issue and edited the similar_objects()
function to resolve the KeyError, as detailed in his ticket.
The solution is to go into the taggit managers.py
and edit the function as follows (+ denotes adding the lines and - removing them).
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: