我正在尝试使用Django Haystack进行搜索,然后在检索结果时,我需要将这些结果传递给我的Django Rest Framework序列化程序。
Django Rest Framework serializers.ModelSerializer要求为序列化程序发送一个对象查询集,以便能够将这些对象及其数据库字段序列化。
当我创建API视图并使用搜索获取结果时,haystack返回searchqueryset。
如何在不执行以下操作的情况下将此searchqueryset转换为django查询集:
article_queryset = Article.objects.filter(id__in=[i.object for i in searchqueryset])
您可以想象,有时搜索可以返回超过1000个搜索结果,这意味着上述效果非常低。
现在,Django rest框架允许我对返回的对象进行分页。我在每页上分成30个对象。我怎么可能用我的Haystack searchqueryset做同样的事情?
关于如何使用Haystack和Django Rest Framework的任何建议或想法都会很棒。其他人如何做类似事情的例子也很酷:)
答案 0 :(得分:8)
您可以使用Haystack的 SearchView (而不是DRF视图)来公开页面对象以进行分页。然后你可以把它传递给序列化器。
E.G。一段时间后,我正在研究在当前HTML页面上需要渲染结果的json对象的东西,所以我写了一个过滤器标签来执行此操作(我们使用FacetedSearchView用于UI,DRF用于更通用的RESTful API) 。在模板中调用如下:
var articlesJson = {{ page.object_list|article_jsonify }}
实际过滤标记:
import collections
from django.template import Library
from django.utils.safestring import mark_safe
from rest_framework.renderers import JSONRenderer
register = Library()
def article_jsonify(object):
if isinstance(object, collections.Iterable):
many = True
ids = [obj.object.id for obj in object]
else:
many = False
ids = [object.id]
articles = Article.objects.filter(pk__in=ids)
serializer = ArticleSerializer(articles, many=many)
content = JSONRenderer().render(serializer.data)
return mark_safe(content)
register.filter('article_jsonify', article_jsonify)
您还可以编写一个继承自 generics.ListAPIView 的视图,并覆盖 get_queryset 方法,您可以将请求的查询参数传递给 SearchQuerySet ,然后使用Serializer输出。更多信息:
http://www.django-rest-framework.org/api-guide/filtering
当然,你可能无法以这种方式使用ModelSerializer,除非你做了类似你提到的事情。但是,DRF有一个在查询集上使用paginator的示例:
http://www.django-rest-framework.org/api-guide/pagination#paginating-querysets
<强>更新强> 最后我最终使用了一个DRF视图,该视图使用Haystack SearchQuerySet作为查询集,然后将其传递给Paginator。这是一个简化的例子(我确信它可以简化一些),但我希望它有助于某人开始。
class ArticleList(ListCreateAPIView):
"""
List, Create files
"""
model = Article
def get(self, request, *args, **kwargs):
# simplified filtering of an SQS
q = request.get('q', '')
sqs = SearchQuerySet().filter(content=Clean(q))
paginator = Paginator(sqs, 20)
page = request.QUERY_PARAMS.get('page')
try:
articles = paginator.page(page)
except PageNotAnInteger:
# If page is not an integer, deliver first page
articles = paginator.page(1)
except PageNotAnInteger:
# If page is out of range, deliver last page
articles = paginator.page(paginator.num_pages)
serializer_context = {'request': request}
serializer = PaginatedArticleSerializer(articles, context=serializer_context)
return Response(serializer.data)
class ArticleSerializer(serializers.ModelSerializer):
"""
Base Article Serializer
"""
class Meta:
model = Article
class PaginatedArticleSerializer(pagination.PaginationSerializer):
"""
Serializes page objects of article querysets.
"""
start_index = serializers.SerializerMethodField('get_start_index')
end_index = serializers.SerializerMethodField('get_end_index')
num_pages = serializers.Field(source='paginator.num_pages')
class Meta:
object_serializer_class = ArticleSerializer
def get_start_index(self, page):
return page.start_index()
def get_end_index(self, page):
return page.end_index()
def get_curr_page(self, page):
return page.number