如何覆盖 Django 序列化程序中的外键空值?
How to override foreign key null values in django serializer?
我正在使用 natural_keys 将查询集序列化为 json 格式。参考:docs
我能够成功序列化数据。如果有任何外键,那么我也可以添加它的对象而不是外键。例如:
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)
这将 return json:
{
"model": 'proj.child'
"pk": 1,
"fields": {
"name": "child name",
"parent": {"id": 1, "name": "parent name"}
}
}
到目前为止一切都很好。我的问题是,当父级外键在子级中为 null 时,它在父级中 returns None:
fields: {
"name": "child name",
"parent": None
}
我的期望是:
fields: {
"name": "child name",
"parent": {"id": None. "name": None}
}
如何将 None 值覆盖到另一个字典?
一种方法是遍历字典列表并对其进行编辑。但是,我觉得它不是最好的。
[编辑]
为了使我的设计更具体:
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
。但是,我没想到序列化数据中有外键。相反,我想要另一个序列化数据来代替 foreign key.So,我遇到了 get_natural_keys() 使用它我可以序列化外键对象。我可以自定义get_natural_keys()
到return一个序列化数据。
在上面的建筑模型中,residing_by
在某个时间点可以为空。对于序列化数据中的 null 值,我想用另一个字典覆盖 null,例如 {'id': None, 'name': None}
.
当我遇到类似的问题时,类似的方法有效:
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-framework serializers。
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..
]
"""
您的设置存在一些问题:
- 自然键的全部意义在于避免自动生成数据,例如自动递增主键,以便您可以识别其他数据库(生产、登台)中的记录,这些数据库可能具有不同的插入顺序。相反,您 return 一个 自动生成的 主键作为 自然键 。
- 您似乎希望将序列化框架用于并非专为某些目的而设计的东西,或者 Django REST Framework 等其他软件包做得更好。
- 您的模型不适合自然键,因为它们只有一个字段并且不是唯一的,所以不使用主键就无法引用记录。
- 最后,我不明白为什么您需要自然键开始。是什么让你决定这样做?
This is the scenario where child table is not willing to refer for parent table
我不确定那是什么意思。你 link child 到 parent 或者你不。它们不是真正的 children,应该服从您的编程:)。如果需要parent,那么not 将null=True 添加到外键,这样它就会抛出一个错误,然后你就知道你的编程问题在哪里了。
总而言之,我认为您对事情的运作方式以及解决方法做出了一些假设,但您选择的解决方案并不合适。
如前所述,您应该首先弄清楚为什么 children 可以在没有 parents 的情况下创建,如果这不是您想要的并修复它。然后 re-evaluate 序列化应该如何工作,因为在自然键中粘贴自动 ID 是没有意义的。您可能不需要自然键。如果您这样做是为了更改输出格式,那么正如其他人所建议的那样,DRF 为您提供了更好的选择,但它也伴随着陡峭的学习曲线。
我正在使用 natural_keys 将查询集序列化为 json 格式。参考:docs
我能够成功序列化数据。如果有任何外键,那么我也可以添加它的对象而不是外键。例如:
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)
这将 return json:
{
"model": 'proj.child'
"pk": 1,
"fields": {
"name": "child name",
"parent": {"id": 1, "name": "parent name"}
}
}
到目前为止一切都很好。我的问题是,当父级外键在子级中为 null 时,它在父级中 returns None:
fields: {
"name": "child name",
"parent": None
}
我的期望是:
fields: {
"name": "child name",
"parent": {"id": None. "name": None}
}
如何将 None 值覆盖到另一个字典? 一种方法是遍历字典列表并对其进行编辑。但是,我觉得它不是最好的。
[编辑]
为了使我的设计更具体:
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
。但是,我没想到序列化数据中有外键。相反,我想要另一个序列化数据来代替 foreign key.So,我遇到了 get_natural_keys() 使用它我可以序列化外键对象。我可以自定义get_natural_keys()
到return一个序列化数据。
在上面的建筑模型中,residing_by
在某个时间点可以为空。对于序列化数据中的 null 值,我想用另一个字典覆盖 null,例如 {'id': None, 'name': None}
.
当我遇到类似的问题时,类似的方法有效:
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-framework serializers。
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..
]
"""
您的设置存在一些问题:
- 自然键的全部意义在于避免自动生成数据,例如自动递增主键,以便您可以识别其他数据库(生产、登台)中的记录,这些数据库可能具有不同的插入顺序。相反,您 return 一个 自动生成的 主键作为 自然键 。
- 您似乎希望将序列化框架用于并非专为某些目的而设计的东西,或者 Django REST Framework 等其他软件包做得更好。
- 您的模型不适合自然键,因为它们只有一个字段并且不是唯一的,所以不使用主键就无法引用记录。
- 最后,我不明白为什么您需要自然键开始。是什么让你决定这样做?
This is the scenario where child table is not willing to refer for parent table
我不确定那是什么意思。你 link child 到 parent 或者你不。它们不是真正的 children,应该服从您的编程:)。如果需要parent,那么not 将null=True 添加到外键,这样它就会抛出一个错误,然后你就知道你的编程问题在哪里了。
总而言之,我认为您对事情的运作方式以及解决方法做出了一些假设,但您选择的解决方案并不合适。
如前所述,您应该首先弄清楚为什么 children 可以在没有 parents 的情况下创建,如果这不是您想要的并修复它。然后 re-evaluate 序列化应该如何工作,因为在自然键中粘贴自动 ID 是没有意义的。您可能不需要自然键。如果您这样做是为了更改输出格式,那么正如其他人所建议的那样,DRF 为您提供了更好的选择,但它也伴随着陡峭的学习曲线。