My Serializer.py
in this MovieSerializer I will check if "name" and "description" is same or not, if same then raise an error.
class MovieSerializer(serializers.Serializer):
id = serializers.IntegerField(read_only=True)
name = serializers.CharField(max_length=80)
description = serializers.CharField(max_length=300)
def create(self, validated_data):
return Movie.objects.create(**validated_data)
def update(self, instance, validated_data):
instance.name = validated_data.get('name', instance.name)
instance.description = validated_data.get('description', instance.description)
instance.save()
return instance
# object level validation
def validate(self, data):
if data['name'] == data['description']:
raise serializers.ValidationError("Name and Description can not be Same.")
else:
return data
My views.py
in serializer.is_valid() not pass raise_exception=True, when 'name' and 'description' is same it return a formated error message. output :
class MovieListAV(APIView):
def post(self, request):
serializer = MovieSerializer(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)
My another serializer
validate "password" and "confirm_password" same or not, if different then raise an error.
class UserPasswordChangeSerializer(serializers.Serializer):
password = serializers.CharField(write_only=True, style={'input_type':'password'})
confirm_password = serializers.CharField(write_only=True, style={'input_type':'password'})
class Meta:
fields = ['password', 'confirm_password']
def validate(self, attrs):
password = attrs.get('password')
password2 = attrs.get('confirm_password')
if password != password2:
raise serializers.ValidationError({'password':'Password and Confirm Password Should be Same!'})
user = self.context.get('user')
user.set_password(password)
user.save()
return attrs
My other view
serializer.is_valid() not pass raise_exception=True, when "password" and "confirm_password" is dirrerent it can't return any formated error message.
but when I use "raise_exception=True" as a parameter of is_valid() like serializer.is_valid(raise_exception=True) then I got formated error message.
my question is, why this time I need to pass "raise_exception=True" ? but "MovieListAV" class view no need to pass "raise_exception=True" in is_view()
class UserPasswordChange(APIView):
authentication_classes = [JWTAuthentication, ]
permission_classes = [IsAuthenticated, ]
def post(self, request, *agrs, **kwargs):
user = User.objects.get(email=request.user)
serializer = UserPasswordChangeSerializer(data=request.data, context={'user':user})
if serializer.is_valid():
return Response({'success':'Password Change successfull.'}, status=status.HTTP_202_ACCEPTED)
return Response(serializer.errors, status=status.HTTP_304_NOT_MODIFIED)
Related
I'm now making user profile update API using drf with RetreiveUpadteAPIView
there is one question that i can't figure out what the solution is.
This is what i want. I wanna update password and update other user data once for all.
changing password is worked as well as i supposed but other user datas (nick_name', 'wannabe', 'profile_img') are not save on DB through this logic below.
When i do self.object.set_password(), self.object.save() first and then do perform_update after. then user datas are well updated on DB. but password is saved without hashed even if i do set_password which is make the password hashed.
How can i fix it..
your best regard
Here is my code below.
#views.py
#permission_classes([IsAuthenticated])
class UpdatePartialUserView(RetrieveUpdateAPIView):
queryset = User.objects.all()
serializer_class = UserProfileSerializer
def get_object(self):
queryset = self.filter_queryset(self.get_queryset())
obj = queryset.get(pk=self.request.user.id)
self.check_object_permissions(self.request, obj)
return obj
def retrieve(self, request, *args, **kwargs):
serializer = UserSerializer(request.user)
return Response(status=status.HTTP_200_OK, data = serializer.data)
def update(self, request, *args, **kwargs):
partial = kwargs.pop('partial', False)
self.object = self.get_object()
serializer = self.get_serializer(request.user, data = request.data, partial=partial)
# serializer = self.get_serializer(self.object, data = request.data, partial=partial)
if not serializer.is_valid(raise_exception=True):
return Response(status=status.HTTP_409_CONFLICT, data = {'message':serializer.errors})
self.perform_update(serializer=serializer)
#make password hashed
self.object.set_password(request.data['password'])
self.object.save()
return Response(status=status.HTTP_202_ACCEPTED, data={"message": "success!"})
#serializers.py
class UserProfileSerializer(serializers.ModelSerializer):
password = serializers.CharField(write_only=True, required=True)
password2 = serializers.CharField(write_only=True, required=True)
old_password = serializers.CharField(write_only=True, required=True)
profile_img = serializers.ImageField(use_url=True, required = False)
def validate(self, attrs):
if attrs.get('password') != attrs.get('password2'):
raise serializers.ValidationError({
"password" : "passwords are not paired."})
return attrs
def validate_old_password(self, value):
#check user
request = self.context.get('request')
if request and hasattr(request, "user"):
user = request.user
if not user.check_password(value):
raise serializers.ValidationError({
"old_password" : "Old password is not correct."
})
return value
class Meta:
model = User
fields = ['nick_name', 'wannabe', 'old_password', 'password', 'password2', 'profile_img']
I think something like that should work.
def update(self, request, *args, **kwargs):
partial = kwargs.pop('partial', False)
self.object = self.get_object()
serializer = self.get_serializer(request.user, data = request.data, partial=partial)
if not serializer.is_valid(raise_exception=True):
return Response(status=status.HTTP_409_CONFLICT, data = {'message':serializer.errors})
self.object.set_password(new_password)
self.object.update(
nick_name=serializer.data["nickname"],
wannabe=serializer.data["wannabe"],
profile_img=serializer.data["profile_img"],
)
self.object.save()
return Response(status=status.HTTP_202_ACCEPTED, data={"message": "success!"})
I was trying to implement password change based on some recommendations on stackoverflow but something was not working which is really weird for me. After troubleshooting I got idea data the my view is not working. Changing serializer actions to print I see data "serializer.data" is result "{}" even though "print(serializer)" give result.
serializers.py
class ChangePasswordSerializer(serializers.Serializer):
old_password = serializers.CharField(max_length=128, write_only=True, required=True)
new_password1 = serializers.CharField(
max_length=128, write_only=True, required=True
)
new_password2 = serializers.CharField(
max_length=128, write_only=True, required=True
)
def validate_old_password(self, value):
user = self.context["request"].user
if not user.check_password(value):
raise serializers.ValidationError(
{
"old_passowrd": _(
"Your old password was entered incorrectly. Please enter it again."
)
}
)
return value
def validate(self, data):
if data["new_password1"] != data["new_password2"]:
raise serializers.ValidationError(
{"new_password2": _("The two password fields didn't match.")}
)
validate_password(data["new_password1"], self.context["request"].user)
return super().validate(data)
views.py
class ChangePassword(UpdateAPIView):
serializer_class = ChangePasswordSerializer
permission_classes = [IsAuthenticated]
def get_object(self, queryset=None):
return self.request.user
def update(self, request, *args, **kwargs):
self.object = self.get_object()
serializer = self.get_serializer(data=request.data)
if serializer.is_valid(raise_exception=True):
# user.set_password(serializer.data.get("new_password1"))
# user.save()
print(serializer.data)
return Response("Success", status=status.HTTP_204_NO_CONTENT)
return Response(serializer.errors, status.HTTP_400_BAD_REQUEST)
'write_only=True' fields are not included when serializing the representation. If you want to debug you can print request.data or remove parameter write_only or set it False.
https://www.django-rest-framework.org/api-guide/fields/
in model.py create a class in which 3 fields are there
class signUp(models.Model):
username = models.CharField(max_length=100)
email = models.EmailField()
password = models.IntegerField()
in serializer.py
class SignupSerializer(serializers.Serializer):
class Meta:
model = signUp
fields = ('username', 'email', 'password')
def create(self, validated_data):
email = validated_data['email'],
name = validated_data['name'],
password = validated_data['password']
return signUp.objects.create(**validated_data)
in views.py
#api_view(['POST'])
def signup(request):
if 'username' not in request.data:
response = {'message': 'please enter username'}
return Response(response, status=status.HTTP_400_BAD_REQUEST)
elif 'email' not in request.data:
response = {'message': 'please enter email'}
return Response(response, status=status.HTTP_400_BAD_REQUEST)
elif 'password' not in request.data:
response = {'message': 'please enter password'}
return Response(response, status=status.HTTP_400_BAD_REQUEST)
if request.method == 'GET':
signup = signUp.objects.all()
serializer = SignupSerializer(signup, many=True)
return JsonResponse(serializer.data, safe=False)
if request.method == 'POST':
data = JSONParser().parse(request)
serializer = SignupSerializer(data=data)
if serializer.is_valid():
user = serializer.validated_data.get('username')
message = f'successfully signup {user}'
return Response({message: message}, status=HTTP_200_OK)
All functions work and signup is a success, but after that data not show up in the database. How do I save it in the database?
I have a custom User model with field is_resetpwd as a boolean field with default value True
I want that to change to False when the password is changed, following is my password change view
class ChangePasswordView(APIView):
"""
An endpoint for changing password.
"""
serializer_class = ChangePasswordSerializer
model = User
permission_classes = (IsAuthenticated,)
def get_object(self, queryset=None):
obj = self.request.user
# print("obj", obj)
return obj
def post(self, request, *args, **kwargs):
self.object = self.get_object()
serializer = self.serializer_class(data=request.data)
if serializer.is_valid():
# Check old password
if not self.object.check_password(serializer.data.get("old_password")):
return Response({"old_password": ["Wrong password."]}, status=status.HTTP_400_BAD_REQUEST)
# set_password also hashes the password that the user will get
self.object.set_password(serializer.data.get("new_password"))
self.object.save()
response = {
'message': 'Password updated successfully',
}
return Response(response)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
what should I add in this to change my boolean value
Just before save() add this
self.object.is_resetpwd = False
and then save the objects just like before
The updated code will look like this
"""
An endpoint for changing passwords.
"""
serializer_class = ChangePasswordSerializer
model = User
permission_classes = (IsAuthenticated,)
def get_object(self, queryset=None):
obj = self.request.user
# print("obj", obj)
return obj
def post(self, request, *args, **kwargs):
self.object = self.get_object()
serializer = self.serializer_class(data=request.data)
if serializer.is_valid():
# Check old password
if not self.object.check_password(serializer.data.get("old_password")):
return Response({"old_password": ["Wrong password."]}, status=status.HTTP_400_BAD_REQUEST)
# set_password also hashes the password that the user will get
self.object.set_password(serializer.data.get("new_password"))
self.object.is_resetpwd = False
self.object.save()
response = {
'message': 'Password updated successfully',
}
return Response(response)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
I have a registration page that allows a user to sign up. After doing so, I want to call an API and then, save the data to my model (not saving it to a form though). I tried doing this:
models.py:
class Profile(models.Model):
user = models.OneToOneField(User, on_delete = models.CASCADE, primary_key=True, related_name = 'profile')
address = models.TextField()
birthday = models.DateField()
def __str__(self):
return str(self.user)
views.py:
def signup(request):
if request.method == 'POST':
user_form = UserForm(request.POST)
register_form = RegisterForm(request.POST)
if user_form.is_valid() and register_form.is_valid():
username = user_form.cleaned_data.get('username'),
first_name = user_form.cleaned_data.get('first_name'),
last_name=user_form.cleaned_data.get('last_name'),
email=user_form.cleaned_data.get('email'),
password=user_form.cleaned_data.get('password2'),
birthday = register_form.cleaned_data.get('dob'),
address=register_form.cleaned_data.get('address'),
payload = {'username': username,'first_name': first_name,'last_name': last_name,'email':email,'password':password,'register' : {'birthday': birthday,'address': address}}
response = requests.post('http://127.0.0.1:8000/my_api/',json=payload)
return redirect("home") #re-direct if login is successful
else:
user_form = UserForm()
register_form = RegisterForm()
return render(request, 'users/register.html', {'user_form': user_form, 'register_form': register_form})
class RegisterAPI(APIView):
permission_classes = [AllowAny]
def post(self, request, format=None):
serializer = UserSerializer(data=request.data)
if serializer.is_valid():
serializer.save()
content = {'status': 'You are registered'}
return Response(content, status=status.HTTP_201_CREATED)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
serializers.py:
from users.models import Profile
from django.contrib.auth.models import User
class ProfileSerializer(serializers.ModelSerializer):
birthday = serializers.DateField(format="%Y-%m-%d")
class Meta:
model = Profile
fields = ('birthday','address')
class UserSerializer(serializers.ModelSerializer):
profile = ProfileSerializer()
class Meta:
model = User
fields = ('username','first_name','last_name','email', 'password', 'profile')
def create(self, request, validated_data, *args, **kwargs):
register_data = validated_data.pop('profile')
password = validated_data.pop('password', None)
user = User.objects.create(**validated_data)
if password is not None:
user.set_password(password)
user.save()
Profile.objects.create(user = user, **register_data)
return validated_data
However, I am getting this error:
Object of type data is not JSON serializable error in Django
It seems that it's got to do with the birthday. On my template, a user can display the date of birth as 'YYYY-MM-DD'. How can I fix this error?
The create method in your UserSerializer should return a User instance instead of validated_data.
def create(self, request, validated_data, *args, **kwargs):
register_data = validated_data.pop('profile')
password = validated_data.pop('password', None)
user = User.objects.create(**validated_data)
if password is not None:
user.set_password(password)
user.save()
Profile.objects.create(user = user, **register_data)
return user