在 django rest 框架序列化 SearchQuerySet 中摆脱 "object" 包装器
Get rid of "object" wrapper in django rest framework serialized SearchQuerySet
我使用 DRF 序列化 Django Haystack 的 SearchQueryStack,如下所示,在生成的 JSON 响应中,我想摆脱我的 Post 模型周围的对象包装器:
{
"count": 6,
"next": null,
"previous": null,
"start_index": 1,
"end_index": 6,
"num_pages": 1,
"results": [
{
"postWrapper": {
"hitcount": {
"counter": 9,
"id": 251
},
"id": 277,
"content": "test",
"owner": {...
这是我想要的JSON(没有postWrapper):
{
"count": 6,
"next": null,
"previous": null,
"start_index": 1,
"end_index": 6,
"num_pages": 1,
"results": [
{
"hitcount": {
"counter": 9,
"id": 251
},
"id": 277,
"content": "test",
"owner": {...
这是视图:
class PostSearch(generics.ListAPIView):
model = Post
def get(self, request, *args, **kwargs):
# simplified filtering of an SQS
q = request.GET.get('q')
sqs = SearchQuerySet().filter(content=q)
paginator = Paginator(sqs, 10)
page = request.GET.get('page')
try:
posts = paginator.page(page)
except PageNotAnInteger:
# If page is not an integer, deliver first page
posts = paginator.page(1)
except EmptyPage:
# If page is out of range (e.g. 9999), deliver last page of results.
posts = paginator.page(paginator.num_pages)
serializer_context = {'request': request}
serializer = PaginatedPostSerializer(posts, context=serializer_context)
ret = serializer.data
return response.Response(ret)
class SearchSerializer(serializers.Serializer):
object = PostSerializer()
def to_representation(self, obj):
"""
Object instance -> Dict of primitive datatypes.
"""
ret = OrderedDict()
fields = [field for field in self.fields.values() if not field.write_only]
for field in fields:
try:
attribute = field.get_attribute(obj)
if field.field_name == 'object':
field.field_name = 'postWrapper'
except SkipField:
continue
if attribute is not None:
ret[field.field_name] = field.to_representation(attribute)
return ret
这里是序列化程序:
class SearchSerializer(serializers.Serializer):
object = PostSerializer()
def to_representation(self, obj):
"""
Object instance -> Dict of primitive datatypes.
"""
ret = OrderedDict()
fields = [field for field in self.fields.values() if not field.write_only]
for field in fields:
try:
attribute = field.get_attribute(obj)
if field.field_name == 'object':
field.field_name = 'postWrapper'
except SkipField:
continue
if attribute is not None:
ret[field.field_name] = field.to_representation(attribute)
return ret
class PaginatedPostSerializer(pagination.PaginationSerializer):
start_index = serializers.SerializerMethodField()
end_index = serializers.SerializerMethodField()
num_pages = serializers.ReadOnlyField(source='paginator.num_pages')
class Meta:
object_serializer_class = SearchSerializer
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
这是Post序列化器:
class PostSerializer(serializers.ModelSerializer):
owner = UserSerializer(required=False, read_only=True)
category_edit = serializers.PrimaryKeyRelatedField(queryset=Category.objects.all(), write_only=True)
category = CategorySerializer(read_only=True)
price = serializers.CharField()
price_currency = serializers.CharField()
hitcount = serializers.SerializerMethodField()
images = ImageSerializer(many=True, read_only=True)
def get_hitcount(self, context):
# Content_type for Post is 20
c_type = ContentType.objects.get_for_model(context)
obj, created = HitCount.objects.get_or_create(content_type=c_type, object_pk=context.id)
data = {}
data["id"] = obj.pk
data["counter"] = obj.hits
return data
class Meta:
model = Post
fields = ('hitcount', 'id', 'content', 'owner', 'category', 'category_edit', 'images', 'price', 'price_currency')
如您所见,我能得到的最接近的方法是将 'object' 包装器重命名为 'postWrapper'。我想将它作为包装器完全删除,所以 'results' 中只有 Post 模型列表,其中包含 'hitcount'、'id'、'content'、 'owner' 等...
非常感谢任何帮助。提前致谢。
我认为只需使用 PostSerializer
,因为 object_serializer_class
中的 PaginatedPostSerializer
就是您想要的。
class PaginatedPostSerializer(pagination.PaginationSerializer):
class Meta:
object_serializer_class = PostSerializer
如果您想覆盖 to_representation
,您可以 扩展 PostSerializers
而不是将其作为新字段添加到新的序列化程序中。
p.s.: 如果你想将结果项包装在 postWrapper
中,你不需要覆盖 to_representation
函数,你可以在你的 SearchSerializer
:
class SearchSerializer(serializers.Serializer):
# object = PostSerializer()
# rename the object to what you want
postWrapper = PostSerializer()
我想我对你的查询集的样子有误解,所以做出上面的回答。
class SearchSerializer(serializers.Serializer):
object = PostSerializer()
def to_representation(self, instance):
res = super(SearchSerializer, self).to_representation(instance)
# pop of the object field, and push the fields inside the object to parent level
objectfield = res.pop('object', None)
if objectfield:
for field, value in objectfield.iteritems():
res[field] = value
return res
恕我直言,将您的查询集更改为 Post
模型查询集,并将 paginatedSerializer 的 object_serializer_class 设置为 PostSerializer
更有意义。
所以我将它添加到我的 PostSearch 视图中,它解决了我的问题:
ret = serializer.data
new_result_list = []
results = ret.get('results')
for orderedDict in results:
post = orderedDict.get('object')
new_result_list.append(post)
ret['results'] = new_result_list
基本上我创建了一个没有 'object' 包装器的新列表,然后将其放回 return 值。
我使用 DRF 序列化 Django Haystack 的 SearchQueryStack,如下所示,在生成的 JSON 响应中,我想摆脱我的 Post 模型周围的对象包装器:
{
"count": 6,
"next": null,
"previous": null,
"start_index": 1,
"end_index": 6,
"num_pages": 1,
"results": [
{
"postWrapper": {
"hitcount": {
"counter": 9,
"id": 251
},
"id": 277,
"content": "test",
"owner": {...
这是我想要的JSON(没有postWrapper):
{
"count": 6,
"next": null,
"previous": null,
"start_index": 1,
"end_index": 6,
"num_pages": 1,
"results": [
{
"hitcount": {
"counter": 9,
"id": 251
},
"id": 277,
"content": "test",
"owner": {...
这是视图:
class PostSearch(generics.ListAPIView):
model = Post
def get(self, request, *args, **kwargs):
# simplified filtering of an SQS
q = request.GET.get('q')
sqs = SearchQuerySet().filter(content=q)
paginator = Paginator(sqs, 10)
page = request.GET.get('page')
try:
posts = paginator.page(page)
except PageNotAnInteger:
# If page is not an integer, deliver first page
posts = paginator.page(1)
except EmptyPage:
# If page is out of range (e.g. 9999), deliver last page of results.
posts = paginator.page(paginator.num_pages)
serializer_context = {'request': request}
serializer = PaginatedPostSerializer(posts, context=serializer_context)
ret = serializer.data
return response.Response(ret)
class SearchSerializer(serializers.Serializer):
object = PostSerializer()
def to_representation(self, obj):
"""
Object instance -> Dict of primitive datatypes.
"""
ret = OrderedDict()
fields = [field for field in self.fields.values() if not field.write_only]
for field in fields:
try:
attribute = field.get_attribute(obj)
if field.field_name == 'object':
field.field_name = 'postWrapper'
except SkipField:
continue
if attribute is not None:
ret[field.field_name] = field.to_representation(attribute)
return ret
这里是序列化程序:
class SearchSerializer(serializers.Serializer):
object = PostSerializer()
def to_representation(self, obj):
"""
Object instance -> Dict of primitive datatypes.
"""
ret = OrderedDict()
fields = [field for field in self.fields.values() if not field.write_only]
for field in fields:
try:
attribute = field.get_attribute(obj)
if field.field_name == 'object':
field.field_name = 'postWrapper'
except SkipField:
continue
if attribute is not None:
ret[field.field_name] = field.to_representation(attribute)
return ret
class PaginatedPostSerializer(pagination.PaginationSerializer):
start_index = serializers.SerializerMethodField()
end_index = serializers.SerializerMethodField()
num_pages = serializers.ReadOnlyField(source='paginator.num_pages')
class Meta:
object_serializer_class = SearchSerializer
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
这是Post序列化器:
class PostSerializer(serializers.ModelSerializer):
owner = UserSerializer(required=False, read_only=True)
category_edit = serializers.PrimaryKeyRelatedField(queryset=Category.objects.all(), write_only=True)
category = CategorySerializer(read_only=True)
price = serializers.CharField()
price_currency = serializers.CharField()
hitcount = serializers.SerializerMethodField()
images = ImageSerializer(many=True, read_only=True)
def get_hitcount(self, context):
# Content_type for Post is 20
c_type = ContentType.objects.get_for_model(context)
obj, created = HitCount.objects.get_or_create(content_type=c_type, object_pk=context.id)
data = {}
data["id"] = obj.pk
data["counter"] = obj.hits
return data
class Meta:
model = Post
fields = ('hitcount', 'id', 'content', 'owner', 'category', 'category_edit', 'images', 'price', 'price_currency')
如您所见,我能得到的最接近的方法是将 'object' 包装器重命名为 'postWrapper'。我想将它作为包装器完全删除,所以 'results' 中只有 Post 模型列表,其中包含 'hitcount'、'id'、'content'、 'owner' 等...
非常感谢任何帮助。提前致谢。
我认为只需使用 PostSerializer
,因为 object_serializer_class
中的 PaginatedPostSerializer
就是您想要的。
class PaginatedPostSerializer(pagination.PaginationSerializer):
class Meta:
object_serializer_class = PostSerializer
如果您想覆盖 to_representation
,您可以 扩展 PostSerializers
而不是将其作为新字段添加到新的序列化程序中。
p.s.: 如果你想将结果项包装在 postWrapper
中,你不需要覆盖 to_representation
函数,你可以在你的 SearchSerializer
:
class SearchSerializer(serializers.Serializer):
# object = PostSerializer()
# rename the object to what you want
postWrapper = PostSerializer()
我想我对你的查询集的样子有误解,所以做出上面的回答。
class SearchSerializer(serializers.Serializer):
object = PostSerializer()
def to_representation(self, instance):
res = super(SearchSerializer, self).to_representation(instance)
# pop of the object field, and push the fields inside the object to parent level
objectfield = res.pop('object', None)
if objectfield:
for field, value in objectfield.iteritems():
res[field] = value
return res
恕我直言,将您的查询集更改为 Post
模型查询集,并将 paginatedSerializer 的 object_serializer_class 设置为 PostSerializer
更有意义。
所以我将它添加到我的 PostSearch 视图中,它解决了我的问题:
ret = serializer.data
new_result_list = []
results = ret.get('results')
for orderedDict in results:
post = orderedDict.get('object')
new_result_list.append(post)
ret['results'] = new_result_list
基本上我创建了一个没有 'object' 包装器的新列表,然后将其放回 return 值。