Reputation: 807
I'm serializing a query set to json format using natural_keys. Reference: docs
I'm able to serialize data successfully. In case, there are any foreign keys, then I'm also able to add it's object instead of foreign key. For example:
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)
And while querying data:
child = serializers.serialize('json', list(Child.objects.all()), user_natural_foreign_keys=True, use_natural_primary_keys=True)
This will return json:
{
"model": 'proj.child'
"pk": 1,
"fields": {
"name": "child name",
"parent": {"id": 1, "name": "parent name"}
}
}
Till this point every thing is fine. My issue is that when parent foreign key is null in child, it returns None in parent:
fields: {
"name": "child name",
"parent": None
}
How I am expecting is:
fields: {
"name": "child name",
"parent": {"id": None. "name": None}
}
How can I override the None value to another dictionary? One way is to loop through the list of dictionaries and edit it. But, I don't feel it as best one.
[EDIT]
To make my design more specific:
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)
Firstly, I tried to serialize building
object and it had foreign keys
in serialized data. However, I was not expecting foreign keys in serialized data. Instead, I want another serialized data in place of foreign key.So, I came across get_natural_keys() using which I can serialize foreign key objects. I can customise get_natural_keys()
to return a serialized data.
In the above building model, residing_by
can be null at some point of time. For that null value in serialized data, I wanted to overwrite null with another dictionary like {'id': None, 'name': None}
.
Upvotes: 1
Views: 1570
Reputation:
There's a few issues with your setup:
This is the scenario where child table is not willing to refer for parent table
I'm not sure what that means. You link the child to the parent or you don't. They're not real children and should obey what you program :). If the parent is required, then do not add null=True to the foreign key so that it throws an error and then you know where your programming problem is.
All in all, I think you made a few assumptions about how things work and how you could solve them, but the solutions you've chosen are not the right fit.
As said, you should first figure out why children can be created without parents, if that is not what you want and fix that. Then re-evaluate how serialization should work, because sticking auto ids in natural keys makes no sense. You probably don't need natural keys. If you did this to change the output format, then as others have suggested, DRF gives you better options, but it also comes with a steep learning curve.
Upvotes: 4
Reputation: 1068
I'd recommend using django-rest-framework serializers for such use cases.
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..
]
"""
Upvotes: 1
Reputation: 389
When I had a similar issue for me something like that worked:
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)
Upvotes: 1