【问题标题】:Get rid of "object" wrapper in django rest framework serialized SearchQuerySet摆脱 django rest 框架序列化 SearchQuerySet 中的“对象”包装器
【发布时间】:2015-03-10 16:47:16
【问题描述】:

我用 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

这里是 PostSerializer:

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”。我想将其作为包装器完全删除,因此“结果”内只有 Post 模型列表,其中包含“hitcount”、“id”、“内容”、“所有者”等...

非常感谢任何帮助。提前致谢。

【问题讨论】:

  • 你需要的输出到底是什么,这个很不清楚。

标签: django-rest-framework django-haystack


【解决方案1】:

我认为在你的PaginatedPostSerializer 中使用PostSerializer 作为你的object_serializer_class 就是你想要的。

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 模型查询集,并将分页序列化器的object_serializer_class 设置为PostSerializer 更有意义。

【讨论】:

  • 感谢您的评论!如果将 PostSerializer 设置为 object_serializer_class 我得到 'NoneType' object has no attribute 'concrete_model' 错误。第二个建议只导致空 postWrapper 对象的数组。很遗憾。(
  • @NBayaman 我为我的答案添加了一个新的解决方案......无论如何,我无法找出“NoneType”对象没有属性“concrete_model”错误的原因......
  • 请查看我的解决方案。到目前为止,它解决了我的问题。
【解决方案2】:

所以我将它添加到我的 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

基本上,我创建了一个没有“对象”包装器的新列表并将其放回返回值。

【讨论】:

    猜你喜欢
    • 2021-07-20
    • 1970-01-01
    • 2015-02-25
    • 1970-01-01
    • 2015-06-29
    • 1970-01-01
    • 2020-03-22
    • 2015-10-29
    • 2020-05-08
    相关资源
    最近更新 更多