How to access requested user object from jwt token in django serializers? - python

After user-registration, user wants to post data into Client model ( OnetoOne relationship with User model ). So, I want to access the requested user object inside the serializer-class to create a new row in Client model associated with the requested user.
models.py
class Client(models.Model):
user= models.OneToOneField(User, on_delete=models.CASCADE, null=False, blank=False)
sex = models.CharField(max_length = 6, blank=False, null=False)
location = models.CharField(max_length = 30, null = False, blank = False)
views.py
class ClientRegister(GenericAPIView):
def post(self, request):
user = request.user
serializer = ClientSerializer(data= request.data)
if serializer.is_valid():
serializer.save()
return Response(status= status.HTTP_201_CREATED)
else:
return Response(data= 'Invalid Form', status= status.HTTP_400_BAD_REQUEST)
serializers.py
class ClientSerializer(serializers.ModelSerializer):
class Meta:
model = Client
fields = ['sex', 'location']
def create(self, validated_data):
sex = validated_data.get('sex')
location = validated_data.get('location')
user = #------ Want requested user object here ------#
if user.is_client:
client = Client(user=user, sex=sex, location=location)
client.save()
return client
I have manually added user oject into the data in serializer = CientSerializer(data=request.data).
But, It didn't work. Please, tell me how to pass it from views.py or how to access it in serializers.py.

Pass user when you do serializer.save in post method of views like
def post(self, request):
u = request.user
serializer = ClientSerializer(data= request.data)
if serializer.is_valid():
serializer.save(user=u)
return Response(status= status.HTTP_201_CREATED)
else:
return Response(data= 'Invalid Form', status= status.HTTP_400_BAD_REQUEST)
Or you can read about passing context from views to serializers and in this context you can pass your required data like -
serializer = ClientSerializer(context = {'request':request}, data=request.data)
then you can have your request object in your serializers and you can get request.user or directly pass it in the context.

Try to pass the user with sex and location in views
class ClientRegister(GenericAPIView):
def post(self, request):
data = request.data
user = request.user
#add user in key
data['user']=user
serializer = ClientSerializer(data=data)
if serializer.is_valid():
serializer.save()
return Response(status= status.HTTP_201_CREATED)
else:
return Response(data= 'Invalid Form', status= status.HTTP_400_BAD_REQUEST)
serializer:
class ClientSerializer(serializers.ModelSerializer):
class Meta:
model = Client
fields = '__all__'

views.py
class ClientRegister(GenericAPIView):
def post(self, request):
user = request.user
serializer = ClientSerializer(context={'user':user}, data= request.data)
if serializer.is_valid():
serializer.save()
return Response(status= status.HTTP_201_CREATED)
else:
return Response(data= 'Invalid Form', status= status.HTTP_400_BAD_REQUEST)
serializers.py
class ClientSerializer(serializers.ModelSerializer):
class Meta:
model = Client
fields = ['sex', 'location']
def create(self, validated_data):
sex = validated_data.get('sex')
location = validated_data.get('location')
user = self.context.get('user')
if user.is_client:
client = Client(user=user, sex=sex, location=location)
client.save()
return client

Related

DRF: make a POST query without data

cannot manage a POST method-query to url /users/{pk}/subscribe
Accesing this url should insert a record in db using Subscription model. No data is passed in body when accessing this url
model.Subscription
class Subscription(models.Model):
user = models.ForeignKey(User,
on_delete=models.CASCADE,
related_name='subscriber',
)
author = models.ForeignKey(User,
on_delete=models.CASCADE,
related_name='subscribing'
)
a router to users
router.register(r'users', CustomUserViewSet, basename='users')
and the additional URL that accepts POST query in the CustomUserViewSet
class CustomUserViewSet(viewsets.ModelViewSet):
queryset = User.objects.all()
serializer_class = CreateUserSerializer
#action(
detail=True,
methods=['post', 'delete'],
permission_classes=[IsAuthenticated],
)
def subscribe(self, request, *args, **kwargs):
user = request.user
author_pk = int(kwargs.get('pk'))
author_to_subscribe = get_object_or_404(User, id=author_pk)
if request.method == 'DELETE':
return Response(status=status.HTTP_204_NO_CONTENT)
if user.pk == author_pk:
data = {
"errors": "Cannot subscribe to yourself"
}
return Response(status=status.HTTP_400_BAD_REQUEST,
data=data)
# q = Subscription.objects.filter(user=user)
serializer = SubscriptionCreateSerializer(data=request.data)
serializer.is_valid()
serializer.save(user=user, author=author_to_subscribe)
return Response(
status=status.HTTP_200_OK)
Method shoould return serialized data from another serializer (SubscriptionSerializer. So i have 2 serializer for subscription: for viewing and creating
At this point in Postman getting error
class SubscriptionCreateSerializer(serializers.ModelSerializer):
class Meta:
model = Subscription
fields = '__all__'
def create(self, validated_data):
pass
class SubscriptionSerializer(serializers.ModelSerializer):
email = serializers.EmailField(source='author.email')
id = serializers.IntegerField(source='author.id')
username = serializers.CharField(source='author.username')
first_name = serializers.CharField(source='author.first_name')
last_name = serializers.CharField(source='author.last_name')
is_subscribed = serializers.BooleanField(default=True)
recipes = serializers.SerializerMethodField()
def get_recipes(self, obj):
qs = obj.author.recipes.all()
return RecipePublicSerializer(qs, many=True).data
def to_representation(self, instance):
representation = super().to_representation(instance)
representation['recipes_count'] = instance.author.recipes.count()
return representation
def to_internal_value(self, data):
recipes_data = data['recipes']
return super().to_internal_value(recipes_data)
class Meta:
model = Subscription
fields = ('email',
'id',
'username',
'first_name',
'last_name',
'is_subscribed',
'recipes',)
class CreateUserSerializer(serializers.Serializer):
"""Serializer for creating user objects"""
username = serializers.CharField(
validators=[
UniqueValidator(queryset=User.objects.all())
]
)
email = serializers.EmailField(
validators=[
UniqueValidator(queryset=User.objects.all())
]
)
first_name = serializers.CharField()
last_name = serializers.CharField()
password = serializers.CharField()
is_subscribed = serializers.SerializerMethodField()
#classmethod
def get_is_subscribed(self, object):
return True
def validate_username(self, value):
if value.lower() == "me":
raise serializers.ValidationError("Username 'me' is not valid")
return value
def create(self, validate_data):
user = User(**validate_data)
user.set_password(validate_data['password'])
user.save()
return user
class Meta:
fields = ('username',
'email',
'first_name',
'last_name',
'id',
'is_subscribed',)
read_only_fields = ('id',)
model = User
As I understood from question you would like to get user from request and id of author to subscribe from url. You pass to serializer empty body of your post request, but according to your serializer you should pass user and author fields, so to get serializer works you need to pass this parameters as data to serializer instance.
subscription_data = {
'user': request.user,
'author': author_to_subscribe
}
serializer = SubscriptionCreateSerializer(data=subscription_data)
serializer.is_valid(raise_exception=True)
serializer.save()
And also remove def save() method from your SubscriptionCreateSerializer it overwrites method which should put info about subscription in DB, so in your case it does nothing instead.

DRF Serializer doesn't recieve value from request for ManyToMany field

My Model is
class ChatRoom(models.Model):
name = models.CharField(max_length=55, verbose_name='Имя чата', unique=True)
users = models.ManyToManyField(
CustomUser,
verbose_name='Пользователи',
related_name='user_chatrooms',
null=True
)
My Serializer for this model
class ChatRoomSerializer(serializers.ModelSerializer):
users = UserInfoSerializer(many=True, read_only=False)
class Meta:
model = ChatRoom
fields = [
'name',
'users'
]
View looks
#api_view(['POST'])
#permission_classes([IsAuthenticated])
def api_create_chat(request):
if request.method == 'POST':
serializer = ChatRoomSerializer(data=request.data)
data = {}
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status=status.HTTP_201_CREATED)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
I do request (here is body)
<QueryDict: {'name': ['benny'], 'users': ['11,1']}>
In this case I recieve Error
{'users': [ErrorDetail(string='This field is required.', code='required')]}
And I can't understand what is wrong here.
When I change parameter to read_only=True in UserInfoSerializer it works, but it doesn't add user to new Chat object.
{
"name": "benny",
"users": []
}
UPD
I tried to add create() method, but it didn't help
def create(self, validated_data):
users = validated_data.pop('users')
users = [int(id) for id in users.split(',')]
chat_instance = ChatRoom.objects.create(name=validated_data.pop('name'))
for id in users:
chat_instance.users.add(CustomUser.objects.get(pk=id))
return chat_instance
UPD 2
UserInfoSerializer
class UserInfoSerializer(serializers.ModelSerializer):
class Meta:
model = CustomUser
fields = ['id',]
Problem solved by modifying serializer in view.py. It isn't good decision, but it works.
#api_view(['POST'])
#permission_classes([IsAuthenticated])
def api_create_chat(request):
if request.method == 'POST':
serializer = ChatRoomSerializer(data=request.data)
data = {}
if serializer.is_valid():
serializer.save()
users_id = [int(id) for id in request.data['users'].split(',')]
chat = ChatRoom.objects.get(pk=serializer.data['id'])
for id in users_id:
user = CustomUser.objects.get(pk=id)
chat.users.add(user)
serializer.data['users'].append({'user': user.id, 'username': user.username})
return Response(serializer.data, status=status.HTTP_201_CREATED)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

How to get request user id in Django Serializers?

I'm getting KeyError: 'request' while i want to get the current user id through user request.
I tried something like this: validated_data['user_id'] = CarOwnerCarDetails.objects.get(user_id=self.context['request'].user.id) but it's throwing me KeyError.
How to get the current user id through request in serializers?
if any help would be much appreciated. Thank you so much in advance my friends.
models :
class CarOwnerCarDetails(models.Model):
user_id = models.OneToOneField(User, on_delete=models.CASCADE)
car_plate_number = models.CharField(max_length=20, null=True, blank=True)
class GetQuotes(models.Model):
user = models.ForeignKey(CarOwnerCarDetails, on_delete=models.CASCADE, blank=True, null=True)
subject = models.CharField(max_length=240, blank=False, null=True)
serializers :
class ShopGarageGetQuoteSerializer(ModelSerializer):
subject = CharField(error_messages={'required':'subject key is required', 'blank':'subject is required'})
user_id = serializers.CharField(read_only=True)
class Meta:
model = GetQuotes
fields= ['user_id', 'subject']
def create(self,validated_data):
subject = validated_data['subject']
validated_data['user_id'] = CarOwnerCarDetails.objects.get(user_id=self.context['request'].user.id)
quotes_obj = GetQuotes.objects.create(
subject=subject,
user_id=validated_data['user_id']
)
return validated_data
views.py :
class ShopGarageGetQuoteAPIView(APIView):
permission_classes = (IsAuthenticated,)
def post(self,request,*args,**kwargs):
data = request.data
serializer = ShopGarageGetQuoteSerializer(data=request.data)
if serializer.is_valid():
serializer.save()
return Response({'success' :'True','message' : 'Quotes send successfully','data' : serializer.data},status=200)
return Response(serializer.errors,status=400)
as is written in the Official Documentation the user information (if the Authentication framework is correctly setup) is available using request.user
In your View you have to pass it using the serializer's context
class ShopGarageGetQuoteAPIView(APIView):
permission_classes = (IsAuthenticated,)
def post(self,request,*args,**kwargs):
data = request.data
context = {'request': request}
serializer = ShopGarageGetQuoteSerializer(data=request.data, context=context)
if serializer.is_valid():
serializer.save()
return Response({'success' :'True','message' : 'Quotes send successfully','data' : serializer.data},status=200)
return Response(serializer.errors,status=400)
For Generic Views/Viewsets the standard context contains 'request', 'view' and 'format' but in a standard APIView you have to pass it manually

Django rest framework image upload error

This is my UserProfile model,
class UserProfile(models.Model):
user = models.OneToOneField(User, related_name='profile', on_delete=models.CASCADE, )
badge = models.ImageField(upload_to='media/badges/', null=True)
reputation = models.IntegerField(default=0)
status = models.CharField(max_length=255, null=True, blank=True)
thumbnail = models.ImageField(upload_to='media/user/', blank=True, null=True)
And this is the Serializer class,
class UserProfileSerializer(serializers.ModelSerializer):
thumbnail = serializers.ImageField(max_length=None, use_url=True)
class Meta:
model = models.UserProfile
fields = ('badge', 'reputation', 'status', 'thumbnail',)
My API to update an image looks like this,
class CreateUpdateUserThumbnail(views.APIView):
def post(self, request, **kwargs):
try:
user = User.objects.get(id=kwargs.get('user_id'))
except User.DoesNotExist:
return Response({"Error": "User does not exist"}, status=status.HTTP_404_NOT_FOUND)
request.data['user_id'] = user.id
serializer = UserProfileSerializer(data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status=status.HTTP_201_CREATED)
else:
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
This is the error that I get when I try to upload an image using POSTMAN.
return Database.Cursor.execute(self, query, params)
django.db.utils.IntegrityError: NOT NULL constraint failed: bouncer_userprofile.user_id
How do I associate a user_id with the serializer data?
the request.data is immutable so you should to create the copy first:
data = request.data.copy()
data['user_id'] = user.id
serializer = UserProfileSerializer(data=data)
You need to pass user_profile instance on UserProfileSerializer instantiation
serializer = UserProfileSerializer(instance=user.profile, data=request.data)
Your view will look like this
class CreateUpdateUserThumbnail(views.APIView):
def post(self, request, **kwargs):
try:
user = User.objects.get(id=kwargs.get('user_id'))
except User.DoesNotExist:
return Response({"Error": "User does not exist"}, status=status.HTTP_404_NOT_FOUND)
serializer = UserProfileSerializer(instance=user.profile, data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status=status.HTTP_201_CREATED)
else:
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

Django Rest Framework: Issue with extended User model and serialization

I' extending the default Django user model to make a customised user profile with additional fields.The following are the related components.
models.py
class CandidateProfile(models.Model):
user = models.OneToOneField(
User, on_delete=models.CASCADE, related_name="user")
exp = models.IntegerField(null=True, blank=True)
serilaizers.py
class CandidateProfileSerializer(serializers.ModelSerializer):
id = serializers.IntegerField(source='pk', read_only=True)
username = serializers.CharField(source='user.username')
email = serializers.CharField(source='user.email')
groups = serializers.RelatedField(read_only=True)
password = serializers.CharField(max_length=128, source='user.password,read_only=True')
class Meta:
model = CandidateProfile
fields = ('id', 'username', 'password', 'email', 'groups')
depth = 1
def update(self, instance, validated_data):
print("In Update" + '*' * 50)
user = User.objects.get(pk=instance.user.pk)
user = instance.user
user.email = validated_data.get('user.email', user.email)
user.first_name = validated_data.get('user.first_name',
user.first_name)
user.last_name = validated_data.get('user.last_name', user.last_name)
user.save()
instance.gender = validated_data.get('gender', instance.gender)
instance.save()
return instance
def create(self, validated_data):
print('*' * 100)
print(validated_data)
user_data = validated_data.pop('user')
print(user_data)
user = User.objects.create_user(**user_data)
g = Group.objects.get(name="Candidate")
g.user_set.add(user)
user.save()
print(validated_data)
print('*' * 100)
profile = CandidateProfile.objects.create(user=user, **validated_data)
return user
views.py
class CandidateRegister(APIView):
def get(self, request, format=None):
candidate_list = User.objects.filter(groups=Group.objects.get(
name="Candidate"))
serializer = CandidateProfileSerializer(candidate_list, many=True)
return Response(serializer.data)
def post(self, request, format=None):
serializer = CandidateProfileSerializer(data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status=status.HTTP_201_CREATED)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
I've succcessfully created the user profile as well as the extended Candidate profile.But i'm encoutering an error on doing the same as follows :
Got AttributeError when attempting to get a value for field `username` on serializer `CandidateProfileSerializer`.
The serializer field might be named incorrectly and not match any attribute or key on the `User` instance.
Original exception text was: 'CandidateProfile' object has no attribute 'username'.
Even with this execpiton the User profile and the related Candidate profile is created.
You can use the SerializerMethodField from docs like -
class CandidateProfileSerializer(serializers.ModelSerializer):
id = serializers.IntegerField(source='pk', read_only=True)
username = serializers.SerializerMethodField()
def get_username(self, obj):
return obj.user.username

Categories