I am running a django app using REST to send data to my API.
I have a network that contains many projects and a project can belong to many networks.
I want to send this dataset via requests:
payload = {
"name": "my great testnetwork",
"type_network": "xyz",
"projects" : [
{
"project_name": "Brasil",
},
{
"project_name": "Sweden",
},
],
"creation_date": "2020-05-15T15:57:27.399455Z"
}
I do not want to create the project_names, they are already in the database. I only want this to work like a normal FK, where I specify the project_name and it shows in my API. It should only relate them.
What happens now is that the project list remains empty when I send it like this
This is what I get:
{
"id": 6,
"name": "my great test",
"type_network": "xyz",
"projects": [],
"creation_date": "2020-05-15T19:00:05.947542Z"
}
But I need the projects in the list.
My serializer looks like this:
class NetworkSerializer(serializers.ModelSerializer):
"""Serializer for Network.
Add extra field buildings from NestedProjectSerializer.
"""
projects = NestedProjectSerializer(
many=True,
read_only=True,
help_text="Many to many relation. Project instances expected."
)
class Meta:
model = Network
fields = (
'id',
'name',
'projects',
'creation_date',
)
Ok so I tried to overwrite the create method for writable nested serializers, but I think I don't need this, right? Because I don't want to create new objects. Then I also tried to use the PrimaryKeyRelatedField
, but i get either the error that pk is not valid
(when passing a queryset) or it doens't show the projects (when using read-only=True).
I am a bit stuck here. Can someone lend me a hand? Thanks so much for your time and help. Appreciated very much!
I am happy to provide more code or clarifications if needed.
My models:
class Project(models.Model):
project_name = models.CharField(max_length=120, primary_key=True, unique=True)
location = models.CharField(max_length=120, null=True, blank=True)
class Network(models.Model):
name = models.CharField(
max_length=120,
null=True,
blank=True,
help_text="Name of network. String expected."
)
projects = models.ManyToManyField(
Project,
default=None,
blank=True,
help_text="Many to many relation. Project instances expected."
)
creation_date = models.DateTimeField(
auto_now=True
)
I'm getting the feeling that I have to overwrite the create method... the project_name is the pk btw.
EDIT: Sending data like this:
payload = {
"name": "my great testnetwork",
# "projects" : [
# {
# "project_name": "frankfurt",
# }
# ],
"projects_data" : [
{
"project_name": "Brasil",
}
],
"creation_date": "2020-05-15T15:57:27.399455Z"
}
r = requests.request('post', 'http://localhost:8000/myendpoint', json=payload, headers=headers)
print(r.text)
print(r.status_code)
You will need to update your code to as below:
from rest_framework import serializers
class NetworkSerializer(serializers.ModelSerializer):
"""Serializer for Network.
Add extra field buildings from NestedProjectSerializer.
"""
projects_data = serializers.SerializerMethodField()
class Meta:
model = Network
fields = (
'id',
'name',
'projects',
'projects_data',
'creation_date',
)
def get_projects_data(self, obj):
projects = obj.projects.all()
return NestedProjectSerializer(projects, many=True).data
I hope this helps..!!
If you define a nested serializer, you will always be stuck while creating the records. Since create method needs a Serialized data from your project serializer
Ref: https://www.django-rest-framework.org/api-guide/fields/#serializermethodfield
Edit: New Serializer
from rest_framework import serializers
class NetworkSerializer(serializers.ModelSerializer):
"""Serializer for Network.
Add extra field buildings from NestedProjectSerializer.
"""
projects = NestedProjectSerializer(many=True, required=False)
class Meta:
model = Network
fields = (
'id',
'name',
'projects',
'projects_data',
'creation_date',
)
def create(self, validated_data):
projects = validated_data.pop("projects")
network_obj = Network.objects.create(**validated_data)
for project in projects:
network_obj.projects.add(Project.objects.create(**project))
network_obj.save()
return network_obj
I have overrides the create method as per your requirements