以下是我的代码:
class File(MPTTModel):
name=models.CharField(max_length=36, primary_key=True)
parent = TreeForeignKey('self', null=True, blank=True, related_name='children', db_index=True)
num=models.IntegerField(null=True)
class MPTTMeta:
order_insertion_by = ['name']
我尝试使用以下代码序列化此类:
class RecursiveField(serializers.Serializer):
def to_representation(self, value):
serializer = self.parent.parent.__class__(value, context=self.context)
return serializer.data
class FileSerializer(serializers.ModelSerializer):
parent=RecursiveField(many=True)
class Meta:
model = File
fields=('name','num','parent')
但是我失败了,因为我只能输出这棵树的根节点的内容。似乎序列化程序无法访问根的子节点,而且孩子的子节点...... 具体问题是在输出中,'parent'显示为'null',但实际上它有4个子节点,每个子节点包含几个后代。 我的代码出了什么问题? 谢谢大家的帮助!
答案 0 :(得分:4)
没有任何关于MPTT和REST框架的魔力。
MPTT 会在您的模块中添加新字段,以便实施a nested set model。它还跟踪从子节点到其父节点的向上链接,它用于某些优化,并且如果它被破坏,则重建嵌套集树。
基本上,您的模型包含您手动添加的以下字段name
/ num
,您为触发MPTT添加的parent
以及以下自动字段:
tree_id
:树标识符。连接到同一根的所有节点共享相同的tree_id
。level
:树中节点的深度。lft
/ rght
:嵌套集索引。请参阅上面的链接,但基本思路是节点是另一个节点的后代,如果其lft
是greate或相等且其rght
低于或等于另一个节点的节点。REST框架不是mptt-aware,也不需要。它只会看到一个包含7个字段的常规模型,它很乐意序列化。
虽然可能实现了一个递归序列化器来塑造对象对象的对象的嵌套对象中的序列化表示,但此时通常不是一个好主意。
现在,如果你真的想这样做,你需要以另一种方式去做。您必须序列化根节点,并确保它们的序列化表示形式递归地包含它们的所有子节点。不是相反,就像你在这里试过的那样。
这个想法是构建这样的东西:
class FileSerializer(serializers.ModelSerializer):
children = FileSerializer(many=True)
class Meta:
model = File
fields=('name','num')
但你不能这样做,因为FileSerializer
没有在你想要的地方定义。您可以尝试覆盖构造函数并在其中插入其他序列化程序,如下所示:
class FileSerializer(serializers.ModelSerializer):
class Meta:
model = File
fields=('name','num')
def get_fields(self):
fields = super(FileSerializer, self).get_fields()
fields['children'] = FileSerializer(many=True)
return fields
未经测试,但你明白了。
<强>然而强>:
怎么样你只是序列化扁平节点,如果真的需要在客户端重建对象树?
[{'id': 1, 'name': 'foo', 'parent': null}, // /foo
{'id': 2, 'name': 'bar1', 'parent': 1}, // /foo/bar1
{'id': 3, 'name': 'bar2', 'parent': 1}, // /foo/bar2
{'id': 4, 'name': 'foo2', 'parent': null}, // /foo2
{'id': 5, 'name': 'baz1', 'parent': 4}, // /foo2/baz1
{'id': 6, 'name': 'baz2', 'parent': 4}] // /foo2/baz2