I am attempting to do a search using Django Haystack and then upon retrieving results I need to pass these results to my Django Rest Framework serializer.
我试图使用Django Haystack进行搜索,然后在检索结果时,我需要将这些结果传递给我的Django Rest Framework序列化程序。
The Django Rest Framework serializers.ModelSerializer requires that a queryset of objects gets sent for the serializer to be able to serialize these objects along with their database fields.
Django Rest Framework serializers.ModelSerializer要求为序列化程序发送一个对象查询集,以便能够将这些对象及其数据库字段序列化。
When I create my API view and use search to get results haystack returns a searchqueryset.
当我创建我的API视图并使用搜索来获取结果时,haystack返回searchqueryset。
How could I get this searchqueryset into a django queryset without doing something like:
如何在不执行以下操作的情况下将此searchqueryset放入django查询集中:
article_queryset = Article.objects.filter(id__in=[i.object for i in searchqueryset])
As you could imagine, sometimes search can return excess of 1000 search results which means that the above would be very inefficient.
可以想象,有时搜索可以返回超过1000个搜索结果,这意味着上述效率非常低。
Right now the Django rest framework allows me to paginate my returned objects. I am paginating by 30 objects on each page. How would it be possible for me to do the same with my Haystack searchqueryset?
现在,Django rest框架允许我对返回的对象进行分页。我在每页上分成30个对象。我怎么可能用我的Haystack searchqueryset做同样的事情?
Any advice or ideas on how to use Haystack along with Django Rest Framework would be great. Examples of how others have done a similar thing would be cool too :)
关于如何使用Haystack和Django Rest Framework的任何建议或想法都会很棒。其他人如何做类似事情的例子也很酷:)
1 个解决方案
#1
8
You could use Haystack's SearchView (instead of a DRF view) which exposes the page object for pagination. Then you can just pass that to your serializer.
您可以使用Haystack的SearchView(而不是DRF视图)来公开页面对象以进行分页。然后你可以把它传递给你的序列化器。
E.G. Awhile back I was working on something that required the json object of the rendered results on the current HTML page, so I wrote a filter tag to do this (we were using FacetedSearchView for the UI, and DRF for a more general purpose RESTful API). Called like so in the template:
例如。一段时间后,我正在研究在当前HTML页面上需要渲染结果的json对象的东西,所以我写了一个过滤器标签来执行此操作(我们使用FacetedSearchView作为UI,DRF使用更通用的RESTful API) 。在模板中调用如下:
var articlesJson = {{ page.object_list|article_jsonify }}
Actual filter tag:
实际过滤标签:
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)
You could also write a view inherited from generics.ListAPIView and override the get_queryset method, where you would pass the request's query parameter to a SearchQuerySet, then output it using the Serializer. More info here:
您还可以编写从generics.ListAPIView继承的视图并覆盖get_queryset方法,您可以将请求的查询参数传递给SearchQuerySet,然后使用Serializer输出它。更多信息:
http://www.django-rest-framework.org/api-guide/filtering
http://www.django-rest-framework.org/api-guide/filtering
Of course you might not be able to use the ModelSerializer this way, unless you do something like you mentioned. However DRF has an example on using the paginator on a queryset like so:
当然,您可能无法以这种方式使用ModelSerializer,除非您执行类似于您提到的操作。但是,DRF有一个在查询集上使用paginator的示例,如下所示:
http://www.django-rest-framework.org/api-guide/pagination#paginating-querysets
http://www.django-rest-framework.org/api-guide/pagination#paginating-querysets
UPDATE I ended up eventually using a DRF view that uses a Haystack SearchQuerySet as the queryset, and then passing it to a Paginator. Here is a simplified example (I'm sure it can be streamlined some), but I hope it helps someone gets started.
更新我最终使用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
#1
8
You could use Haystack's SearchView (instead of a DRF view) which exposes the page object for pagination. Then you can just pass that to your serializer.
您可以使用Haystack的SearchView(而不是DRF视图)来公开页面对象以进行分页。然后你可以把它传递给你的序列化器。
E.G. Awhile back I was working on something that required the json object of the rendered results on the current HTML page, so I wrote a filter tag to do this (we were using FacetedSearchView for the UI, and DRF for a more general purpose RESTful API). Called like so in the template:
例如。一段时间后,我正在研究在当前HTML页面上需要渲染结果的json对象的东西,所以我写了一个过滤器标签来执行此操作(我们使用FacetedSearchView作为UI,DRF使用更通用的RESTful API) 。在模板中调用如下:
var articlesJson = {{ page.object_list|article_jsonify }}
Actual filter tag:
实际过滤标签:
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)
You could also write a view inherited from generics.ListAPIView and override the get_queryset method, where you would pass the request's query parameter to a SearchQuerySet, then output it using the Serializer. More info here:
您还可以编写从generics.ListAPIView继承的视图并覆盖get_queryset方法,您可以将请求的查询参数传递给SearchQuerySet,然后使用Serializer输出它。更多信息:
http://www.django-rest-framework.org/api-guide/filtering
http://www.django-rest-framework.org/api-guide/filtering
Of course you might not be able to use the ModelSerializer this way, unless you do something like you mentioned. However DRF has an example on using the paginator on a queryset like so:
当然,您可能无法以这种方式使用ModelSerializer,除非您执行类似于您提到的操作。但是,DRF有一个在查询集上使用paginator的示例,如下所示:
http://www.django-rest-framework.org/api-guide/pagination#paginating-querysets
http://www.django-rest-framework.org/api-guide/pagination#paginating-querysets
UPDATE I ended up eventually using a DRF view that uses a Haystack SearchQuerySet as the queryset, and then passing it to a Paginator. Here is a simplified example (I'm sure it can be streamlined some), but I hope it helps someone gets started.
更新我最终使用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