如何在django序列化程序中重写外键null值



我正在使用natural_keys将查询集序列化为json格式。参考:文档

我能够成功地序列化数据。如果有任何外键,那么我也可以添加它的对象而不是外键。例如:

class Parent(models.Model):
name = models.CharField()
def get_natural_keys(self):
return(
{'name': self.name, 'pk': self.pk}
)
class Child(models.Model):
name = models.CharField()
parent = models.ForeignKey(Parent, null=True)

查询数据时:

child = serializers.serialize('json', list(Child.objects.all()), user_natural_foreign_keys=True, use_natural_primary_keys=True)

这将返回json:

{
"model": 'proj.child'
"pk": 1,
"fields": {
"name": "child name",
"parent": {"id": 1, "name": "parent name"}
}
}

到目前为止,一切都很好。我的问题是,当父外键在子项中为null时,它在父项中返回None:

fields: {
"name": "child name",
"parent": None
}

我的期望是:

fields: {
"name": "child name",
"parent": {"id": None. "name": None}
}

如何将None值覆盖到另一个字典?一种方法是循环浏览字典列表并对其进行编辑。但是,我觉得这不是最好的方法。

[EDIT]

让我的设计更具体:

class Person(models.Model):
name = models.CharField()
phone = models.CharField()

class Building(modls.Model):
name = models.CharField()
address = models.CharField()
build_by = models.ForeignKey(Person, null=False)
owner = models.ForeignKey(Person)
residing_by = models.ForeignKey(Person, null=True)

首先,我尝试序列化building对象,它在序列化的数据中有foreign keys。但是,我不希望在序列化数据中出现外键。相反,我想要另一个序列化的数据来代替外键。因此,我发现了get_natural_keys((,使用它可以序列化外键对象。我可以自定义get_natural_keys()以返回序列化的数据。

在上面的构建模型中,residing_by在某个时间点可以为空。对于序列化数据中的null值,我想用另一个字典(如{'id': None, 'name': None}(覆盖null。

您的设置有几个问题:

  • 自然密钥的全部目的是避免自动生成数据,如自动递增主键,这样您就可以在其他数据库(生产、暂存(中识别记录,这些数据库可能有不同的插入顺序。相反,您返回一个自动生成的主键作为自然键
  • 您似乎希望将序列化框架用于它不适合的东西,或者像Django REST framework这样的其他包做得更好
  • 您的模型不适合使用自然键,因为它们只有一个字段,而且它不是唯一的,所以如果不使用主键,就无法引用记录
  • 最后,我不明白为什么你一开始就需要自然的钥匙。是什么让你决定这么做的

这是子表不愿意引用父表的情况

我不知道这意味着什么。您将孩子链接到父对象,或者不链接。他们不是真正的孩子,应该遵守你的程序:(。如果父项是必需的,那么请执行而不是将null=True添加到外键,这样它就会抛出错误,然后您就知道编程问题在哪里。

总而言之,我认为你对事情如何运作以及如何解决这些问题做了一些假设,但你选择的解决方案并不合适。

正如所说,你应该首先弄清楚为什么孩子可以在没有父母的情况下出生,如果这不是你想要的,并解决这个问题。然后重新评估序列化应该如何工作,因为在自然键中粘贴自动id毫无意义。您可能不需要自然键。如果你这样做是为了改变输出格式,那么正如其他人所建议的那样,DRF给了你更好的选择,但它也有一个陡峭的学习曲线。

当我遇到类似的问题时,类似的东西起了作用:

class Chield(models.Model):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
if not self.parent:
self.parent = Parent()
name = models.CharField()
parent = models.ForeignKey(Parent, null=True)

对于此类用例,我建议使用django-rest框架序列化程序。


from .models import Parent, Child
from rest_framework import serializers
### Define Serializers
class ParentSerializer(serializers.ModelSerializer):
class Meta:
model = Parent
fields = ['id', 'name']

class ChildSerializer(serializers.ModelSerializer):
parent = ParentSerializer()

class Meta:
model = Child
fields = ['id', 'name', 'parent']

def to_representation(self, instance):
# get representation from ModelSerializer
ret = super(ChildSerializer, self).to_representation(instance)
# if parent is None, overwrite
if not ret.get("parent", None):
ret["parent"] = {"id": None, "name": None}
return ret


### example serialization
childs = ChildSerializer(Child.objects.all(), many=True)
print(childs.data)
"""
Output:
[
{
"id": 1,
"name": "example child name",
"parent": {
"id": 1,
"name": "example parent name"
}
},
#...snip..
]
"""

最新更新