Writing a Django app which has a post table that has a recursive relationship to itself. This means that post CAN have a parent post (allows for replies). I want to ensure that a post can have a null for the parent post attribute - this would denote the "root" post. However, when I implement the views, model and serializer for the posts, I get the following error (stack trace):
Got a `TypeError` when calling `Post.objects.create()`. This may be because you have a writable field on the serializer class that is not a valid argument to `Post.objects.create()`. You may need to make the field read-only, or override the PostSerializer.create() method to handle this correctly.
Original exception was:
Traceback (most recent call last):
File "/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/rest_framework/serializers.py", line 962, in create
instance = ModelClass._default_manager.create(**validated_data)
File "/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/django/db/models/manager.py", line 85, in manager_method
return getattr(self.get_queryset(), name)(*args, **kwargs)
File "/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/django/db/models/query.py", line 669, in create
obj = self.model(**kwargs)
File "/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/django/db/models/base.py", line 564, in __init__
_setattr(self, field.attname, val)
File "/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/django/db/models/fields/related_descriptors.py", line 606, in __set__
raise TypeError(
TypeError: Direct assignment to the reverse side of a related set is prohibited. Use parent_post_id.set() instead.
Here's my model:
class Post(models.Model):
"""
Post model
"""
class PostObjects(models.Manager):
"""
Return the Post object and all children posts
"""
def get_queryset(self):
return super().get_queryset().filter(id='')
title = models.CharField(max_length=250)
body = models.TextField()
# Author deletion cascade deletes all of author's posts
author = models.ForeignKey(settings.AUTH_USER_MODEL,
on_delete=models.CASCADE,
related_name='forum_posts')
# if a post is deleted, all children posts will also be deleted
# defines recursive many-to-one relationship
parent_post = models.ForeignKey('self',
on_delete=models.CASCADE,
blank=True,
null=True,
related_name='parent_post_id')
time_stamp = models.DateTimeField(default=timezone.now)
# Default object manager
objects = models.Manager()
# Custom object manager for a particular object
post_objects = PostObjects()
def __str__(self):
return self.title
Here's my serializer:
class PostSerializer(serializers.ModelSerializer):
"""
Serializer for Post class
"""
class Meta:
model = Post
fields = ('id', 'title', 'body', 'author', 'time_stamp')
Here's my view:
class PostList(generics.ListCreateAPIView):
"""
Create a post or get a list of all posts within the database that are parent posts
API endpoints that use this view:
- /posts
- /createPost
"""
queryset = Post.objects.all()
serializer_class = PostSerializer
Urls:
from django.urls import path, include
from .views import *
urlpatterns = [
# path('', ),
path('createPost/', PostList.as_view(), name='createPost'),
path('createUser/', CreateUser.as_view(), name='createUser'),
path('getUser/<int:pk>', GetUser.as_view(), name='getUser'),
path('admin/addQuestion', GetQuestions.as_view(), name='addQuestion'),
path('admin/addCategory', Category.as_view(), name='addCategory'),
path('admin/deletePost/<int:pk>', PostDetail.as_view(), name='deletePost'),
path('admin/getCategories', Category.as_view(), name='getCategories'),
path('questionsBank/', GetQuestions.as_view(), name='questionsBank'),
path('posts/', PostList.as_view(), name='getPosts'),
path('posts/<int:pk>', PostDetail.as_view(), name='getPost'),
path('userProgress/<int:pk>', UserProgress.as_view(), name='getUserProgress'),
path('modifyUserProgress/<int:pk>', UserProgress.as_view(), name='modifyUserProgress'),
path('deletePost/<int:pk>', PostDetail.as_view(), name='deletePost'),
path('jobPostings/', JobPostings.as_view(), name='getJobPostings'),
]
POST request I make through API viewer to encounter error:
CodePudding user response:
In serializers:
I think your fields should be begin and close with [] brackets.
change this:
fields = ('id', 'title', 'body', 'author', 'time_stamp')
To this:
fields = ['id', 'title', 'body', 'author', 'time_stamp']
read_only_fields = ['id'] #also add this
In views:
class PostList(generics.ListCreateAPIView): #updated here, removed ViewSets
"""
Create a post or get a list of all posts within the database that are parent posts
API endpoints that use this view:
- /posts
- /createPost
"""
queryset = Post.objects.all()
serializer_class = PostSerializer #removed serializers from here
In urls.py:
path('createPost/', ListCreateAPIView.as_view(), name='createPost'), #Updated here instead of PostList, added ListCreateAPIView
CodePudding user response:
The issue was with the related names that I was using. I used the related_name attribute in the foreign key parent post. So this was creating some sort of backward relation and causing my error. Getting rid of the related_name attribute (and adjusting serializer class to reflect this) solved my issue!