I want to implement my own create function on my serializer but I'm getting the following error:
TypeError: Direct assignment to the reverse side of a related set is prohibited. Use lines.set() instead.
Internal Server Error: /api/cheatsheets/
Traceback (most recent call last):
File "/home/christian-sama/Code/cheatsheet-app/venv/lib/python3.10/site-packages/django/core/handlers/exception.py", line 55, in inner
response = get_response(request)
File "/home/christian-sama/Code/cheatsheet-app/venv/lib/python3.10/site-packages/django/core/handlers/base.py", line 197, in _get_response
response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "/home/christian-sama/Code/cheatsheet-app/venv/lib/python3.10/site-packages/django/views/decorators/csrf.py", line 54, in wrapped_view
return view_func(*args, **kwargs)
File "/home/christian-sama/Code/cheatsheet-app/venv/lib/python3.10/site-packages/rest_framework/viewsets.py", line 125, in view
return self.dispatch(request, *args, **kwargs)
File "/home/christian-sama/Code/cheatsheet-app/venv/lib/python3.10/site-packages/rest_framework/views.py", line 509, in dispatch
response = self.handle_exception(exc)
File "/home/christian-sama/Code/cheatsheet-app/venv/lib/python3.10/site-packages/rest_framework/views.py", line 469, in handle_exception
self.raise_uncaught_exception(exc)
File "/home/christian-sama/Code/cheatsheet-app/venv/lib/python3.10/site-packages/rest_framework/views.py", line 480, in raise_uncaught_exception
raise exc
File "/home/christian-sama/Code/cheatsheet-app/venv/lib/python3.10/site-packages/rest_framework/views.py", line 506, in dispatch
response = handler(request, *args, **kwargs)
File "/home/christian-sama/Code/cheatsheet-app/venv/lib/python3.10/site-packages/rest_framework/mixins.py", line 19, in create
self.perform_create(serializer)
File "/home/christian-sama/Code/cheatsheet-app/venv/lib/python3.10/site-packages/rest_framework/mixins.py", line 24, in perform_create
serializer.save()
File "/home/christian-sama/Code/cheatsheet-app/venv/lib/python3.10/site-packages/rest_framework/serializers.py", line 212, in save
self.instance = self.create(validated_data)
File "/home/christian-sama/Code/cheatsheet-app/api/serializers.py", line 35, in create
Section.objects.create(cheatsheet=cheatsheet, **section)
File "/home/christian-sama/Code/cheatsheet-app/venv/lib/python3.10/site-packages/django/db/models/manager.py", line 85, in manager_method
return getattr(self.get_queryset(), name)(*args, **kwargs)
File "/home/christian-sama/Code/cheatsheet-app/venv/lib/python3.10/site-packages/django/db/models/query.py", line 669, in create
obj = self.model(**kwargs)
File "/home/christian-sama/Code/cheatsheet-app/venv/lib/python3.10/site-packages/django/db/models/base.py", line 562, in __init__
_setattr(self, prop, value)
File "/home/christian-sama/Code/cheatsheet-app/venv/lib/python3.10/site-packages/django/db/models/fields/related_descriptors.py", line 595, in __set__
raise TypeError(
TypeError: Direct assignment to the reverse side of a related set is prohibited. Use lines.set() instead.
My models.py
from django.db import models
class Cheatsheet(models.Model):
title = models.CharField(max_length=500)
description = models.CharField(max_length=500)
score = models.IntegerField()
def __str__(self):
return self.title
class Section(models.Model):
title = models.CharField(max_length=500)
description = models.CharField(max_length=500)
cheatsheet = models.ForeignKey(Cheatsheet, on_delete=models.CASCADE, related_name='sections', null=True, blank=True)
def __str__(self):
return self.title
class Line(models.Model):
description = models.CharField(max_length=500)
snippet = models.CharField(max_length=500)
section = models.ForeignKey(Section, on_delete=models.CASCADE, related_name='lines', null=True, blank=True)
def __str__(self):
return self.description
My serializers.py
from rest_framework import serializers
from .models import Cheatsheet, Section, Line
class LineSerializer(serializers.ModelSerializer):
class Meta:
model = Line
fields = "__all__"
class SectionSerializer(serializers.ModelSerializer):
lines = LineSerializer(many=True)
class Meta:
model = Section
fields = "__all__"
def create(self, validated_data):
lines_data = validated_data.pop('lines')
section = Section.objects.create(**validated_data)
for line in lines_data:
Line.objects.create(section=section, **line)
return section
class CheatsheetSerializer(serializers.ModelSerializer):
sections = SectionSerializer(many=True)
class Meta:
model = Cheatsheet
fields = "__all__"
def create(self, validated_data):
sections_data = validated_data.pop('sections')
print(sections_data)
cheatsheet = Cheatsheet.objects.create(**validated_data)
print(cheatsheet)
for section in sections_data:
Section.objects.create(cheatsheet=cheatsheet, **section)
return cheatsheet
My views.py
from api.serializers import CheatsheetSerializer
from .models import Cheatsheet
from rest_framework import viewsets
class CheatsheetViewSet(viewsets.ModelViewSet):
queryset = Cheatsheet.objects.all()
serializer_class = CheatsheetSerializer
And this is the json I'm sending in the request:
{
"title": "Cheatsheet title",
"description": "Cheatsheet description",
"score": 24,
"sections": [
{
"title": "Section title",
"description": "Section description",
"lines": [
{
"description": "Line description",
"snippet": "line snippet"
},
{
"description": "Line description2",
"snippet": "line snippet2"
}
]
}
]
}
I've been following this tutorial but can't figure out why my code is failing. Other answers suggest using set() instead of get(), but I don't think that's my case.
CodePudding user response:
The way you handled line data in SectionSerializer
needs to also be done on CheatsheetSerializer
, so something like:
class CheatsheetSerializer(serializers.ModelSerializer):
# ...
for section in sections_data:
# pop the lines
lines_data = section.pop('lines')
section = Section.objects.create(cheatsheet=cheatsheet, **section)
# and create them after the section:
for line in lines_data:
Line.objects.create(section=section, **line)