How to deserialize nested serializers with Django Rest Framework - python

i have in models.py
class Variants(Model):
class Meta:
db_table = 'variants'
id = models.AutoField(primary_key=True)
name = models.CharField(max_length=255, blank=False, null=False)
client = models.ForeignKey(Client, on_delete=models.CASCADE, null=False, blank=False)
created_at = models.DateField(auto_created=True, default=now, blank=True)
updated_at = models.DateField(auto_now=True, null=True, blank=True)
and
class VariantOptions(Model):
class Meta:
db_table = 'variant_options'
id = models.AutoField(primary_key=True)
name = models.CharField(max_length=255, blank=False, null=False)
variant = models.ForeignKey(Variants, on_delete=models.CASCADE, null=False, blank=False)
created_at = models.DateField(auto_created=True, default=now, blank=True)
updated_at = models.DateField(auto_now=True, null=True, blank=True)
and in serializers.py
class VariantOptionsSerializer(serializers.ModelSerializer):
class Meta:
model = models.VariantOptions
fields = ['name']
class VariantsSerializer(serializers.ModelSerializer):
options = VariantOptionsSerializer(many=True)
class Meta:
model = models.Variants
fields = ['name','client','options']
def create(self, validated_data):
options_data = validated_data.pop('options')
variant = models.Variants.objects.create(**validated_data)
for option_data in options_data:
models.VariantOptions.objects.create(variant=variant, **option_data)
return variant
and my view
class VariantsCreate(APIView):
permission_classes = (permissions.IsAuthenticated,)
serializer_class = serializers.VariantsSerializer
def post(self, request, format=None):
serializer = serializers.VariantsSerializer(data=request.data)
if serializer.is_valid():
saved = serializer.save()
return Response(serializer.data) ==> serializer.data gives error
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
i have this error
Got AttributeError when attempting to get a value for field options on serializer VariantsSerializer.
The serializer field might be named incorrectly and not match any attribute or key on the Variants instance.
Original exception text was: 'Variants' object has no attribute 'options'.
but the data has already been validated by the call to is_valid()
why return Response(serializer.data) gives error ?

Try to change
variant = models.ForeignKey(Variants, on_delete=models.CASCADE, null=False, blank=False)
with
variant = models.ForeignKey(Variants, related_name='options', on_delete=models.CASCADE, null=False, blank=False)

Related

Python Django | POST method with nested object. NOT NULL constraint failed

My point is to implement the post method with a nested object which has just ID. When I use all fields of a nested object post method works fine. But I'd like to pass just one field and it is ID, other fields gotta be unrequired
Now I'm getting the error like
NOT NULL constraint failed: article_article.author_id
models.py
class Author(models.Model):
first_name = models.CharField(max_length=20, blank=True, null=True)
last_name = models.CharField(max_length=20, blank=True, null=True)
nickname = models.CharField(max_length=20, blank=True, null=True)
def __str__(self):
return self.nickname
class Article(models.Model):
title = models.CharField(max_length=120, unique=True)
description = models.TextField(blank=True)
author = models.ForeignKey(Author, on_delete=models.CASCADE, related_name='articles')
created_at = models.DateTimeField(auto_now_add=True, blank=True)
updated_at = models.DateTimeField(auto_now=True, blank=True)
def __str__(self):
return self.title
views.py
class ArticleView(APIView):
def get(self, request, pk=None):
if pk:
article = Article.objects.get(pk=pk)
serializer = ArticleSerializer(article, many=False)
else:
articles = Article.objects.all()
serializer = ArticleSerializer(articles, many=True)
return Response(serializer.data)
def post(self, request):
data = request.data
serializer = ArticleSerializer(data=data)
if serializer.is_valid(raise_exception=True):
article_saved = serializer.save()
return Response({"success": "Article '' created successfully".format(article_saved.title)},
status=status.HTTP_201_CREATED)
serializers.py
class AuthorSerializer(serializers.Serializer):
first_name = serializers.CharField(required=False)
last_name = serializers.CharField(required=False)
nickname = serializers.CharField(required=False)
class ArticleSerializer(serializers.Serializer):
title = serializers.CharField(max_length=120)
description = serializers.CharField()
author = AuthorSerializer(required=False)
def create(self, validated_data):
author_data = validated_data.pop('author', None)
if author_data:
author = Author.objects.get_or_create(**author_data)[0]
validated_data['author'] = author
return Article.objects.create(**validated_data)
I got it. I should just have added to a serializer the field ID
class AuthorSerializer(serializers.Serializer):
first_name = serializers.CharField(required=False)
last_name = serializers.CharField(required=False)
nickname = serializers.CharField(required=False)
id = serializers.IntegerField()

Django Rest Framework (DRF) how to get value of GenericRelation field?

at my models.py I have a "Movies" model with the following field setup:
video_stream_relation = GenericRelation(VideoStreamInfo, related_query_name='video_stream_relation')
This GenericRelation field points to the following model class:
class VideoStreamInfo(models.Model):
objects = RandomManager()
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
content_type = models.ForeignKey(ContentType, limit_choices_to=referential_stream_models, on_delete=models.CASCADE, verbose_name=_("Content Type"))
object_id = models.CharField(max_length=36, verbose_name=_("Object ID"))
content_object = GenericForeignKey('content_type', 'object_id')
index = models.IntegerField(verbose_name=_("Stream Index"), blank=False)
bit_rate = models.IntegerField(verbose_name=_("Bitrate (bps)"), blank=True, null=True, editable=False)
codec_name = models.CharField(verbose_name=_("Codec Name"), blank=True, null=True, editable=False, max_length=255)
width = models.IntegerField(verbose_name=_("Width"), blank=True, null=True, editable=False)
height = models.IntegerField(verbose_name=_("Height"), blank=True, null=True, editable=False)
date_added = models.DateTimeField(auto_now_add=True, verbose_name=_("Date Added"))
Now the Question is how can I get video_stream_relation.codec_name value in a ModelSerializer like this:
class MovieSerializer(serializers.ModelSerializer):
id = serializers.PrimaryKeyRelatedField(queryset=Movies.objects.all())
class Meta:
model = Movies
fields = ('id',
...)
I want to be able to display the codec_name as a API JsonResponse.
If needed, this is how my API view currently looks like:
#api_view(['GET',])
#authentication_classes([JSONWebTokenAuthentication])
#permission_classes([AllowAny])
def movies(request):
if request.method == 'GET':
obj = Movies.objects.all()
serializer = MovieSerializer(obj, many=True)
return JsonResponse(serializer.data, safe=False)
If I try to add the video_stream_relation field to my MovieSerializer I get back the following error:
TypeError: Object of type GenericRelatedObjectManager is not JSON
serializable
Thanks in advance.
You can create a model serializer for VideoStreamInfo and use it in MovieSerializer as a related manager like this:
from rest_framework import serializers
class VideoStreamInfoSerializer(serializers.ModelSerializer):
class Meta:
model = VideoStreamInfo
fields = ('codec_name', )
class MovieSerializer(serializers.ModelSerializer):
video_stream_relation = VideoStreamInfoSerializer(many=True, read_only=True)
id = serializers.PrimaryKeyRelatedField(queryset=Movies.objects.all())
class Meta:
model = Movies
fields = ('id',
'video_stream_relation',
...
)

How to nest these Serializes without facing AttributeError: 'BlogPost' object has no attribute 'review_set'

I followed Dennis Ivy proshop Tutorial He used the same approach as the code is
class ReviewSerializer(serializers.ModelSerializer):
class Meta:
model = Review
fields = '__all__'
class ProductSerializer(serializers.ModelSerializer):
reviews = serializers.SerializerMethodField(read_only=True)
class Meta:
model = Product
fields = '__all__'
def get_reviews(self, obj):
reviews = obj.review_set.all()
serializer = ReviewSerializer(reviews, many=True)
return serializer.data
Now I need a Blog for the eCommerce Project and I created another app named blog and Created the models as
class BlogPost(models.Model):
_id = models.AutoField(primary_key=True, editable=False)
user = models.ForeignKey(User, on_delete=models.SET_NULL, null=True)
title = models.CharField(max_length=200, null=True, blank=True, help_text="Like How To Treat Hypertension etc")
image = models.ImageField(null=True, blank=True,
default='/placeholder.png')
rating = models.DecimalField(
max_digits=7, decimal_places=2, null=True, blank=True)
numReviews = models.IntegerField(null=True, blank=True, default=0)
createdAt = models.DateTimeField(auto_now_add=True)
youtubeVideoLink = models.CharField(max_length=1000, null=True , blank=True)
def __str__(self):
return str(self.createdAt)
class BlogPostReview(models.Model):
blogpost = models.ForeignKey(BlogPost, on_delete=models.SET_NULL, null=True)
user = models.ForeignKey(User, on_delete=models.SET_NULL, null=True)
name = models.CharField(max_length=200, null=True, blank=True)
rating = models.IntegerField(null=True, blank=True, default=0)
comment = models.TextField(null=True, blank=True)
createdAt = models.DateTimeField(auto_now_add=True)
_id = models.AutoField(primary_key=True, editable=False)
def __str__(self):
return str(self.rating)
But when I serialize them via same approach as mentioned above....
class BlogPostReviewSerializer(serializers.ModelSerializer):
class Meta:
model = BlogPostReview
fields = '__all__'
class BlogPostSerializer(serializers.ModelSerializer):
blog_post_reviews = serializers.SerializerMethodField(read_only=True)
class Meta:
model = BlogPost
fields = '__all__'
def get_blog_post_reviews(self, obj):
blog_post_reviews = obj.review_set.all()
serializer = BlogPostReviewSerializer(blog_post_reviews, many=True)
return serializer.data
This error comes
in get_blog_post_reviews
blog_post_reviews = obj.review_set.all()
AttributeError: 'BlogPost' object has no attribute 'review_set'
How to solve this problem or what I'm doing wrong and what need to be fixed. What would be another apporach obv there would be.... And I don't know why Dennis Ivy used review_set in his code. If someone know why we use _set and what are the circumstances please let me know.
The simplest solution is to update your get_blog_post_reviews method:
def get_blog_post_reviews(self, obj):
blog_post_reviews = obj.blogpostreview_set.all() # <- this line has changed
serializer = BlogPostReviewSerializer(blog_post_reviews, many=True)
return serializer.data
The original worked because there was a model named Review, so the automatically created reverse name was review_set. Your model is named BlogPostReview, so the reverse is blogpostreview_set.
More information about reverse relationships in the docs.

how to fix django instance of a model

Error message AttributeError: 'NoneType' object has no attribute 'add'
am trying to create an instance of a model.
the card model is suppose to be an instance of the patient model and the patient model has a foreign key relations with the user model.
Its like a patient who has a card in the hospital.
My error is coming from the perform_create method
views.py
class PatientCardListAPIView(ListCreateAPIView):
serializer_class = PatientsCardSerializer
queryset = Card.objects.all()
permission_classes = (permissions.IsAuthenticated, IsOwner, )
def perform_create(self, serializer):
serializer.save()
serializer.instance.owner.add(self.request.user)
models.py
from django.db import models
from authentication.models import User
# Create your models here.
class Patient(models.Model):
name = models.CharField(max_length=255, null=True)
country = models.CharField(max_length=255, null=True)
state = models.CharField(max_length=255, null=True)
phone = models.CharField(max_length=255, null=True)
email = models.CharField(max_length=255, null=True)
owner = models.ForeignKey(to=User, null=True, on_delete=models.CASCADE)
def __str__(self):
return self.name
class Card(models.Model):
name = models.CharField(max_length=255, null=True)
card_number = models.CharField(max_length=255, null=True)
owner = models.OneToOneField(Patient, null=True, blank=True, on_delete=models.CASCADE)
def __str__(self):
return self.name
It should be as
class PatientCardListAPIView(ListCreateAPIView):
serializer_class = PatientsCardSerializer
queryset = Card.objects.all()
permission_classes = (permissions.IsAuthenticated, IsOwner,)
def perform_create(self, serializer):
serializer.save(owner = self.request.user)
This should be:
def perform_create(self, serializer):
model_instance = serializer.save(owner=self.request.user)
OR
def perform_create(self, serializer):
model_instance = serializer.save()
model_instance.owner = self.request.user
Edited
..............
A closer look at your model shows that you need to redefine the model. As you've defined, the owner field under Patient class indicated that you can have a User who can be many Patient...(a query of: patient=Patient.objects.get(owner=self.request.user) may return more than one instance. ). Suggested model should be:
class Patient(models.Model):
name = models.CharField(max_length=255, null=True)
country = models.CharField(max_length=255, null=True)
state = models.CharField(max_length=255, null=True)
phone = models.CharField(max_length=255, null=True)
email = models.CharField(max_length=255, null=True)
**owner = models.OneToOneField(User, null=True)**
def __str__(self):
return self.name
class Card(models.Model):
name = models.CharField(max_length=255, null=True)
card_number = models.CharField(max_length=255, null=True)
owner = models.OneToOneField(Patient, null=True, blank=True, on_delete=models.CASCADE)
def __str__(self):
return self.name
Then you can have your view:
class PatientCardListAPIView(ListCreateAPIView):
serializer_class = PatientsCardSerializer
queryset = Card.objects.all()
permission_classes = (permissions.IsAuthenticated, IsOwner, )
def perform_create(self, serializer):
card_instance = serializer.save()
patient = Patient.objects.get(owner=self.request.user)
card_instance.owner = patient
Appreciation
I was almost discouraged with programming for the past 24hrs because of this problem, but this community helped me, even though they did not give the answer i needed, they led me into discovering the answer myself, and i say Thank you to stackoverflow community...
Solved
I finally discovered what i was doing wrong.
a card does not just belong to a patient, it also belongs to a hospital, so the card needs a relation to both the hospital and the patient.
models.py
class Patient(models.Model):
name = models.CharField(max_length=255, null=True)
country = models.CharField(max_length=255, null=True)
state = models.CharField(max_length=255, null=True)
phone = models.CharField(max_length=255, null=True)
email = models.CharField(max_length=255, null=True)
owner = models.ForeignKey(to=User, null=True, on_delete=models.CASCADE)
def __str__(self):
return self.name
class Card(models.Model):
name = models.CharField(max_length=255, null=True)
card_number = models.CharField(max_length=255, null=True)
owner = models.OneToOneField(Patient, null=True, blank=True, on_delete=models.CASCADE)
hospital = models.ForeignKey(User, null=True, blank=True, on_delete=models.CASCADE)
def __str__(self):
return self.name
views.py
class PatientCardListAPIView(ListCreateAPIView):
serializer_class = PatientsCardSerializer
queryset = Card.objects.all()
permission_classes = (permissions.IsAuthenticated, IsOwner, )
def perform_create(self, serializer):
return serializer.save(hospital=self.request.user)
def get_queryset(self):
return self.queryset.filter(hospital=self.request.user)
class PatientCardDetailAPIView(RetrieveUpdateDestroyAPIView):
serializer_class = PatientsCardSerializer
permission_classes = (permissions.IsAuthenticated, IsOwner,)
queryset = Card.objects.all()
lookup_field = "id"
def get_queryset(self):
return self.queryset.filter(hospital=self.request.user)

Insert related field django rest framework

I have this simple model and I am having difficult in inserting related field of 'notes' through django rest framework.
class Student(models.Model):
firstName = models.CharField(max_length=100, blank=True, null=True)
lastName = models.CharField(max_length=100, blank=True, null=True)
prefLocation = models.ManyToManyField("Location", blank=True, null=True, related_name = 'prefLocation')
def __unicode__(self):
return self.firstName
class LocationRegion(models.Model):
regionName = models.CharField(max_length=100)
def __unicode__(self):
return self.regionName
class Location(models.Model):
locationName = models.CharField(max_length=100)
region = models.ForeignKey(LocationRegion, null=True, blank=True, related_name='locations')
def __unicode__(self):
return self.locationName
class Note(models.Model):
text = models.CharField(max_length=1000)
student = models.ForeignKey(Student, null=True, blank=True, related_name='notes')
def __unicode__(self):
return self.text
class StudentViewSet(viewsets.ModelViewSet):
queryset = Student.objects.all()
serializer_class = StudentSerializer
I am unsure if I need to use ModelSerializer or generic Serializer. Validated_data doesn't return 'note' field in the deserialized data. I would appreciate any help with the serializer.
Thanks
Here are my serializers :
class StudentSerializer(serializers.ModelSerializer):
def create(self, validated_data):
def get_notes(self, obj):
return validated_data['note']
note = serializers.SerializerMethodField('get_notes')
return Candidate.objects.create(**validated_data)
class Meta:
model = Student
fields = ('id', 'firstName', 'lastName', 'note')
class NoteSerializer(serializers.ModelSerializer):
class Meta:
model = Note

Categories

Resources