【问题标题】:Django haystack SearchQuerySet to QuerySetDjango 干草堆 SearchQuerySet 到 QuerySet
【发布时间】:2012-11-30 09:47:26
【问题描述】:

我有一个非常通用的视图/模板来显示给定模型的查询集的内容。
我在 12 个地方使用了 12 个不同的查询集,现在我想在其中集成 haystack 搜索,但我不能,因为 SearchQuerySet 与模板中的 QuerySet 不匹配。

我使用普通的查询集

{%for obj in qs%}
    {{obj.foreign_key.name }}
{%endfor%}

使用 SearchQuerySet 我需要这样做

{%for obj in qs%} 
   {{obj.object.foreign_key.name}}
{%endfor%}

这基本上破坏了我现在知道查询集来自哪里的通用模板和视图。

我想要一种让 searchqueryset 表现得像普通查询集的方法,我知道:

  • 虽然我会维持秩序,但我会输掉分数
  • 我需要执行 load_all() 来获取整个对象

关于如何保持模板通用但接受 SearchQuerySet 或将 SearchQuerySet 转换为 QuerySet 的任何提示?

【问题讨论】:

  • 如何从视图中返回一个列表,例如:[obj.object for obj in qs],那么模板中的 forloop 应该仍然可以工作
  • 这将实例化整个查询集,而且我会失去分页,我需要返回一个类似查询集的对象

标签: django solr django-queryset django-haystack


【解决方案1】:

我使用了一个简洁的生成器技巧,它可以避免将 object 方法添加到您的模型中,并允许您对 Django 的 QuerySet 和 Haystack SearchQuerySet 使用相同的模板。

诀窍是将您的 SearchQuerySet 包装到生成器中。

# In your view...

def queryset_gen(search_qs):
    for item in search_qs:
        yield item.object  # This is the line that gets the model instance out of the Search object

qs = queryset_gen(sqs)

这种方法的优点是它保持 SearchQuerySet 返回的顺序并节省计算和内存,因为您不需要创建或存储列表的另一个实例。

【讨论】:

    【解决方案2】:

    如何在模型上添加一个名为object 的方法,以便查询集的行为类似于 SearchQuerySet?例如

    class MyModel(models.Model):
        ...
    
        @property
        def object(self):
            return self
    

    【讨论】:

    • 您不需要添加@property吗?
    【解决方案3】:

    对于那些来这里寻找更通用的方法来处理像 QS 一样的 SQS 的其他人。

    我需要为 Django Rest Framework 提供类似的东西,所以我为 sqs -> qs 创建了以下包装器。 它允许将 SQS 当作一个查询集来处理,但对迭代和切片的支持有限。

    您也可以在迭代生成器函数之前调用 load_all。

    class SearchQuerySetWrapper(object):
        """
        Decorates a SearchQuerySet object using a generator for efficient iteration
        """
        def __init__(self, qs):
            self.qs = qs
    
        def count(self):
            return self.qs.count()
    
        def __iter__(self):
            for result in self.qs:
                yield result.object
    
        def __getitem__( self, key):
            if isinstance(key, int) and (key >= 0 or key < self.count()):
                # return the object at the specified position
                return self.qs[key].object
            # Pass the slice/range on to the delegate
            return SearchQuerySetWrapper(self.qs[key])
    

    【讨论】:

    • 仅生成器模式很有用,但这样更好,它支持例如分页器等...
    【解决方案4】:

    你可以这样创建一个数组:

    q = request.GET['q']
        results = SearchQuerySet().auto_query(q)
        obj = []
        for r in results:
            obj.append(r.object)
        return render_to_response('template.html',
            {'obj': obj )
    

    【讨论】:

    • 如果你这样做了(我建议不要这样做),你至少应该将它包装在一个生成器类中,它会暴露 count(),并在迭代期间返回对象。否则,如果您的查询包含数千条记录,您可能会冒着单个请求杀死您的服务器的风险。
    猜你喜欢
    • 2014-07-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-01-09
    相关资源
    最近更新 更多