2017-11-11 206 views
2

我的目標是在訪問單個產品頁面時在我的電子商務網站中構建「推薦產品」部分。通過Django中的標籤獲取相關對象

我有一個產品的sereis在管理員中有幾個用戶定義的標籤。標記系統是django-taggitmodelcluster的組合,詳見Wagtail-CMS docs

我試圖使它在訪問產品頁面時,Django會查看所有其他具有相同/相似標籤的產品,並根據相同標籤的數量在「推薦產品」部分中列出它們。根據their docsdjango-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,) 

如果我嘗試訪問其他產品頁面,我會得到相同的錯誤,只是使用不同的異常值。該函數期望從一個字典的關鍵,但由於某種原因,它被賦予的價值,而不是...這可能是與代碼兼容性問題?

+0

'related_products = current_tags.similar_objects()'不會返回你想要的'Product'對象列表嗎?通過'Product.objects.filter(...)'傳遞它似乎沒有任何目的(也不是'filter'方法的有效語法)。 – gasman

+0

這就是我在第一次嘗試時所嘗試的 - 仍然給了我同樣的錯誤:'異常類型:KeyError在/ categories/test-category/test-product /異常值:(15,)'和回溯到'元組(在lookup_keys中k的結果[k])'@gasman – DDiran

+0

請分享完整的回溯 - 單行代碼並不能真正告訴我任何事情。 – gasman

回答

0

好吧,經過大量的研究和修補,我發現了一個解決方案,但是這個只適用於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: 
0

如果你不想打補丁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 - 對我的代碼(從TaggedItemBase iherited)M2M模型

wagtailcore_page - Taggit標籤 - 爲

taggit_tag頁基地鶺鴒表表

(1, 2, 3) - j ust示例標記ID

希望它有幫助!隨意適應您的需求。