DRF Custom Update password got KeyError: 'request' - python

When I want to update password received error,
user = self.context['request'].user
KeyError: 'request'
Can someone help me with it?
serializer:
Custom serializer
class UserPasswordChangeSerializer(serializers.Serializer):
old_password = serializers.CharField(required=True)
password = serializers.CharField(required=True)
class Meta:
model = User
fields = ('old_password', 'password')
def validate_old_password(self, data):
user = self.context['request'].user
if not user.check_password(data):
raise serializers.ValidationError(
{'old_password': 'Wrong password.'}
)
return data
def update(self, instance, validated_data):
instance.set_password(validated_data['password'])
return super().update(instance)
My action view
My action view
#action(methods=['patch'], detail=True)
def change_password(self, request, *args, **kwargs):
user = self.get_object()
user.serializer = UserPasswordChangeSerializer(data=request.data)
user.serializer.is_valid(raise_exception=True)
user.serializer.save()
return Response(status=status.HTTP_204_NO_CONTENT)

You need to pass request as context variable to the serializer
#action(methods=['patch'], detail=True)
def change_password(self, request, *args, **kwargs):
user = self.get_object()
user.serializer = UserPasswordChangeSerializer(data=request.data,
context={'request': request})
user.serializer.is_valid(raise_exception=True)
user.serializer.save()
return Response(status=status.HTTP_204_NO_CONTENT)
Reference: Including extra context in Serializer

Related

How to get requested user in clean function in django forms?

Well i want to get requested user in clean function of django forms but i'm unable to do that. I'm trying to get that by simply saying self.request.user , it works in views but not working in forms.py, anybody have an idea how to get requested user in djnago forms ?
forms.py
class KycModelForm(forms.ModelForm):
class Meta:
model = KycModel
fields = '__all__'
def __init__(self, *args, **kwargs):
self.request = kwargs.pop('request', None)
super(KycModelForm, self).__init__(*args, **kwargs)
def clean(self):
cleaned_data = super().clean()
user = User.objects.get(username=self.request.user)
print(user)
views.py
class KycFormCreateView(CreateView):
form_class = KycModelForm
model = KycModel
template_name = "accounts/kyc/new_kyc.html"
def form_valid(self, form):
user_kyc = form.save(commit=False)
user_kyc.owner = self.request.user
user_kyc.save()
return super().form_valid(form)
You never construct a form with a request in the first place. You should pass this with:
class KycFormCreateView(CreateView):
form_class = KycModelForm
model = KycModel
template_name = 'accounts/kyc/new_kyc.html'
def get_form_kwargs(self, *args, **kwargs):
form_kwargs = super().get_form_kwargs(*args, **kwargs)
form_kwargs['request'] = self.request
return form_kwargs
def form_valid(self, form):
user_kyc = form.save(commit=False)
user_kyc.owner = self.request.user
user_kyc.save()
return super().form_valid(form)
In the clean function, you do not need to query for a user self.request.user is a user object, so you can work with self.request.user directly:
class KycModelForm(forms.ModelForm):
class Meta:
model = KycModel
fields = '__all__'
def __init__(self, *args, **kwargs):
self.request = kwargs.pop('request', None)
super(KycModelForm, self).__init__(*args, **kwargs)
def clean(self):
cleaned_data = super().clean()
user = self.request.user
print(user)
return cleaned_data

How to get user object from request in django rest framework?

I want to get the password of curent user from request body and verify it.
I am trying to get user object from request like this:
class UserPasswordUpdateAsAdminViewSet(APIView):
def patch(self, request, pk):
serializer = ResetPasswordAsAdminSerializer(data=request.data,
context={'request': request})
serializer.is_valid(raise_exception=True)
serializer.update_password()
return Response(status=status.HTTP_200_OK, data={'success': True})
and below is my serializer:
class ResetPasswordAsAdminSerializer(serializers.ModelSerializer):
new_password = serializers.CharField(write_only=True)
password = serializers.CharField(write_only=True)
def validate_password(self, attrs):
self.user = None
request = self.context.get("request")
if request and hasattr(request, "user"):
self.user = request.user
if not self.user or not self.user.check_password(attrs['password']):
raise CustomAPIException(
status_code=status.HTTP_401_UNAUTHORIZED,
message='Invalid password provided',
error_code=None
)
def validate_new_password(self, password):
if not re.match(REGEX['password'], str(password)):
raise CustomAPIException(
status_code=status.HTTP_409_CONFLICT,
message=None,
error_code='password_policy_mismatch'
)
return password
def update_password(self):
self.user.set_password(self.validated_data['new_password'])
self.user.save()
return
class Meta:
model = User
fields = ('password', 'new_password')
But on hitting the api, I am getting the following error:
string indices must be integers
What am I doing wrong?
You don't have to do this in the serializer itself, it can be done in the views pretty easily take a look at this example
serializer = PasswordSerializer(data=request.data)
if serializer.is_valid():
if not user.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
user.set_password(serializer.data.get('new_password'))
user.save()
return Response({'status': 'password set'}, status=status.HTTP_200_OK)
return Response(serializer.errors,
status=status.HTTP_400_BAD_REQUEST)

Django update api

I ma creating a user profile update api via django:
in urls:
url(r'^/api/users/(?P<user_id>[0-9]+)$', UserView.as_view(), name='user_profile'),
And my view:
class UserView(APIView):
def patch(self, request, user_id):
# logging.info('user Id: %s' % user_id)
logging.info('in patch...')
user = User.objects.get(id=user_id)
serializer = UserSerializer(user, data=request.data, partial=True)
if serializer.is_valid():
serializer.save()
return Response(status=status.HTTP_200_OK)
return Response(status=status.HTTP_400_BAD_REQUEST)
why patch def not called at all?! (I get 504 method not allowed)
my request is:
patch > http://localhost:8000/api/users/2
When i'm deleting the user_id argument in view, it works, but i need to get the user id in path.
def patch(self, request, user_id):
# logging.info('user Id: %s' % user_id)
logging.info('in patch...')
user = User.objects.get(id=2)
serializer = UserSerializer(instance=user, data=request.data, partial=True)
if serializer.is_valid():
serializer.save()
return Response(status=status.HTTP_200_OK)
return Response(status=status.HTTP_400_BAD_REQUEST)
You must provide instance eq: serializer = UserSerializer(instance=user, data=request.data, partial=True)
try this.
class UserView(APIView):
def patch(self, request, *args, **kwargs):
# try to get user_id from kwargs.get('user_id', None)

Django RestFrame work to update the fied

My serializer fun is
class change_pwdform(serializers.ModelSerializer):
def update(self, instance, validated_data):
user.set_password(validated_data.get('new_password', new_password))
user.save()
return instance
old_password = serializers.CharField( style={'input_type': 'password'})
new_password = serializers.CharField( style={'input_type': 'password'})
class Meta:
fields = ( 'pty_email','old_password','new_password',)
model = registration
in my model i have only the filed called
password field in model
my view function to change password is,
class Change_Password(mixins.ListModelMixin,
mixins.CreateModelMixin,
generics.GenericAPIView):
serializer_class = change_pwdform
def post(self, request, format=None):
email = request.data['pty_email']
pwd = request.data['old_password']
user = registration.objects.filter(pty_email=email, pty_password=pwd)
if user:
user = registration.objects.get(pty_email=email)
request['password'] = request.data['new_password']
print request.data //says quickdict of email , password , new_password, and old_password
serializer = change_pwdform(object, data=request.DATA, partial=True)
if serializer.is_valid():
serializer.save()
data = { "result":"success"}
return Response(data)
error ={"Invalid"}
return Response(error, status=status.HTTP_400_BAD_REQUEST)
This request return a dict ack: success but the password is not yet changed.
Thanks in advance..
You can wright an update function in your serializers like this.Following
def update(self, instance, validated_data):
user.set_password(validated_data.get('new_password', new_password))
user.save()
return instance
Here user is the user object and in your views.py you have to pass the model object like this
change_pwdform = change_pwdform(object, data=request.DATA, partial=True)
This worked for me and you can also refer "http://www.django-rest-framework.org/api-guide/serializers/#customizing-multiple-update"

django update view and passing context

I have a update view:
class GeneralUserUpdateView(UpdateView):
model = GeneralUser
form_class = GeneralUserChangeForm
template_name = "general_user_change.html"
def dispatch(self, *args, **kwargs):
return super(GeneralUserUpdateView, self).dispatch(*args, **kwargs)
def post(self, request, pk, username):
self.pk = pk
self.username = username
self.gnu = GeneralUser.objects.get(pk=self.pk)
#form = self.form_class(request.POST, request.FILES)
return super(GeneralUserUpdateView, self).post(request, pk)
def form_valid(self, form, *args, **kwargs):
self.gnu.username = form.cleaned_data['username']
self.gnu.email = form.cleaned_data['email']
self.gnu.first_name = form.cleaned_data['first_name']
self.gnu.last_name = form.cleaned_data['last_name']
self.gnu.address = form.cleaned_data['address']
self.gnu.save()
return redirect("user_profile", self.pk, self.username)
Here in this view I want to pass a context like:
context['picture'] = GeneralUser.objects.get(pk=self.pk)
I did trying get_context_data but I cant access pk in there..
Am I doing the update right?? How can I pass that context in there??
You shouldn't be overriding post at all. All of that logic should happen in get_context_data.
In fact, none of your overrides are needed. Everything that you do in form_valid will be done already by the standard form save. And overriding dispatch just to call the superclass is pointless.
Your view should look like this only, with no overridden methods at all:
class GeneralUserUpdateView(UpdateView):
model = GeneralUser
form_class = GeneralUserChangeForm
template_name = "general_user_change.html"
context_object_name = 'picture'
(although it seems a little odd that you want to refer to an instance of GeneralUser as "picture").
Edit to redirect to a specific URL, you can define get_success_url:
def get_success_url(self):
return reverse("user_profile", self.kwargs['pk'], self.kwargs['username'])

Categories

Resources