首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Django Rest框架序列化多个生成序列化关系的NoneType实例

Django Rest框架序列化多个生成序列化关系的NoneType实例
EN

Stack Overflow用户
提问于 2016-05-30 09:05:17
回答 2查看 1.3K关注 0票数 3

我对Django Rest框架非常陌生,我一直试图为我的一个模型编写一个序列化程序。对于我的项目,我打算根据json标准输出JSON结果,为此,我使用了SerializerMethodField,其中我按如下方式调用了get_data()方法:

models.py

代码语言:javascript
复制
class Level(MPTTModel):
    name = models.CharField(max_length=100)
    parent = TreeForeignKey('self', null=True, blank=True, related_name='children', db_index=True)

    class MPTTMeta:
        order_insertion_by = ['name']


class Group(models.Model):
    name = models.CharField(max_length=100)
    level_set = models.ManyToManyField(Level, blank=True)

serializers.py

代码语言:javascript
复制
class LevelSerializer(serializers.ModelSerializer):
    data = serializers.SerializerMethodField()

    class Meta:
        model = Level
        fields = ('data',)

    def get_data(self, instance):
        return {
            "type": "Level",
            "uuid": instance.id_key(),
            "attributes": {
                "name": instance.name,
            },
            "relationships": {
                "children": self.get_children_recursive(),
            },
        }

    def get_children_recursive(self, child=None):
        """
        Generates a tree of levels structured according to JSON API standards.
        """
        if not child:
            children = self.instance.get_children()
            level = self.instance
        else:
            children = child.get_children()
            level = child
        tree = {
            'data': {
                'type': 'Level',
                'uuid': level.id_key(),
                'attributes': {
                    'name': level.name,
                },
                'relationships': {
                    'children': [],
                    'parents': [],
                }
            }
        }
        for child in children:
            tree['data']['relationships']['children'].append(self.get_children_recursive(child))
        return tree

class GroupSerializer(serializers.ModelSerializer):
    root_level_set = LevelSerializer(many=True)

    class Meta:
        model = Group
        fields = ('id_key', 'name', 'root_level_set')

奇怪的是,如果我转到shell并尝试序列化一个级别的实例,它会很好地工作,但是尝试序列化一个组会在get_children_recursive()上给我一个错误,这与if not child statement所说的'NoneType' object has no attribute 'get_children'是一致的。产出如下:

运行:

代码语言:javascript
复制
from core.serializers import LevelSerializer
from core.models import Level
lvl = Level.objects.all()[0]
serializer = LevelSerializer(lvl)
print(serializer.data)

根据我按照JSON标准设计的JSON结构,输出嵌套级别及其子级别。

不过,如果我跑:

代码语言:javascript
复制
from core.serializers import GroupSerializer
from core.models import Group
grp = Group.objects.all()[0]
serializer = GroupSerializer(grp)
print(serializer.data)

产出:

代码语言:javascript
复制
Traceback (most recent call last):
  File "<console>", line 1, in <module>
  File "/home/maumau/.virtualenvs/olist/lib/python3.5/site-packages/rest_framework/serializers.py", line 503, in data
    ret = super(Serializer, self).data
  File "/home/maumau/.virtualenvs/olist/lib/python3.5/site-packages/rest_framework/serializers.py", line 239, in data
    self._data = self.to_representation(self.instance)
  File "/home/maumau/.virtualenvs/olist/lib/python3.5/site-packages/rest_framework/serializers.py", line 472, in to_representation
    ret[field.field_name] = field.to_representation(attribute)
  File "/home/maumau/.virtualenvs/olist/lib/python3.5/site-packages/rest_framework/serializers.py", line 614, in to_representation
    self.child.to_representation(item) for item in iterable
  File "/home/maumau/.virtualenvs/olist/lib/python3.5/site-packages/rest_framework/serializers.py", line 614, in <listcomp>
    self.child.to_representation(item) for item in iterable
  File "/home/maumau/.virtualenvs/olist/lib/python3.5/site-packages/rest_framework/serializers.py", line 472, in to_representation
    ret[field.field_name] = field.to_representation(attribute)
  File "/home/maumau/.virtualenvs/olist/lib/python3.5/site-packages/rest_framework/fields.py", line 1653, in to_representation
    return method(value)
  File "/mnt/SHARED-DRIVE/Workspace/interview-tests/work-at-olist/core/serializers.py", line 20, in get_data
    "children": self.get_children_recursive(),
  File "/mnt/SHARED-DRIVE/Workspace/interview-tests/work-at-olist/core/serializers.py", line 29, in get_children_recursive
    children = self.instance.get_children()
AttributeError: 'NoneType' object has no attribute 'get_children'

对我来说,自我的级别序列化拥有属性实例集,而调用级别序列化的Group序列化也不具有属性实例集,这似乎没有任何意义。有线索吗?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2016-06-04 05:51:15

为什么要自己设计所有的东西?让djrf做一些魔术:)

代码语言:javascript
复制
class LevelSerializer(serializers.ModelSerializer):
    type = serializers.SerializerMethodField()
    attributes = serializers.SerializerMethodField()
    relationships = serializers.SerializerMethodField()

    def get_type(self, instance):
        return "Level"

    def get_attributes(self, instance):
        return {
            "name": instance.name
        }

    def get_relationships(self, instance):
        return {
            "children": self.__class__(instance.get_children(), many=True).data,
            "parents": []
        }

    class Meta:
        model = Level
        fields = ('type', 'attributes', 'relationships')


class GroupSerializer(serializers.ModelSerializer):
    level_set = LevelSerializer(many=True)

    class Meta:
        model = Group
        fields = ('name', 'level_set')

为什么您的代码不工作?因为错误的代码:

  1. 看看在这2种情况下调用LevelSerializer有什么不同??一个参数- many=True;当many=True -序列化程序没有instance属性时。
  2. 在(1)旁边,get_children_recursive的第一次运行将复制第一个元素作为第一个子元素
  3. 使用您的方法,您根本不需要ModelSerializer,因为所有操作都是手动完成的--在这种情况下,简单的Serializer会更好。
  4. 通过创建虚拟data字段--使代码变得更加复杂,为什么不直接使用数据来避免使用一个data键的字典?

我的示例代码缺少id_key字段--您没有在这里记录它,但是添加它应该是一次狂风。

使用额外的模块rest_framework_recursive,可以简化代码:

代码语言:javascript
复制
from rest_framework_recursive.fields import RecursiveField


class LevelSerializer(serializers.ModelSerializer):
    type = serializers.SerializerMethodField()
    children = serializers.ListField(child=RecursiveField(), source='get_children')

    def get_type(self, instance):
        return "Level"

    class Meta:
        model = Level
        fields = ('type', 'name', 'children')
票数 1
EN

Stack Overflow用户

发布于 2016-05-30 14:01:44

序列化的属性名:root_level_set。模型:level_set.

DRF试图在组中找到属性root_level_set,但没有找到它,并将其替换为None。这就是为什么你会犯这样的错误。

修正:

  1. 在序列化程序中重命名root_level_set -> level_set
  2. 或将source添加到字段:root_level_set = LevelSerializer(source='level_set', many=True)
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/37521708

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档