【问题标题】:Serializing context on Django CBV?在 Django CBV 上序列化上下文?
【发布时间】:2020-08-13 10:05:28
【问题描述】:

我在序列化第 3 方包 (django-organizations) 时遇到问题,因为我想以 JSON 格式接收上下文。

类本身如下所示:

class OrganizationUserMixin(OrganizationMixin, JSONResponseMixin):
    """Mixin used like a SingleObjectMixin to fetch an organization user"""

    user_model = OrganizationUser
    org_user_context_name = 'organization_user'

    def get_user_model(self):
        return self.user_model

    def get_context_data(self, **kwargs):
        kwargs = super(OrganizationUserMixin, self).get_context_data(**kwargs)
        kwargs.update({self.org_user_context_name: self.object,
            self.org_context_name: self.object.organization})
        return kwargs

    def get_object(self):
        """ Returns the OrganizationUser object based on the primary keys for both
        the organization and the organization user.
        """
        if hasattr(self, 'organization_user'):
            return self.organization_user
        organization_pk = self.kwargs.get('organization_pk', None)
        user_pk = self.kwargs.get('user_pk', None)
        self.organization_user = get_object_or_404(
                self.get_user_model().objects.select_related(),
                user__pk=user_pk, organization__pk=organization_pk)
        return self.organization_user

我正在尝试将此自定义 JSONResponseMixin 传递给我的 OrganizationUserMixin 类:

class JSONResponseMixin:
    """
    A mixin that can be used to render a JSON response.
    """
    def render_to_json_response(self, context, **response_kwargs):
        """
        Returns a JSON response, transforming 'context' to make the payload.
        """
        return JsonResponse(
            self.get_data(context),
            **response_kwargs
        )

    def get_data(self, context):
        print(context)
        return context

然后像这样覆盖OrganizationUserMixin 中的render_to_response

def render_to_response(self, context, **response_kwargs):
    return self.render_to_json_response(context, **response_kwargs)

如果我打印context

看起来像这样

# {
# 'object': <OrganizationUser: Erik (MyOrgName)>, 
# 'organizationuser': <OrganizationUser: Erik (MyOrgName)>, 
# 'organization': <Organization: MyOrgName>, 
# 'view': <organizations.views.OrganizationUserDetail object at 0x1091a3ac0>, 
# 'organization_user': <OrganizationUser: Erik (MyOrgName)>
# }

我得到的错误信息是TypeError: Object of type OrganizationUser is not JSON serializable

如何在我的 JSONResponseMixin 中序列化 context

【问题讨论】:

  • 您希望从序列化中得到什么数据?是模型的__unicode__() 值吗?然后您可以检查上下文字典中每个值的类型,如果它是一个对象,请将其替换为__unicode__() 的调用。话虽如此,您在这里最需要的可能是使用序列化程序并定义要序列化程序的字段,通用 JsonResponseMixin 是不够的。
  • 我希望将上下文中的数据转换为 JSON 格式,例如 'organization_user': &lt;OrganizationUser: Erik (MyOrgName)&gt;,这样我就可以在页面上做一些 AJAX 而不是使用常规模板视图
  • 您评论中的&lt;&gt; 表明这是一个python 对象,您不能在Json 中有python 对象。你的意思是字符串OrganizationUser: Erik (MyOrgName)
  • 是的,实际的对象就是我想要 JSONify 的对象
  • 好的,我现在明白了,查看我刚刚发布的答案,如果您还有其他问题,请告诉我

标签: django django-class-based-views django-serializer


【解决方案1】:

您有两个选择,要么使用Django rest framework (DRF),要么实现为模型执行序列化的函数。

选项 1

随着您应用程序的 API 方面的发展,DRF 是一种更可持续的解决方案,因为它会抽象大部分反序列化工作,并为您提供许多其他有用的功能,例如路由器、视图集等。

示例代码

# serializers.py
from rest_framework import serializers

class OrganizationUserSerializer(serializers.ModelSerializer):
    class Meta:
        model = OrganizationUser
        fields = '__all__'


# views.py
from rest_framework import generics

class OrganizationUser(generics.RetrieveModelMixin):
    queryset = OrganizationUser.objects.all()
    serializer_class = OrganizationUserSerializer

选项 2

话虽如此,如果您的JsonResponseMixin 足以满足您的大部分需求,并且您的应用程序并不主要依赖于 API,那么您只需为您的模型添加序列化函数并在您的 @ 中调用它们即可摆脱困境987654326@

示例代码:

# Models.py
class OrganizationUser(models.Model):
    ...

    def to_json(self):
        # assuming you have a field name and organization
        return {"name": self.name, "organization": self.organization.to_json()}

# mixins.py
class JSONResponseMixin:
    """
    A mixin that can be used to render a JSON response.
    """
    def render_to_json_response(self, context, **response_kwargs):
        """
        Returns a JSON response, transforming 'context' to make the payload.
        """
        return JsonResponse(
            self.get_data(context),
            **response_kwargs
        )

    def get_data(self, context):
        data = {}
        for key, val in context:
            if hasattr(val, "to_json"):
                data[key] = val.to_json()
            else:
                data[key] = val
        return data

【讨论】:

  • 非常感谢您的反馈。我还认为合并 DRF 会更有意义 - 使用这些第三方软件包是一个真正的兔子洞。你能告诉我使用 DRF 会是什么样子吗?我尝试更改OrganizationUserMixin 类中的get_object() 方法:gist.github.com/erikvlm/c7c1b30f04c22c6a5370b2cf872cd8bf 但我只收到AttributeError: 'Response' object has no attribute 'organization' 错误。我错过了什么吗?
  • 我需要以某种方式将 DRF 中的 APIView 合并到我的 OrganizationUserMixin 类中,还是使用 DRF 提供的 retrieve 方法?
  • 是的,为 JSON 响应设置一个不同的类可能是最简单的,例如,结帐:django-rest-framework.org/api-guide/views
  • 是的,我确实做到了 - 感谢您的帮助。如果您想修改答案,我会将其标记为已完成。我创建了一个新的 Serializer Class 并继承了基本的组织类
  • 乐于助人。我更新了我的答案,因此您可以将其标记为完成。
猜你喜欢
  • 2018-04-04
  • 2023-04-04
  • 1970-01-01
  • 2016-09-13
  • 2015-08-14
  • 2017-01-30
  • 2015-12-20
  • 1970-01-01
  • 2016-09-25
相关资源
最近更新 更多