DRF: Is two sided object creation and relation assignment possible? - django

For example, I have two models,
Questionnaire Model
Profile Model
These two models are linked by a one-to-one relation, where the one-to-one-field is declared on the questionnaire model.
I want to be able to:
Create a new questionnaire instance, and assign an existing profile instance to it
Create a new profile instance, and assign an existing questionnaire instance to it
Currently, because my one-to-one relation is defined on the questionnaire model, I can do 1)
However, I am not able to achieve 2)
How do i get both 1) and 2) working?
Serializer
class ProfileCreateSerializer(serializers.ModelSerializer):
class Meta:
model = Profile
fields = "__all__"
Models
class Questionnaire(models.Model):
distance = models.FloatField(null=True)
profile = models.OneToOneField("Profile", on_delete=models.SET_NULL, null=True, related_name="questionnaire", blank=True)
class Profile(models.Model):
bio = models.CharField(max_length=300, blank=True)
Views
class ProfileCreate(generics.CreateAPIView):
queryset = Profile.objects.all()
serializer_class = ProfileCreateSerializer
permission_classes = [IsAuthenticated]
POST Request
{
"bio": "I like to eat pizza",
"questionnaire": 2
}

SOLVED with kind help from awesome people on Django Discord!
class ProfileCreateSerializer(serializers.ModelSerializer):
questionnaire_id = serializers.IntegerField(write_only=True)
class Meta:
model = Profile
fields = "__all__"
def create(self, validated_data):
questionnaire_id = validated_data.pop("questionnaire_id")
print(questionnaire_id)
profile = super().create(validated_data)
questionnaire = Questionnaire.objects.get(pk=questionnaire_id)
questionnaire.profile = profile
questionnaire.save()
return profile

Related

Listing objects field instead of Object in Django Rest Framework

I've got a model
class Like(models.Model):
product = models.ForeignKey('ProductInStore', on_delete=models.PROTECT)
user = models.ForeignKey('users.CustomUser', on_delete=models.PROTECT)
class Meta:
unique_together = ('product', 'user',)
and a serializer
class LikeSerializer(serializers.ModelSerializer):
user = serializers.PrimaryKeyRelatedField(read_only=True, default=serializers.CurrentUserDefault())
product = serializers.PrimaryKeyRelatedField(read_only=True)
class Meta:
model = Like
fields = ('user', 'product',)
class UserLikedProductsApiList(generics.ListAPIView):
queryset = Like.objects.all()
serializer_class = LikeSerializer
And so if someone likes a product, adds it to favourites, it creates an Like object in database. And i want to create an endpoint users/me/likedProducts so that i can list all the products that self.user.request has liked. Meaning all the Like instances but instead of Like instances i want to show only Like.product instances. Lets say a person x has liked 4 items, and i want to show only 4 items in that list. Do you have any idea how to get around that in Django Rest Framework?
you can change the queryset from like model to ProductInStore model
the query would look like this:
ProductInStore.objects.filter(id__in=Like.objects.filter(user=self.request.user).values_list('product',flat_true))
and you can use the default product serializer

display only some fields in get api response django serializer

I have an example model which has a fk relation with user model and Blog model. Now I have a get api which only requires certain fields of user to be displayed.
My model:
class Example(models.Model):
user = models.ForeignKey(
settings.AUTH_USER_MODEL,
on_delete=models.CASCADE,
null=True,
related_name="user_examples",
)
blog = models.ForeignKey(
Blog,
on_delete=models.CASCADE,
null=True,
related_name="blog_examples",
)
/................./
Now my view:
class ExampleView(viewsets.ModelViewSet):
queryset = Example.objects.all()
serializer_class = ExampleSerializer
def list(self, request, *args, **kwargs):
id = self.kwargs.get('pk')
queryset = Example.objects.filter(blog=id)
serializer = self.serializer_class(queryset,many=True)
return Response(serializer.data,status=200)
My serializer:
class ExampleSerializer(serializers.ModelSerializer):
class Meta:
model = Example
fields = ['user','blog','status']
depth = 1
Now when I call with this get api, I get all example objects that is required but all the unnecessary fields of user like password, group etc . What I want is only user's email and full name. Same goes with blog, I only want certain fields not all of them. Now how to achieve this in a best way??
You will have to specify the required fields in nested serializers. e.g.
class BlogSerializer(serializers.ModelSerializer):
class Meta:
model = Blog
fields = ['title', 'author']
class ExampleSerializer(serializers.ModelSerializer):
blog = BlogSerializer()
class Meta:
model = Example
fields = ['user','blog','status']
are you setting depth in serializer's init method or anywhere else? beacause ideally it should only display id's and not anything else. if yes then set depth to zero and use serializer's method field to return data that you need on frontend. I can provide you with example code samples

How to retrieve data from model that current user created and list it for another model's field in django

Let us imagine that I have two models.
First model contains curse details and user that created this course
class Course(models.Model):
course_name = models.CharField(max_length=100, null=False)
description = models.CharField(max_length=255)
user_profile = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
and my second model is:
class Lesson(models.Model):
course = models.OneToOneField(Course, on_delete=models.CASCADE) #
# inside the course I want my APIVIEW to list only the courses that current user created.
# OnetoOne relationship does not solve the problem.
status = models.CharField(choices=STATUS, null=False, default=GOZLEMEDE,max_length=20)
tariffs = models.FloatField(max_length=5,null=False,default=0.00)
continues_off = models.CharField(max_length=2)
user_profile = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
My serializers for both Models:
class LessonSerializer(serializers.ModelSerializer):
class Meta:
model = models.Lesson
fields = ('course', 'status', 'tariffs', 'continues_off', 'user_profile')
def create(self, validated_data):
lesson = models.Lesson.objects.create(
course = validated_data['course'],
status = validated_data['status'],
tariffs=validated_data['tariffs'],
continues_off=validated_data['continues_off'],
user_profile=validated_data['user_profile']
)
return lesson
class CourseSerializer(serializers.ModelSerializer):
"""Serializers Course content"""
class Meta:
model = models.Course
fields = '__all__'
def create(self,validated_data):
course = models.Course.objects.create(
course_name = validated_data['course_name'],
description=validated_data['description'],
user_profile=validated_data['user_profile']
)
return course
My Viewset:
class LessonViewset(viewsets.ModelViewSet):
model = models.Lesson
serializer_class = serializers.LessonSerializer
authentication_classes = (SessionAuthentication,)
permission_classes = (IsAuthenticated,BasePermission,)
def get_queryset(self):
user_current = self.request.user.id
return models.Lesson.objects.filter(user_profile=user_current)
How can I get the desired result. I want to get the courses for the current user and show them as a dropdown list in my API view. Just only the courses that user created should be in the dropdown list not all.
OnetoOne relationship gives all results of course table.
i think change your view code to :
def get_queryset(self,id):
return model.objects.filter(user_profile=id)
#You do not need to call it again when you put the Lesson on the model
\

Django rest framework queryset gives me .pk i want .name

my model
class Vacatures(models.Model):
title = models.CharField(max_length=50)
employer = models.ForeignKey(Employer, on_delete=models.CASCADE)
my .view
class VacaturesOverzichtMobile(generics.ListAPIView):
model = Vacatures
serializer_class = VacaturesSerializer
queryset = Vacatures.objects.all()
def get_queryset(self):
queryset = Vacatures.objects.all()
return queryset
So in the model there is Employer as foreign key. The api call in the view is working fine. The only thing is I get the employer as employer.pk , but I want the name of the Employer which is in the Employers model.
Can I tune the queryset so that it returns employer.name instead of employer.pk
I'd probably go with serializers for both models of the relationship as described in the DRF documentation. Then you have full control over which attributes of Employer you want to include. This approach is called "serializers as fields" in DRF.
class EmployerSerializer(serializers.ModelSerializer):
class Meta:
model = Employer
fields = ['name']
class VacaturesSerializer(serializers.ModelSerializer):
employer = EmployerSerializer(read_only=True)
class Meta:
model = Vacatures
fields = ['title']

fetch related resource with primary resource depend on some filter in django-rest

here are my models:
class Ratings(BaseModel):
resource_a = models.OneToOneField(ResourceA)
count = models.IntegerField(default=0)
total = models.IntegerField(default=0)
average = models.IntegerField(default=0)
def __unicode__(self):
return self.count
class UserRatings(BaseModel):
user = models.ForeignKey(UserProfile)
score = models.IntegerField()
rating = models.ForeignKey(Ratings)
def __unicode__(self):
return self.user.username
I want to fetch the ratings of ResourceA with rating of user who is logged-in in same API call.
I am able to fetch ratings of ResourceA using ModelSerializer but not able to fetch rating of user who is logged in.
I tried to do it using below code in ModelSerializer of Ratings.:
user_rating = serializer.CharField(source='get_user_rating')
but I can write get_user_rating function only in models and I think there is no way to access request.user in model itself.
Please suggest a way so that I can fetch UserRatings of user who is logged in along with Ratings.
You can use nested serializers to get all the data in 1 api call.
Simpleest method of that is to specify depth field in Meta class of serializer.
Class Meta:
depth = 1
But it has disadvantage that it will fetch all of the data for all foreign related fields till that depth even if you don't all of it.
You can try below approach which i like better
Class ResourceASerializer(serializers.ModelSerializer):
rating = RatingSerializer()
class Meta:
model = UserRatings
Class RatingsSerializer(serializers.ModelSerializer):
resource_a = ResourceASerializer()
class Meta:
model = Ratings
Class UserRatingSerializer(serializers.ModelSerializer):
rating = RatingSerializer()
class Meta:
model = UserRatings
or if you don't want to make 3 serializers:
Class UserRatingSerializer(serializers.ModelSerializer):
resource_a_rating = serailizers.SerializerMethodField()
class Meta:
model = UserRatings
fields = ('resource_a_rating', ) # add other fields too
def get_resource_a_rating(self, obj):
return obj.rating.resource_a // This data should be serializeable
To get the data for logged in user only over ride the get_queryset method in the view.
def get_queryset(self):
return UserRatings.objects.filter(user=self.request.user)