Django中通过标签获取相关对象
Getting related objects via tags in Django
我的目标是在访问单个产品页面时在我的电子商务网站中建立一个 "Recommended Products" 部分。
我有一系列产品,在管理员中有几个用户定义的标签。标签系统是 django-taggit
和 modelcluster
的组合,详见 Wagtail-CMS docs.
我试图做到这一点,以便在访问产品页面时,Django 会查看带有 same/similar 标签的所有其他产品,并根据数量将它们列在 "Recommended Products" 部分中相同的标签。根据 their docs.
,django-taggit
文档似乎通过 get_related()
函数在 API 中解决了这一需求
我正在努力让它工作,但是因为我不断遇到错误,最新的错误是 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,)
如果我尝试访问其他产品页面,我会遇到同样的错误,只是异常值不同。该函数需要来自字典的键,但由于某种原因,它被赋予了值...这可能是代码的兼容性问题吗?
好的,经过大量的研究和修改,我找到了一个解决方案,但是这个 只适用于 Django >= 1.9.
Github 用户 nickhudkins 运行 遇到了同样的问题并编辑了 similar_objects()
函数来解决 KeyError,详见他的 ticket.
解决方法是进入 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
- 我的标签的 m2m 模型(继承自 TaggedItemBase
)
wagtailcore_page
- 基本 Wagtail table 页面
taggit_tag
- Taggit 标签 table
(1, 2, 3)
- 只是示例标记 ID
希望对您有所帮助!请随意根据您的需要进行调整。
我的目标是在访问单个产品页面时在我的电子商务网站中建立一个 "Recommended Products" 部分。
我有一系列产品,在管理员中有几个用户定义的标签。标签系统是 django-taggit
和 modelcluster
的组合,详见 Wagtail-CMS docs.
我试图做到这一点,以便在访问产品页面时,Django 会查看带有 same/similar 标签的所有其他产品,并根据数量将它们列在 "Recommended Products" 部分中相同的标签。根据 their docs.
,django-taggit
文档似乎通过 get_related()
函数在 API 中解决了这一需求
我正在努力让它工作,但是因为我不断遇到错误,最新的错误是 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,)
如果我尝试访问其他产品页面,我会遇到同样的错误,只是异常值不同。该函数需要来自字典的键,但由于某种原因,它被赋予了值...这可能是代码的兼容性问题吗?
好的,经过大量的研究和修改,我找到了一个解决方案,但是这个 只适用于 Django >= 1.9.
Github 用户 nickhudkins 运行 遇到了同样的问题并编辑了 similar_objects()
函数来解决 KeyError,详见他的 ticket.
解决方法是进入 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
- 我的标签的 m2m 模型(继承自 TaggedItemBase
)
wagtailcore_page
- 基本 Wagtail table 页面
taggit_tag
- Taggit 标签 table
(1, 2, 3)
- 只是示例标记 ID
希望对您有所帮助!请随意根据您的需要进行调整。