Django Edit Profile View not saving new email value - django

I am (attempting to) implement the ability for a user to edit and update their email address on their profile page. I am getting no errors when doing this end to end but the new email is not being saved to the DB.
Everything seems to be working, even the redirect to the profile page in the edit_profile function, but the save() doesn't seem to be working, the users email doesn't update and when I am redirected back to the profile page, the email is still the current value.
Thanks!
Model:
class CustomUser(AbstractUser):
email = models.EmailField(_('email address'), unique=True)
is_pro = models.BooleanField(default=False)
is_golfer = models.BooleanField(default=False)
def __str__(self):
return self.email
Form
class EditProfileForm(forms.Form):
email = forms.EmailField(
label='', widget=forms.TextInput(attrs={'class': 'form-field'}))
View
#login_required
def edit_profile(request):
if request.method == "POST":
form = EditProfileForm(request.POST)
if form.is_valid():
email = form.cleaned_data["email"]
user = CustomUser.objects.get(id=request.user.id)
user.save()
return redirect("typeA", username=user.username)
else:
form = EditProfileForm()
return render(request, "registration/edit_profile.html", {'form': form})
URLS
urlpatterns = [
path('type_a_signup/', ASignUpView.as_view(), name='a_signup'),
path('type_b_signup/', BSignUpView.as_view(), name='b_signup'),
path('login/', LoginView.as_view(), name='login'),
path('password_reset', PasswordResetView.as_view(), name='password_reset'),
path('typea/<username>/', typeA, name='typeA'),
path('typeb/<username>/', typeB, name='typeB'),
path('login_success/', login_success, name='login_success'),
path('edit_profile/', edit_profile, name='edit_profile'),
]
Template
<div class="container">
<div class="form-container">
<h2>Edit profile</h2>
<form method="post" enctype="multipart/form-data">
{% csrf_token %}
<div>
{{ form.email.label_tag }}
<input type="text" class="form-control {% if form.email.errors %}is-invalid{% endif %}" id="id_email"
name="email" value='{{ form.email.value|default:user.email }}'>
{% if form.email.errors %}
<div>{{ form.email.errors }}</div>
{% endif %}
</div>
<button type="submit">Submit</button>
</form>
<br>
</div>

You never set the email field of the object. You should set this with:
#login_required
def edit_profile(request):
if request.method == "POST":
form = EditProfileForm(request.POST)
if form.is_valid():
email = form.cleaned_data["email"]
user = request.user
user.email = email # 🖘 set the email field
user.save()
return redirect("typeA", username=user.username)
else:
form = EditProfileForm()
return render(request, "registration/edit_profile.html", {'form': form})
You should only redirect in case the form is successful. If it is not, Django will rerender the form with the errors.

Related

authenticate() is not validate data properly django

When I try to click on login button it always execute the invalid credentials instead of redirect to the index page.. What I did is that in database create table name signup and wants to validate all the data from that table.. Here signup_data function is works well but in login_data cannot authenticate the user.
Models.py
from django.db import models
class signup(models.Model):
username = models.CharField(max_length=10)
first_name = models.CharField(max_length=20)
last_name = models.CharField(max_length=20)
email = models.EmailField()
password = models.CharField(max_length=10)
Forms.py
from django.forms import ModelForm
from . models import signup
from django import forms
class signupform(ModelForm):
username= forms.CharField(max_length=10,widget=forms.TextInput(attrs={'class':'form-control'}))
first_name = forms.CharField(max_length=20, widget=forms.TextInput(attrs={'class': 'form-control'}))
last_name = forms.CharField(max_length=20,widget=forms.TextInput(attrs={'class': 'form-control'}))
email = forms.EmailField(max_length=20,widget=forms.EmailInput(attrs={'class': 'form-control'}))
password = forms.CharField(max_length=10,widget=forms.PasswordInput(attrs={'class':'form-control'}))
class Meta:
model = signup
fields = '__all__'
Views.py
from django.shortcuts import render,redirect
from . forms import signupform
from . models import signup
from django.contrib import messages
from django.contrib.auth import login,authenticate
def index(response):
return render(response,'login_module/index.html')
def signup_data(response):
if response.method == 'POST':
form = signupform(response.POST)
if form.is_valid():
username = form.cleaned_data['username']
first_name = form.cleaned_data['first_name']
last_name = form.cleaned_data['last_name']
email = form.cleaned_data['email']
password = form.cleaned_data['password']
if signup.objects.filter(username=username).exists():
# messages.add_message(response,messages.WARNING,'Username is already taken')
messages.error(response,'Username is already taken')
return redirect('signup')
elif signup.objects.filter(email=email).exists():
messages.error(response,'Email is already taken')
# messages.add_message(response,messages.WARNING,'Email is already taken')
return redirect('signup')
else:
register_instance = signup(username=username, first_name=first_name, last_name=last_name, email=email, password=password)
register_instance.save()
messages.success(response,'Registered Successfull')
return redirect('signup')
else:
form = signupform()
return render(response,'login_module/signup.html',{'form':form, 'message': messages})
def login_data(request):
form = signupform(request.POST or None)
if request.method == "POST":
username = request.POST['username']
password = request.POST['password']
user = authenticate(username=username, password=password)
if user is not None:
login(request,user)
return redirect('index')
else:
messages.error(request,'Invalid Credentials')
return redirect('login')
else:
return render(request,'login_module/login.html',{'form':form, 'message': messages})
Login.html
{% extends 'login_module/base.html' %}
{% block content %}
<div class="container">
<div class="row">
<div class="col-md-12 text-center mt-50">
<h1>Login Page</h1>
</div>
</div>
<div class="row">
<div class="col-md-4 offset-md-4 ">
<form method="post" action="{% url 'login' %}">
{% csrf_token %}
<div class="form-group rounded-top">
{{ form.username.label_tag }} {{ form.username }}
</div>
<div class="form-group rounded-top">
{{ form.password.label_tag }} {{ form.password }}
</div>
<div class="text-center">
<button type="submit" class="btn btn-primary">Login</button>
</div>
</form>
</div>
</div>
<div class="text-center mt-50">
{% if messages %}
{% for message in messages %}
<div class="alert alert-danger" role="alert">
{{ message }}
{% endfor %}
{% endif %}
</div>
</div>
{% endblock %}
Login Page
As far as I can tell you are creating a signup object when signing up, but when trying to login with authenticate django is looking for the generic User model. You have to create a User in the database rather than a signup object to use authenticate.

Django custon form with validate

I have some problem with the form and Django.
I would like to do a custom (in column and with style) form from a model. But after few hours to try I thinks it's not possible.
So I decide to create not a forms.ModelForm but a forms.Form, in order to custom my form. But in this way i can't keep the validations...
And last thing I try, it in the template file to write a validation manually, it's work but when I submit my form with error, and when it's refresh, all the data are loose, and I see just the error message...
So it make me crazy... I just would like to do a nice form with django...
Thanks in advance
forms.py
class PatienceForm(forms.ModelForm):
class Meta:
model = Patience
fields = ('nom', 'prenom', 'age', 'email')
template.html
<form method="POST" accept-charset="utf-8">
{% csrf_token %}
<p><label for="id_nom">Nom :</label> <input type="text" name="nom" maxlength="200" required id="id_nom"></p>
<p><label for="id_prenom">Prenom :</label> <input type="text" name="prenom" maxlength="200" required id="id_prenom"></p>
<p><label for="id_age">Age :</label> <input type="number" name="age" required id="id_age"></p>
<p><label for="id_email">Email :</label> <input type="email" name="email" maxlength="254" required id="id_email"></p>
{% for err in form.email.errors %}
{{err}}
{% endfor %}
<button type="submit" class="save btn btn-default">Save</button>
view.py
def post_essaie(request):
if request.method == "POST":
form = PatienceForm(request.POST)
if form.is_valid():
logging.info('Hello')
post = form.save(commit=False)
post.published_date = timezone.now()
post.save()
return render(request, 'blog/succes.html')
return render(request, 'blog/teste.html', {'form': form})
else:
form = PatienceForm()
return render(request, 'blog/teste.html', {'form': form})
Thanks in advance for your help
for your form.py :
class PatienceForm(forms.Form):
nom = forms.CharField(max_length=200,label='Nom')
prenom = forms.CharField(max_length=200)
age = forms.integerField(max_length=200)
email = forms.EmailField(max_length=254)
# use clean to verify your form
def clean(self):
cleaned_data = super(ContactForm, self).clean()
nom = cleaned_data.get('nom')
prenom = cleaned_data.get('prenom')
age = cleaned_data.get('age')
email = cleaned_data.get('email')
if not name and not email and not message:
raise forms.ValidationError('le formulaire est vide')
in your views.py you can use :
from django.shortcuts import render
from .forms import ContactForm
def post_essaie(request):
if request.method == 'POST':
form = PatienceForm(request.POST)
if form.is_valid():
logging.info('Hello')
nom = form.cleaned_data['nom']
prenom = form.cleaned_data['prenom']
age = form.cleaned_data['age']
email = form.cleaned_data['email']
# here create your entry with all the data from your form then add
# your published_date
post = Patience(nom=nom, prenom=prenom, age=age,
email=email, published_date = timezone.now())
post.save()
return render(request, 'blog/succes.html')
else:
form = PatienceForm()
return render(request, 'blog/teste.html', {'form': form})
Voila Bonne journée !!

How to use form_validate() with CustomForm in Django

I'm creating an app in which I'd like to use my own custom login form with a captcha field. My intention is to do this without using an external library (except for requests) but I couldn't add captcha field to my custom form in forms.py, so I added it directly to login.html but for some reason when I do form.is_valid() it returns an error.
I've already seen the solutions in Django - adding google recaptcha v2 to login form and Adding a Recaptcha form to my Django login page but as I said, I'd like to do this without using an external library.
views.py
...
def login_view(request):
if request.method == 'POST':
form = CustomLoginForm(request.POST)
result = is_recaptcha_valid(request)
print(result) # prints True
if form.is_valid():
username = form.cleaned_data['username']
email = form.cleaned_data['email']
password = form.cleaned_data['password']
user = authenticate(request, username=username, password=password)
if user is not None:
login(request, user)
# Redirect to index
messages.success(request, "Logged in.")
return HttpResponseRedirect(reverse('orders:index'))
else:
messages.error(request, "Invalid credentials.")
else:
print("error")
return render(request, 'registration/login.html', {'form': CustomLoginForm()})
else:
form = CustomLoginForm()
return render(request, 'registration/login.html', {'form': form})
forms.py
class CustomLoginForm(AuthenticationForm):
email = forms.EmailField(
error_messages={
'required': 'Please enter your email.',
'invalid': 'Enter a valid email address.'
},
help_text='Email',
)
login.html
<form class="" action="{% url 'orders:login' %}" method="post">
{% csrf_token %}
{% for field in form %}
<p>
{{ field.label_tag }}<br>
{{ field }}
{% if field.help_text %}
<small style="color: grey">{{ field.help_text }}</small>
{% endif %}
{% for error in field.errors %}
<p style="color: red">{{ error }}</p>
{% endfor %}
</p>
{% endfor %}
<!-- ReCAPTCHAV3 -->
<script src="https://www.google.com/recaptcha/api.js" async defer></script>
<div class="g-recaptcha" data-sitekey='key-here'></div>
<button class="btn btn-success" type="submit" name="">Login</button>
<!-- <input type="hidden" name="next" value="{{ next }}"> -->
</form>
is_recaptcha_valid() function already returns True so I didn't share that. I'm a beginner in Django, so if you can please explain in two words what I've done wrong instead of just posting the answer, I'd be grateful. Thank you for your time.
The AuthenticationForm is slightly different than the others..
If your check AuthenticationForm class, AuthenticationForm 's first arguments is not data like others form:
class AuthenticationForm(forms.Form):
...
def __init__(self, request=None, *args, **kwargs):
...
Thats why you need to pass request.POST to data.
So update your code like this:
def login_view(request):
if request.method == 'POST':
form = CustomLoginForm(data=request.POST)
...

help_text for username and email fields always output in browser

I have this model:
class User(AbstractUser):
REQUIRED_FIELDS = []
USERNAME_FIELD = 'email'
email = models.EmailField(
_('email address'),
max_length=150,
unique=True,
help_text=_('Required. 150 characters of fewer. Must be a valid email address.'),
error_messages={
'unique':_("A user with that email address already exists."),
},
)
this form class:
class UserForm(forms.ModelForm):
password = forms.CharField(widget=forms.PasswordInput)
class Meta:
model = User
fields = ['username','email','password']
this view class:
class UserFormView(View):
form_class = UserForm
template_name = 'workoutcal/register.html'
def get(self, request):
print("Hi again")
form = self.form_class(None)
return render(request, self.template_name, {'form':form})
def post(self, request):
form = self.form_class(request.POST)
if form.is_valid():
user = form.save(commit=False)
username = form.cleaned_data['username']
password = form.cleaned_data['password']
user.set_password(password)
user.save()
user = authenticate(username=username, password=password)
if user is not None:
if user.is_active:
login(request, user)
return redirect('workoutcal:calendar')
return render(request, self.template_name, {'form': form})
and this url:
url(r'^register/$', views.UserFormView.as_view(), name='register')
So when I go to /workoutcal/register, I see this:
The "help text" is always shown in the browser. Is this default Django behaviour, or is it due to some error I have made?
Also, how do I make the text only show up if the user has entered bad data into the respective fields?
Yes if you are using {{ form }} in your template
It will always show help_text, label, errors and widget automatically
If you don't want that you need to render form manually by looping over fields
<form method="post" novalidate>
{% csrf_token %}
{{ form.non_field_errors }}
{% for hidden_field in form.hidden_fields %}
{{ hidden_field.errors }}
{{ hidden_field }}
{% endfor %}
{% for field in form.visible_fields %}
<div class="fieldWrapper">
{{ field.errors }}
{{ field.label_tag }} {{ field }}
{{ field.help_text }} <!-- remove this line if you don't want to show it in your html.-->
</div>
{% endfor %}
<button type="submit">Submit</button>
</form>
For more read docs: https://docs.djangoproject.com/en/2.0/topics/forms/

Django model form for user profile won't pre-populate

I've made a profile model in models.py:
class Profile(models.Model):
user = models.OneToOneField(User)
title = models.CharField(max_length=20, default='title')
firstname = models.CharField(max_length=40, default='firstname')
lastname = models.CharField(max_length=40, default='lastname')
blurb = models.CharField(max_length=500, default='tell us about yourself')
#work out how to make filename equal the username
pic = models.ImageField(default="static/profile/blank.png", upload_to='static/profile/%d%m%y.jpg') #+ user.pk + '.jpg')
def __unicode__(self):
return self.user.username
and here is the view for a page to edit the profile of a logged in user:
def editprofile(request):
u_p = request.user.profile
template = loader.get_template('registration/editprofile.html')
if request.method == 'POST':
form = ProfileForm(request.POST, instance=u_p)
if form.is_valid():
form.save()
else:
# todo
None
else:
#todo
context = RequestContext(request, {'form': form})
return HttpResponse(template.render(context))
The template fragment reads:
<form method="POST" action=".">
{% csrf_token %}
<div class="regformout">
<div class="regform">
{% for field in form %}
<div class='cell'> {{ field.label_tag }} </div>
<div class='nogin'> {{ field.errors }} </div>
<div class='cell'> {{ field }} </div>
{% endfor %}
</div>
</div>
<input class="btn btn-large btn-primary" type="submit" value="Save Your Profile" ></input>
</form>
I want the form fields to automatically populate with the data for the current user on the corresponding page for editing the profile. However, no matter what I try I cannot make this happen. What am I doing wrong here?
Your main problem is you are only populating the form if the user hits the submit button, so when the view is requested initially, your form is empty.
from django.shortcuts import render, redirect
def editprofile(request):
u_p = request.user.profile
form = ProfileForm(request.POST or None, instance=u_p)
if request.method == 'POST':
if form.is_valid():
form.save()
return redirect('/')
return render(request,
'registration/editprofile.html', {'form': form})