DRF: Need Guidance to perform a task - django

I need to create an API to book a call with an advisor
Endpoint: /user/<user_id>/advisor/<advisor_id>/
for this used path('user/<int:user_id>/advisor/<int:advisor_id>') in urls.py
but the problem is I have to request a Booking time(a DateTime sting) when I make a request to that link which I can perform via PostMan
In serilaizer.py I used:
class BookingSerializer(serializers.ModelSerializer):
class Meta:
model = models.Booking
fields = '__all__'
def create(self, validated_data):
user = models.Booking.objects.create(
user=validated_data['user'], advisor=validated_data['advisor'], time=validated_data['time'])
user.save()
return user
views.py
class BookAdvisorAPIView(generics.CreateAPIView):
serializer_class = serializer.BookingSerializer
permission_classes = [IsAuthenticated]
queryset = models.Booking.objects.all()
In this i have pass everything via the body in postman but I want to use the user_id and advisor_id from the url and just want to provide DateTime string via body in PostMan

I hope this should work,
class BookingSerializer(serializers.ModelSerializer):
class Meta:
model = models.Booking
fields = '__all__'
read_only_fields = ("user", "advisor")
def create(self, validated_data):
view_kwargs = self.context["view"].kwargs
booking = models.Booking.objects.create(
user_id=view_kwargs["user_id"],
advisor_id=view_kwargs["advisor_id"],
time=validated_data['time']
)
return booking

Related

DRF SERILAZATION

I serialize the field named "product" with ProductSerializer() inside OrderItemSerializer().
That's what I want.
class OrderItemSerializer(serializers.ModelSerializer):
product = ProductSerializer()
class Meta:
model = models.OrderItem
fields = ('id','order', 'product', 'quantity')
The output is;
But when I try to request with POST Method needs to send Product as a dictionary, just giving the id value is not enough.
How can I POST by sending only the id value?
I haven't written anything about the operation yet. Default ModelViewSet
class OrderItemViewSet(ModelViewSet):
queryset = OrderItem.objects.all()
serializer_class = serializers.OrderItemSerializer
permission_classes = (IsOwnerOrNot, IsAuthenticated)
def get_queryset(self):
user = self.request.user
return self.filter_queryset(queryset=self.queryset.filter(order__user=self.request.user))
If you're supporting writable nested representations you'll need to write .create() or .update() methods that handle saving multiple objects.
class UserSerializer(serializers.ModelSerializer):
profile = ProfileSerializer()
class Meta:
model = User
fields = ['username', 'email', 'profile']
def create(self, validated_data):
profile_data = validated_data.pop('profile')
user = User.objects.create(**validated_data)
Profile.objects.create(user=user, **profile_data)
return user

How to set read_only dynamically in django rest framework?

I am trying to check if the user id not equal to 1 then he should not be able to update few fields. I tried something similar to the following code but it did not work because of the following issues
self.user.id don't actually return the user I need to get the authenticated user in different why?
the def function maybe should have a different name like update?
also the general way maybe wrong?
class ForAdmins(serializers.ModelSerializer)):
class Meta:
model = User
fields = '__all__'
class ForUsers(serializers.ModelSerializer)):
class Meta:
read_only_fields = ['email','is_role_veryfied','is_email_veryfied']
model = User
fields = '__all__'
class UsersSerializer(QueryFieldsMixin, serializers.ModelSerializer):
def customize_read_only(self, instance, validated_data):
if (self.user.id==1):
return ForAdmins
else:
return ForUsers
class Meta:
# read_only_fields = ['username']
model = User
fields = '__all__'
You can make the decision which serializer you want to pass from your views
or
you can do it inside modelSerializer update method.
for getting user from Serializer class Try:
request = self.context.get('request', None)
if request:
user = request.user
for getting user from View class Try:
user = self.request.user

Querying and Filtering related models in DRF

I have Contact model to list the followers of an User object, I try to filter the contacts of a User but I still could not manage get a correct queryset. My Contact model is simple with two ForeignKey:
class Contact(models.Model):
user_from = models.ForeignKey(User,related_name='rel_from_set', on_delete=models.CASCADE,)
user_to = models.ForeignKey(User,related_name='rel_to_set', on_delete=models.CASCADE,)
def __str__(self):
return '{} follow {}'.format(self.user_from, self.user_to)
I have created serializers for User and Contact:
##Contact Serializer
class ContactsSerializer(serializers.ModelSerializer):
user_from = serializers.StringRelatedField(read_only=True)
user_to = serializers.StringRelatedField(read_only=True)
class Meta:
model = Contact
fields = ["user_from", "user_to"]
##UserSerializer
class UserInformationSerializer(serializers.ModelSerializer):
followers = ContactsSerializer(many=True, read_only=True)
class Meta:
model = User
fields = ['first_name', 'last_name', 'followers']
​
And try to make a query through views:
class FollowerListView(APIView):
queryset = Contact.objects.all()
serializer_class = ContactsSerializer
lookup_field = "username"
def get(self, request, format=None, slug=None):
kwarg_username = self.kwargs.get("slug")
user = User.objects.filter(is_active=1).filter(username=kwarg_username)
print(user.username)
contacts = Contact.objects.filter(user_to=user.id)
serializer = ContactsSerializer(contacts)
return Response(serializer.data)
Now I get error message:
AttributeError at /api/member/ytsejam/followers/
'QuerySet' object has no attribute 'username'
print(user.username)
If i try print(user) I can see the user an Object.
Can you guide me how to correct?
Thanks
filter will always return a queryset. If you expect to retrieve one single item, use get.
So that it looks like that:
def get(self, request, format=None, slug=None):
kwarg_username = self.kwargs.get("slug")
user = User.objects.filter(is_active=1).get(username=kwarg_username)
print(user.username)
contacts = Contact.objects.filter(user_to=user.id)
serializer = ContactsSerializer(contacts)
return Response(serializer.data)
You could, of course, do this on one take:
User.objects.get(is_active=1, username=kwarg_username)
But beware, if there are two rows in your model that would satisfy this call, Django will throw an error. Best make sure that the username has a unique constraint.

I created an extra table extra table in one to one relation with User table. how to show phone field in User registration

I am trying to create a simple API to get a user register.
I am using the default User table for authentication purpose, created another table called "phone" with one to one relation with User.
I am trying to add "phone" field just above the password. (I hope the image attached is visible).
**
Serializer.py
class UserRegisterSerializer(serializers.ModelSerializer):
class Meta:
model = UserDetailsModel
fields = ('phone', 'user')
class RegisterSerializer(serializers.ModelSerializer):
password = serializers.CharField(max_length=68, min_length=6, write_only=True)
class Meta:
model = User
fields = ('username','first_name', 'last_name','email','password')
read_only_fields = ('id',)
**
models.py<<
**
class UserDetailsModel(models.Model):
phone = models.IntegerField()
balance = models.DecimalField(max_digits=10, decimal_places=2, default=0)
user = models.OneToOneField(get_user_model(),primary_key='email' , on_delete=models.CASCADE)
def __str__(self):
return str(self.user)
**
views.py
**
class RegisterView(generics.GenericAPIView):
serializer_class = RegisterSerializer
def post(self, request):
user = request.data
serializer = self.serializer_class(data=user)
serializer.is_valid(raise_exception=True)
serializer.save()
user_data = serializer.data
return Response(user_data,status=status.HTTP_201_CREATED)
class DetailsRegisterView(generics.GenericAPIView):
serializer_class = UserRegisterSerializer
def post(self, request):
user = request.data
serializer = self.serializer_class(data=user)
serializer.is_valid(raise_exception=True)
serializer.save()
user_data = serializer.data
return Response(user_data,status=status.HTTP_201_CREATED)
**
urls
**
urlpatterns = [
path('',RegisterView.as_view()),
path('details', DetailsRegisterView.as_view())
]
**
You probably can use source in a serializer with a FK
class RegisterSerializer(...)
...
phone = serializers.CharField(..., source='userdetails.phone')
see also : the doc
I have some doubt in create case, in a update case this code work fine.
see also : How to serialize a relation OneToOne in Django with Rest Framework?
and an other way to resolve your issue : nested serializer
Updated code:
serializers>
from django.contrib.auth.models import User
from django.http import JsonResponse
from rest_framework import serializers
from .models import UserDetailsModel
class RegisterSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = ('username','first_name', 'last_name','email','password')
read_only_fields = ('id',)
class UserRegisterSerializer(serializers.ModelSerializer):
user = RegisterSerializer(required=True)
class Meta:
model = UserDetailsModel
fields = ('phone','user')
def create(self, validated_data):
user_data = validated_data.pop('user')
user = RegisterSerializer.create(RegisterSerializer(), validated_data=user_data)
data, created = UserDetailsModel.objects.update_or_create(user=user,
phone=validated_data.pop('phone'))
return data
class DetailView(serializers.ModelSerializer):
user = RegisterSerializer(read_only=True)
class Meta:
model = UserDetailsModel
fields = ('user','phone')
Remaining code stays the same.

How to retrieve all items created by a user using the django rest framework

I am trying to get only courses belonging to a particular user below I have the model, serializer and view I am using to try and achieve this. If I delete the entire get_queryset function from the view the api returns the appropriate user and every course created by every user. If get_queryset remains, the api always returns user not found and still gives every course that exists. Can anyone point me to how I can achieve my desired result.
view:
class UserDetail(generics.RetrieveUpdateDestroyAPIView):
permission_classes = [IsProfileOwnerOrReadOnly]
# queryset = User.objects.all()
serializer_class = UserSerializer
def get_queryset(self):
user = self.request.user
queryset = User.objects.all()
if user is not None:
queryset = queryset.filter(courses__owner_id=user.id)
return queryset
serializer
class UserSerializer(serializers.ModelSerializer):
courses = serializers.PrimaryKeyRelatedField(
many=True, queryset=Course.objects.all())
class Meta:
model = User
fields = ['id', 'username', 'courses']
Model
class Course (models.Model):
title = models.CharField(max_length=200)
description = models.TextField()
pub_date = models.DateField(default=date.today)
owner = models.ForeignKey('auth.User', related_name='courses', on_delete=models.CASCADE)
def __str__(self):
return self.title
You need to filter objects by user
class CreatePostsView(viewsets.ModelViewSet):
model = Post
serializer_class = PostsSerializer
def get_queryset(self):
user = self.request.user
return Post.objects.filter(owner=user)
class CoursesByOwnerView(RetrieveModelMixin, GenericViewSet):
serializer_class = YourModelSerializer
authentication_classes =[TokenAuthentication,]
permission_classes = [IsAuthenticated,]
def list(self, request, *args, **kwargs):
course_taker = self.request.user
courses = YourModel.objects.filter(owner=course_taker).values('your_model_fields')
return Response(courses)
Given your answer in the comments:
Either you use self.request.user given by the authentication middleware. In this case, it will only work for authenticated users, and you can't see courses for another User.
Either you use the endpoint users/<int:pk>/ you mentioned. In this case, you can fetch the user with:
class UserDetail(generics.RetrieveUpdateDestroyAPIView):
permission_classes = [IsProfileOwnerOrReadOnly]
serializer_class = UserSerializer
def get_queryset(self):
return UserDetail.objects.filter(pk=self.kwargs["pk"])
See this thread if you need another example: Django 2.0 url parameters in get_queryset
EDIT: In both cases, change your UserSerializer with:
class UserSerializer(serializers.ModelSerializer):
courses = serializers.PrimaryKeyRelatedField(
many=True, read_only=True)
class Meta:
model = User
fields = ['id', 'username', 'courses']