My goal is to reset the password via mail. But the profile_obj of the ChangePassword view returns None and 'NoneType' object has no attribute 'user'. Why? I tried different ways but did not work. The ForgetPassword view working well. The ChangePassword view doesn't work. Where is the problem? give me a relevant solution.
views.py:
def ForgetPassword(request):
try:
if request.method == 'POST':
email = request.POST.get('email')
if not User.objects.filter(email=email).first():
messages.warning(request, 'Not email found with this email.')
return redirect('ForgetPassword')
user_obj = User.objects.get(email = email)
token = str(uuid.uuid4())
send_forget_password_mail(user_obj.email , token)
messages.success(request, 'Please check your mail box an email is send.')
return redirect('ForgetPassword')
except Exception as e:
print(e)
context = {
}
return render(request, "forget_password_email.html", context)
def ChangePassword(request, token):
context = {}
try:
profile_obj = User.objects.filter(forget_password_token=token).first()
print(profile_obj)
if request.method == 'POST':
new_password = request.POST.get('new_password')
confirm_password = request.POST.get('reconfirm_password')
user_id = request.POST.get('user_id')
if user_id is None:
messages.warning(request, 'No user id found.')
return redirect(f'/ChangePassword/{token}/')
if new_password != confirm_password:
messages.warning(request, 'both should be equal.')
return redirect(f'/ChangePassword/{token}/')
profile_obj.password = new_password
profile_obj.save()
user_obj = User.objects.get(id = user_id)
user_obj.set_password(new_password)
user_obj.save()
return redirect('Login')
context = {'user_id' : profile_obj.user.id}
except Exception as e:
print(e)
context = {
}
return render(request,'change_password.html', context)
helpers.py:
from django.core.mail import send_mail
from django.conf import settings
def send_forget_password_mail(email , token ):
subject = 'Your forget password link'
message = f'Hi , click on the link to reset your password http://127.0.0.1:8000/ChangePassword/{token}/'
email_from = settings.EMAIL_HOST_USER
recipient_list = [email]
send_mail(subject, message, email_from, recipient_list)
return True
models.py:
class User(AbstractUser):
email = models.EmailField(max_length=50, unique=True, error_messages={"unique":"The email must be unique!"})
REQUIRES_FIELDS = ["email"]
objects = CustomeUserManager()
forget_password_token = models.CharField(null= True, max_length=100, blank=True)
def __str__(self):
return f"{self.pk}.{self.email}"
urls.py:
path('ForgetPassword/', views.ForgetPassword, name="ForgetPassword"),
path('ChangePassword/<token>/', views.ChangePassword, name="ChangePassword")
Your context in the ChangePassword function is :
context = {'user_id' : profile_obj.user.id}
Your error here is that profile_obj is a QuerySet and you are looking for a user field in a queryset and not in a model instance(model) like user_obj.
Also, you can't change a password this way in a queryset:
profile_obj.password = new_password
profile_obj.save()
This works on model instances.
You need to rewrite your view to either get a User instance and then return it's id to your context or use the already created user_obj you are getting later in your code.
context = {'user_id' : user_obj.id}
Related
I have django app with authentication in it and email verification. When user is created activation email is sent with link inside of it, when user clicks this link is doesn't take him nowhere.
views.py
class customer_register(CreateView):
model = User
form_class = CustomerSignUpForm
template_name = 'authentication/customer_register.html'
def form_valid(self, form):
user = form.save()
user.token = str(uuid.uuid4())
subject = 'Verify your account | Zane'
message = f"http://127.0.0.1:8000/accounts/verify/{user.token}/"
recipient_list = [user.email]
send_mail(
subject,
message,
'from#example.com',
['to#example.com'],
fail_silently=False,
)
return redirect('/')
def activate(request, token):
try:
obj = models.User.objects.get(email_token = token)
obj.signup_confirmation = True
obj.save()
return HttpResponse('Your account is verified')
except Exception as e:
return HttpResponse('Invalid token')
urls.py
path('verify/<uuid:pk>/', views.activate, name='activate'),
models.py
...
token = models.CharField(max_length=200, blank=True)
signup_confirmation = models.BooleanField(default=False)
I wonder what do I need to put in my url to trigger my function?
I would rewrite your active view as a class. Here is an example:
class ActivateView(LoginRequiredMixin, View):
def get(self, request, *args, **kwargs):
token = kwargs['pk']
try:
obj = User.objects.get(email_token = token)
obj.signup_confirmation = True
obj.save()
return HttpResponse('Your account is verified')
except Exception as e:
return HttpResponse('Invalid token')
urls.py
path('verify/<uuid:pk>/', ActivateView.as_view(), name='activate'),
My custom signup view has the user's is_active set to False. They use an emailed authorized token to set is_active to True. However, immediately after I sign up as a new user, I log into the admin page as a superuser and I can see that my new user has active checked off.
views
def signup(request):
if request.method == 'POST':
form = CustomUserCreationForm(request.POST)
if form.is_valid():
user = form.save()
user.is_teacher = True
user.is_staff = True
user.is_active = False
to_email = form.cleaned_data.get('email')
user.username = to_email # make the username the same as the email
user.save()
group = Group.objects.get(name='teacher')
user.groups.add(group)
current_site = get_current_site(request)
# use sendgrid api for email
sendgrid_client = SendGridAPIClient(
api_key=os.environ.get('SENDGRID_API_KEY'))
from_email = From("me#email.com")
to_email = To(to_email)
subject = "Activate your SmartMark Account"
active_link = render_to_string('account/acc_active_email_link.html', {
'user': user,
'domain': current_site.domain,
'uid': urlsafe_base64_encode(force_bytes(user.pk)),
'token': account_activation_token.make_token(user),
})
html_text = f'Hello {user}<br/><p>Registration email</p>{active_link}'
html_content = HtmlContent(html_text)
mail = Mail(from_email, to_email, subject,
html_content)
response = sendgrid_client.send(message=mail)
return redirect(reverse('accounts:account_activation_sent'))
else:
form = CustomUserCreationForm()
return render(request, 'account/signup.html', {'form': form})
def account_activation_sent(request):
return render(request, 'account/account_activation_sent.html')
def activate(request, uidb64, token):
try:
uid = force_text(urlsafe_base64_decode(uidb64))
user = CustomUser.objects.get(pk=uid)
except (TypeError, ValueError, OverflowError, User.DoesNotExist):
user = None
# calls check_token function but user is already set to active - email and token
# were never used.
if user is not None and account_activation_token.check_token(user, token):
user.is_active = True
user.save()
login(request, user)
return redirect('home')
else:
return render(request, 'account/account_activation_invalid.html')
CustomUser model
class CustomUser(AbstractUser):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
is_teacher = models.BooleanField('teacher status', default=False)
def __str__(self):
return self.username
Form
class CustomUserCreationForm(UserCreationForm):
first_name = forms.CharField(max_length=30)
last_name = forms.CharField(max_length=30)
class Meta:
model = get_user_model()
fields = ('email', 'first_name', 'last_name')
def signup(self, request, user):
user.first_name = self.cleaned_data['first_name']
user.last_name = self.cleaned_data['last_name']
def clean_email(self):
value = self.cleaned_data["email"]
if not value:
raise forms.ValidationError('An Email address is required.')
check_users = CustomUser.objects.filter(email__iexact=value)
if check_users:
raise forms.ValidationError('This email is already in use.')
return value
I am using Django's built in authentication. I am expecting the Active in the admin panel to be not checked off. I also tried moving the user.is_active=False to after the user.save() but this did not change the behaviour. I know from looking at my inital migrations file that the default for is_active is True but I would think that my signup view would override this
Edit
I thought I had fixed this by changing to user=form.save(commit=False) but it's happening again. New sign ups are automatically active.
First I changed my form save to:
user=form.save(commit=False)
However, it appears that the problem is that when I email the authorization token, the email recipient is checking the url for spam. By checking that the token url is a valid, the token is getting validated. I add a POST form such that the token is not checked until the user submits the form.
hello i learning about Django rest api, I am learning through someone else's code, but I don't know how to make Login.
my code :
model:
class User(models.Model):
class Meta:
db_table = "users"
created_at = models.DateTimeField(default = timezone.now)
updated_ay = models.DateTimeField(auto_now= True)
email = models.CharField(max_length = 128, unique= True)
password = models.CharField(max_length = 255)
active = models.BooleanField(default=False)
token = models.CharField(max_length= 255, null = True)
nickname = models.CharField(max_length = 255, null = True)
serializer:
class UserSerializer(serializers.ModelSerializer):
email = serializers.EmailField()
class Meta:
model = User
fields = '__all__'
def to_internal_value(self, data):
ret = super(UserSerializer, self).to_internal_value(data)
# cipher = AESSipher()
# ret['password'] = cipher.encrypt_str(ret['password'])
return ret
def to_representation(self, obj):
ret = super(UserSerializer, self).to_representation(obj)
print(ret)
return ret
def validate_email(self, value):
if User.objects.filter(email=value).exists():
raise serializers.ValidationError("Email already exists")
return value
def validate_password(self, value):
if len(value) < 8:
raise serializers.ValidationError("The password must be at least %s characters long. " % 8)
return value
def create(self, validate_data):
user = User.objects.create(
email = validate_data['email'],
password = validate_data['password'],
)
user.active = False
user.save()
message = render_to_string('user/account_activate_email.html', {
'user': user,
'domain' : 'localhost:8000',
'uid': urlsafe_base64_encode(force_bytes(user.pk)),
'token': account_activation_token.make_token(user)
})
mail_subject = 'sign up mail.'
to_email = 'mymail#gmail.com'
email = EmailMessage(mail_subject, message, to=[to_email])
email.send()
return validate_data
views:
class SignUp(APIView):
def post(self, request):
serializer = UserSerializer(data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status=status.HTTP_200_OK)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
class UserActivate(APIView):
permission_classes = (permissions.AllowAny,)
def get(self, request, uidb64, token):
try:
uid = force_text(urlsafe_base64_decode(uidb64))
user = User.objects.get(pk = uid)
except(TypeError, ValueError, OverflowError, User.DoesNotExist):
user = None
try:
if user is not None and account_activation_token.check_token(user, token):
user.active = True
user.token = token
user.save()
return Response(user.email + 'email active', status=status.HTTP_200_OK)
else:
return Response('Expired Link', status=status.HTTP_400_BAD_REQUEST)
except Exception as e:
print(traceback.format_exc())
Since I want to handle log-in status in the Mobile Client section,
I want to get only user model information when I log-in.
When Enter Email and Password in Client and I want to get user information.
How to make log-in? Do you know anyone?
Here is the link to the article: custom user authentication; it should help you
https://wsvincent.com/django-rest-framework-user-authentication-tutorial/
Hi you can use Django packages for this. for example you can use rest-auth package this package have all the things that you need for log in log out and reset password and all you need is that follow the rest auth documentation :
. https://pypi.org/project/django-rest-auth/
. https://django-rest-auth.readthedocs.io/en/latest/
I have a registration that let users register and i'm having difficulty fixing it.
The problem is when a user submits a single field instead of the whole form for example an email . I get this error
KeyError at /register/
password
Request Method: POST
Request URL: http://127.0.0.1:8000/register/
File "C:\Python26\Lib\site-packages\django\forms\forms.py" in _get_errors
115. self.full_clean()
File "C:\Python26\Lib\site-packages\django\forms\forms.py" in full_clean
271. self._clean_form()
File "C:\Python26\Lib\site-packages\django\forms\forms.py" in _clean_form
299. self.cleaned_data = self.clean()
File "C:\o\17\mysite\pet\forms.py" in clean
31. if self.cleaned_data['password'] != self.cleaned_data['password1']:
Exception Type: KeyError at /register/
Exception Value: password
I tried to fix this solution using if . If user has a submitted a username or any other required field , process the form otherwise redisplay the original form.
but I still get the same error.
This is my edited views.py (at the bottom of the page is my original RegistrationForm)
def PetRegistration(request):
if request.user.is_authenticated():
return HttpResponseRedirect(reverse('world:HappyLand'))
if request.method =='POST':
form = UserRegistration(request.POST)
if form.is_valid():
username = form.cleaned_data['username']
if username:
email=form.cleaned_data['email']
if email:
password=form.cleaned_data['password']
if password:
user = User.objects.create_user(
username=form.cleaned_data['username'],
email=form.cleaned_data['email'],
password=form.cleaned_data['password']
)
user.is_active = True
user.first_name = form.cleaned_data['name']
user.save()
person = authenticate(
username=form.cleaned_data['username'],
password=form.cleaned_data['password']
)
Person.objects.create(user_id=user.id,
name=form.cleaned_data['name'],birthday=form.cleaned_data['birthday'])
login(request, person)
return HttpResponseRedirect(reverse('world:HappyLand'))
return render(request, 'register.html', {'form': UserRegistration()})
How can I fix this error and also how could I display an error message on the other fields that the user didn't fill out like "Error Missing Field , Please Fill this Field".
def PetRegistration(request):
if request.user.is_authenticated():
return HttpResponseRedirect(reverse('world:HappyLand'))
if request.method =='POST':
form = UserRegistration(request.POST)
if form.is_valid():
user = User.objects.create_user(
username=form.cleaned_data['username'],
email=form.cleaned_data['email'],
password=form.cleaned_data['password']
)
user.is_active = True
user.first_name = form.cleaned_data['name']
user.save()
person = authenticate(
username=form.cleaned_data['username'],
password=form.cleaned_data['password']
)
Person.objects.create(user_id=user.id,
name=form.cleaned_data['name'],birthday=form.cleaned_data['birthday'])
login(request, person)
return HttpResponseRedirect(reverse('world:HappyLand'))
return render(request, 'register.html', {'form': UserRegistration()})
My forms.py
class UserRegistration(forms.Form):
username = forms.CharField()
name = forms.CharField()
email = forms.EmailField()
birthday = forms.DateField(widget=extras.SelectDateWidget(years=range(1950, 2012)))
password = forms.CharField(
widget=forms.PasswordInput(render_value=False)
)
password1 = forms.CharField(
label=(u'Verify Password'),
widget = forms.PasswordInput(render_value=False)
)
def clean_username(self):
username = self.cleaned_data['username']
try:
User.objects.get(username=username)
except User.DoesNotExist:
return username
raise forms.ValidationError(
"That user is already taken , please select another ")
def clean(self):
if self.cleaned_data['password'] != self.cleaned_data['password1']:
raise forms.ValidationError("The password does not match ")
return self.cleaned_data
My models.py
class Person(models.Model):
user = models.ForeignKey(User)
name = models.CharField(max_length=100, blank=True)
birthday = models.DateField(blank=True,null=True)
def __unicode__(self):
return self.name
Problem is with your clean(). In clean(), you are trying to access field password on form's cleaned_data. password will only be available on cleaned_data if the user has filled this field. So, you must check that password is there in cleaned_data before trying to access it.
Changing your clean():
def clean(self):
if 'password' in self.cleaned_data and 'password1' in self.cleaned_data and self.cleaned_data['password'] != self.cleaned_data['password1']:
raise forms.ValidationError("The password does not match ")
return self.cleaned_data
You can provide a keyword argument error_messages on form field for showing error message like "Error Missing Field , Please Fill this Field".
class SomeForm(forms.Form):
name = forms.CharField(error_messages={'required':'Error Missing Field , Please Fill this Field'})
There is a bug in your view.
is_valid() populates errors on the form but this same form instance must be sent to the template so that you can access the errors on the form's fields.
But in your view, you have only one call to render() which gets called even in case of an invalid form on a post request. And in this render(), you are creating a new instance of form. So, this new form which you are sending to template will not have any errors.
So, making slight modification to your view:
def PetRegistration(request):
if request.user.is_authenticated():
return HttpResponseRedirect(reverse('world:HappyLand'))
form = UserRegistration() #This will be used in GET request
if request.method =='POST':
form = UserRegistration(request.POST) #This will be used in POST request
if form.is_valid():
user = User.objects.create_user(
username=form.cleaned_data['username'],
email=form.cleaned_data['email'],
password=form.cleaned_data['password']
)
user.is_active = True
user.first_name = form.cleaned_data['name']
user.save()
person = authenticate(
username=form.cleaned_data['username'],
password=form.cleaned_data['password']
)
Person.objects.create(user_id=user.id,
name=form.cleaned_data['name'],birthday=form.cleaned_data['birthday'])
login(request, person)
return HttpResponseRedirect(reverse('world:HappyLand'))
return render(request, 'register.html', {'form': form})
Notice in your view, I have added form=UserRegistration() before checking if its POST request, and have added the comment at two places where we are instantiating UserRegistration. And then in render(), you should send this form.
Then your {{form.username.errors}} will work.
I just modified your forms.py
class UserRegistration(forms.Form):
username = forms.CharField()
name = forms.CharField()
email = forms.EmailField()
birthday = forms.DateField(widget=extras.SelectDateWidget(years=range(1950, 2012)))
password = forms.CharField(
widget=forms.PasswordInput(render_value=False)
)
password1 = forms.CharField(
label=(u'Verify Password'),
widget = forms.PasswordInput(render_value=False)
)
def clean(self):
cleaned_data = super(UserRegistration, self).clean()
username = cleaned_data.get("username")
password = cleaned_data.get("password")
password1 = cleaned_data.get("password1")
#check if username exist
user = User.objects.filter(username=username)
if user:
raise forms.ValidationError(
"That user is already taken , please select another ")
#check password
if password != password1:
raise forms.ValidationError(
"Your current and confirm password do not match.")
return cleaned_data
i need to create group seekers and user register he has to automatically add to seekers
models.py
class Seeker(models.Model):
user = models.OneToOneField(User)
birthday = models.DateField()
name = models.CharField(max_length=100)
def __unicode__(self):
return self.name
forms.py
this is the default user for storing the userid & password for my application
class RegistrationForm(ModelForm):
username = forms.CharField(label = (u'User Name'))
email = forms.EmailField(label =(u'Email Address'))
password = forms.CharField(label = (u'Password'),widget = forms.PasswordInput(render_value = False))
password1 = forms.CharField(label =(u'Verify Password'),widget = forms.PasswordInput(render_value = False))
class Meta:
model = Seeker
exclude = ('user',)
def clean_username(self):
username = self.cleaned_data['username']
try:
User.objects.get(username = username)
except User.DoesNotExist:
return username
raise forms.ValidationError("That username is already taken,please select another.")
def clean(self):
if self.cleaned_data['password'] != self.cleaned_data['password1']:
raise forms.ValidationError("The Password did not match please try again.")
return self.cleaned_data
views.py
i am using default user for creating the user
def SeekersRegistration(request):
if request.user.is_authenticated():
return HttpResponseRedirect('/profile/')
if request.method == "POST":
form = RegistrationForm(request.POST)
if form.is_valid():
user = User.objects.create_user(username = form.cleaned_data['username'], email = form.cleaned_data['email'], password =form.cleaned_data['password'])
user.save()
seekers = Seeker(user =user, name = form.cleaned_data['name'],birthday = form.cleaned_data['birthday'])
seekers.save()
return HttpResponseRedirect('/profile/')
else:
return render_to_response('register.html',{'form':form},context_instance = RequestContext(request))
else:
'''user is not submitting the form, show them a blank registration form'''
form = RegistrationForm()
context = {'form':form}
return render_to_response('register.html',context,context_instance = RequestContext(request))
Use signals
from django.contrib.auth.models import User
from django.db.models.signals import post_save
from django.dispatch import receiver
#receiver(post_save, sender=User)
def add_user_to_specific_group(instance, created, **kwargs):
if created:
# assign user to group