AttributeError with Django REST Framework and a ManyToMany relationship - python

Trying to access my json page I get this error!
AttributeError at /project/api/1.json
Got AttributeError when attempting to get a value for field `title` on serializer `TaskSerializer`.
The serializer field might be named incorrectly and not match any attribute or key on the `RelatedManager` instance.
Original exception text was: 'RelatedManager' object has no attribute 'title'.
I have a Many to Many relationship with my models:
class Project(models.Model):
owner = models.ForeignKey('auth.User')
title = models.CharField(max_length=100)
slug = models.SlugField(unique=True)
created_date = models.DateTimeField(auto_now_add=True, auto_now=False)
updated_date = models.DateTimeField(auto_now_add=False, auto_now=True)
def __str__(self):
return self.title
def save(self, **kwargs):
super(Project, self, **kwargs).save()
self.slug = slugify(self.title)
super(Project, self, **kwargs).save()
def create(self):
pass
class Task(models.Model):
title = models.CharField(max_length=100)
description = models.TextField(blank=True)
completed = models.BooleanField(default=False)
project = models.ForeignKey('Project', related_name="tasks")
dependency = models.ManyToManyField('self', through='Dependency', null=True,
blank=True, through_fields=('task', 'sub_task'), symmetrical=False)
def sub_tasks(self, **kwargs):
qs = self.dependency.filter(**kwargs)
for sub_task in qs:
qs = qs | sub_task.sub_tasks(**kwargs)
return qs
def __str__(self):
return self.title
class Dependency(models.Model):
task = models.ForeignKey(Task, related_name="dependency_task")
sub_task = models.ForeignKey(Task, related_name="dependency_sub_task")
And these serializers:
class TaskSerializer(serializers.ModelSerializer):
class Meta:
model = Task
fields = ('id', 'title', 'project', 'completed',)
class ProjectSerializer(serializers.ModelSerializer):
tasks = TaskSerializer()
class Meta:
model = Project
fields = ('id', 'title', 'tasks',)
How can I get round this? RelatedManager tells me something is disagreeing with my M2M link, but why/how? I couldn't see anything here about Attribute Errors.
This question seems related, but setting many=False doesn't do anything.
AttributeError with Django REST Framework and MongoEngine

In that question they set many=False. You do have a Many-to-Many, so set many=True It's that simple.
In fact if you look closely, that's how the example shows you to do it:
class TrackListingField(serializers.RelatedField):
def to_representation(self, value):
duration = time.strftime('%M:%S', time.gmtime(value.duration))
return 'Track %d: %s (%s)' % (value.order, value.name, duration)
class AlbumSerializer(serializers.ModelSerializer):
tracks = TrackListingField(many=True)
class Meta:
model = Album
fields = ('album_name', 'artist', 'tracks')
See how the tracks listing field has the many=True attribute? Do that.

I had a similar issue when I missed out on specifying the related_name attribute to the definition of ForeignKeyField pointing to the Album model.

Related

Django Rest Framework: 'RelatedManager' object has no attribute 'body' error when using nested serializer

With Django DRF, I am trying to display the comments for a particular post in a blog using a nested serializer.
I have run into the following error:
'RelatedManager' object has no attribute 'body'
Here is my code:
comment model:
class Comment(models.Model):
#adapted from https://blog.logrocket.com/use-django-rest-framework-to-build-a-blog/
created = models.DateTimeField(auto_now_add=True)
body = models.TextField(blank=False)
user_id = models.ForeignKey(settings.AUTH_USER_MODEL, related_name='comments', on_delete=models.CASCADE)
post = models.ForeignKey('Posts', related_name='comments', on_delete=models.CASCADE)
#property
def time_left(self):
return self.post.time_left
Post model:
class Posts(models.Model):
title = models.CharField(max_length=100)
topic = MultiSelectField(choices=TOPIC_CHOICES)
creation_timestamp = models.DateTimeField(auto_now_add=True)
expiration_timestamp = models.DateTimeField(default=expiration)
body = models.CharField(max_length=255)
user_id = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE) #related_name='posts'
likes = models.ManyToManyField(settings.AUTH_USER_MODEL, related_name="likes",blank=True)
dislikes = models.ManyToManyField(settings.AUTH_USER_MODEL, related_name="dislikes",blank=True)
#property
def is_expired(self):
#taken from https://stackoverflow.com/questions/41505243/how-to-automatically-change-model-fields-in-django
if now() > self.expiration_timestamp:
return True
return False
#property
def time_left(self):
return self.expiration_timestamp - now()
serializers.py:
class CommentSerializer(serializers.ModelSerializer):
time_left = serializers.ReadOnlyField()
class Meta:
model = Comment
fields = ('created', 'body', 'user_id', 'post','time_left')
class PostsSerializer(serializers.ModelSerializer):
is_expired = serializers.ReadOnlyField()
time_left = serializers.ReadOnlyField()
comments = CommentSerializer(source='comments.body',) ########## THIS IS THE PROBLEMATIC LINE #######
class Meta:
#make sure that the relevant fields are read only
model = Posts
fields = ('comments','title','topic','creation_timestamp','expiration_timestamp','body','user_id','likes','dislikes','is_expired','time_left')
I believe the problematic line is the following one from serializers.py:
comments = CommentSerializer(source='comments.body',)
I think you are confusing the different keywords that a serializer can receive. Here I leave you an answer so that you understand it perfectly.
Your comments variable should look like this.
comments = CommentSerializer(many=True)

'Workout' object has no attribute 'exercises'

I just started to play with Django trying to make an API REST, for some reason that i don't understand i'm getting this error 'Workout' object has no attribute 'exercises' when i do GET - /workouts.
I'm using Django REST framework to make this thing.
This is part of my code that I think you need to help me:
serializers.py
class WorkoutSerializer(serializers.ModelSerializer):
exercises = serializers.StringRelatedField(many=True)
class Meta:
model = Workout
fields = ['id', 'name', 'creation_date', 'exercises']
class ExerciseSerializer(serializers.ModelSerializer):
class Meta:
model = Exercise
fields = ['url', 'video_url', 'workout']
models.py
class Workout(models.Model):
name = models.CharField(max_length=30)
creation_date = models.DateField(auto_now_add=True)
def __str__(self):
return self.name
class Exercise(models.Model):
video_url = models.URLField(max_length=200)
workout = models.ForeignKey(Workout, related_name='workout', on_delete=models.CASCADE)
def __str__(self):
return str(self.video_url)
views.py
class WorkoutViewSet(viewsets.ModelViewSet):
queryset = Workout.objects.all()
serializer_class = WorkoutSerializer
class ExerciseViewSet(viewsets.ModelViewSet):
"""
API endpoint that allows exercises to be viewed or edited.
"""
queryset = Exercise.objects.all()
serializer_class = ExerciseSerializer

How to make a ManyToMany serialization to be able to create a object in the POST request?

I'm trying to create a serialize to handle a ManyToMany relation, but it's not working. I have read the documentation and I probably doing something wrong. Also I have read the answers here.
Here are my models.
class Author(models.Model):
name = models.CharField(verbose_name="Name", max_length=255)
class Book(models.Model):
author = models.ForeignKey(
Author,
related_name="id_author",
blank=True,
null=True,
on_delete=models.PROTECT)
price = models.FloatField(verbose_name="Price")
class FiscalDocument(models.Model):
seller = models.ForeignKey(
User,
related_name="user_id",
on_delete=models.PROTECT)
book = models.ManyToManyField(Book)
My serializer:
class AuthorSerializer(serializers.ModelSerializer):
class Meta:
model = Author
fields = ('id', 'name')
class BookSerializer(serializers.ModelSerializer):
class Meta:
model = Book
fields = ('id', 'author', 'price')
def to_representation(self, instance):
response = super().to_representation(instance)
response['author'] = AuthorSerializer(instance.author).data
return response
class FiscalDocumentSerializer(serializers.ModelSerializer):
book = BookSerializer()
class Meta:
model = FiscalDocument
fields = ('id', 'seller', 'book')
def create(self, validated_data):
book_data = validated_data.pop('book')
fiscal_document = FiscalDocument.objects.create(**validated_data)
Book.objects.create(FiscalDocument=FiscalDocument,**medicine_data)
return fiscal_document
When I try to access the endpoint of the FiscalDocument, django-rest-framework is throwing an error:
Got AttributeError when attempting to get a value for field price on serializer BookSerializer. The serializer field might be named incorrectly and not match any attribute or key on the ManyRelatedManager instance. Original exception text was: ManyRelatedManager object has no attribute price.
If anyone can help XD.

Object of type 'ListSerializer' is not JSON serializable

I want to get all customer data and responses and also remarks.
This is model.py
class Customer(models.Model):
name = models.CharField(max_length=200)
email_address = models.CharField(max_length=200)
phone_number = models.CharField(max_length=20)
age = models.SmallIntegerField(default=14)
remarks = models.ManyToManyField(Remark,null=True,blank=True)
created_at = models.DateTimeField(auto_now_add=True)
def __str__(self):
return str(self.id)
class Response(models.Model):
question = models.ForeignKey(Question)
customer = models.ForeignKey(Customer)
response_text = models.CharField(max_length=100, null=True, blank=True)
created_at = models.DateTimeField(auto_now_add=True)
uuid = models.UUIDField()
def __str__(self):
return str(self.id)
This is serializers.py
class ResponseSerializer(ModelSerializer):
class Meta:
model = Response
fields = '__all__'
class RemarksSerializer(ModelSerializer):
class Meta:
model = Remark
fields = '__all__'
class CustomerInformationSerializer(ModelSerializer):
remarks = RemarksSerializer(many=True)
responses = serializers.SerializerMethodField()
def get_responses(self, obj):
responses = Response.objects.filter(customer=obj)
return ResponseSerializer(responses, many=True)
class Meta:
model = Customer
fields = ('name', 'email_address', 'phone_number', 'age', 'remarks', 'responses')
This is services.py
def customer_information(company_id=1):
cus = Customer.objects.filter(remarks__company_id=company_id)
return CustomerInformationSerializer(cus, many=True).data
This is views.py
class CustomerInformationView(APIView):
def get(self, request):
company_id = request.GET.get('company_id', 1)
resp = {'data': customer_information(company_id)}
return Response(data=resp, status=status.HTTP_200_OK)
This is url.py
url(r'^customer/$', CustomerInformationView.as_view()),
I'm having this problem. How can I solve this. Kindly guide me.
get function in your view should return responses.data, insted of responsed.
SIDE NOTE
First, let me point you to a resource that I think is GREAT for anything dealing with Django REST Framework:
Classy Django REST Framework. It is a fantastic resource because you can easily dig right into the source code to see how you may or may not need to override default operations.
MY ANSWER
What I suggest is that instead of using the APIView, you use ListAPIView.
It would look something like this:
from rest_framework.generics import ListAPIView
class Customer(models.Model):
name = models.CharField(max_length=200)
email_address = models.CharField(max_length=200)
phone_number = models.CharField(max_length=20)
age = models.SmallIntegerField(default=14)
remarks = models.ManyToManyField(Remark,null=True,blank=True)
created_at = models.DateTimeField(auto_now_add=True)
def __str__(self):
return str(self.id)
class Response(models.Model):
question = models.ForeignKey(Question)
customer = models.ForeignKey(Customer, related_name='responses')
response_text = models.CharField(max_length=100, null=True, blank=True)
created_at = models.DateTimeField(auto_now_add=True)
uuid = models.UUIDField()
def __str__(self):
return str(self.id)
class ResponseSerializer(ModelSerializer):
class Meta:
model = Response
fields = '__all__'
class RemarksSerializer(ModelSerializer):
class Meta:
model = Remark
fields = '__all__'
class CustomerInformationSerializer(ModelSerializer):
remarks = RemarksSerializer(many=True)
responses = ResponseSerializer(many=True)
class Meta:
model = Customer
fields = ('name', 'email_address', 'phone_number', 'age', 'remarks', 'responses')
class CustomerInformationView(ListAPIView):
queryset = Customer.objects.all()
serializer_class = CustomerInformationSerializer
lookup_field = 'remarks__company'
Note the change that I made by adding related_name to the customer field on your Response model. See Django documentation for more information on related_name. In short, it adds responses as a field name on your Customer model so that you can travel backwards through that relationship.
This is not tested, but this should be a better strategy to do what you want without having to have a get_responses method, or a services.py.
Some there might be error because of missing "/" at the end of path like "event-api"=incorrect and "event-api/" correct. That worked for me. Hope you also have same problem.
Incorrect: path('event-api',views.event_view,name="event-view")
Correct: path('event-api/',views.event_view,name="event-view")

Attribute Error after adding many=True in restframework django?

class CommentSerializer(serializers.ModelSerializer):
class Meta:
model = Comment
fields=('Comment','Comment_text','Comment_time','Comment_Post','Comment_User', )
class PostSerializers(serializers.ModelSerializer):
comment = CommentSerializer(many=True)
class Meta:
model = Postovo
fields = ('Postovo_id','Postovo_trending','comment', )
Models are like this
class Postovo(models.Model):
Postovo_id = models.AutoField(primary_key=True)
Postovo_type = models.ForeignKey(Type, related_name='posttype' ,default='1', editable=True)
Postovo_time = models.CharField(max_length=100,default=currentTimestamp, editable=True)
Postovo_link1 = models.CharField(max_length=1000,default='linkofimage1', editable=True)
Postovo_link2 = models.CharField(max_length=1000,default='linkofimage2', editable=True)
Postovo_person1=models.CharField(max_length=100,default='person1', editable=True)
Postovo_person2=models.CharField(max_length=100,default='person2', editable=True)
Postovo_hot=models.CharField(max_length=100,default='False', editable=True)
Postovo_trending=models.CharField(max_length=100,default='False', editable=True)
def __str__(self):
return '%s' % (self.Postovo_id)
Next
class Comment(models.Model):
Comment = models.AutoField(primary_key=True)
Comment_text = models.CharField(max_length=100)
Comment_time = models.CharField(max_length=100,default=currentTimestamp)
Comment_Post = models.ForeignKey(Postovo, related_name='commentpost' ,default='1', editable=True)
Comment_User = models.ForeignKey(RegUser, related_name='commentuser' ,default='1', editable=True)
def __str__(self):
return '%s' % (self.Comment)
In views
class Postcomment(viewsets.ModelViewSet):
queryset = Postovo.objects.all()
serializer_class = PostSerializers
ERROR
AttributeError: Got AttributeError when attempting to get a value for
field comment on serializer PostSerializers. The serializer field
might be named incorrectly and not match any attribute or key on the
Postovo instance. Original exception text was: 'Postovo' object has
no attribute 'comment'.
You need to use the related name commentpost instead of comment in PostSerializers.
class PostSerializers(serializers.ModelSerializer):
commentpost = CommentSerializer(many=True)
class Meta:
model = Postovo
fields = ('Postovo_id','Postovo_trending','commentpost', )
The error is coming because there is no comment attribute on a Postovo instance. The manager for getting all the related Comment instances is accessible using the related_name commentpost.

Categories