Hi I'm working on a form to edit a user's profile. It properly updates the fields upon successful submission without any validation errors. The problem I'm having is that if the form does return a validation error upon submission and I've changed the name on the form, the template will display this new name instead of the old name. I'm assuming this is because it uses the user context provided by the POST request. Is there any way to properly display the user's old name until the form is actually successfully submitted? Below is my code.
forms.py
from django import forms
from django.contrib.auth.models import User
from django.contrib.auth.forms import UserCreationForm
from django.forms import ModelForm
class UserProfileForm(UserCreationForm):
first_name = forms.CharField(label="First Name", required=True)
last_name = forms.CharField(label="Last Name", required=True)
email = forms.EmailField(label="Email", required=True)
class Meta:
model = User
fields = ("first_name", "last_name", "email", "username", "password1", "password2")
def clean_email(self):
email = self.cleaned_data.get('email')
if email:
if User.objects.filter(email=email).exists():
raise forms.ValidationError('This email is already in use.')
return email
def save(self, commit=True):
user = super(UserProfileForm, self).save(commit=False)
user.email = self.cleaned_data["email"]
if commit:
user.save()
return user
class EditProfileForm(ModelForm):
first_name = forms.CharField(label="First Name", required=True)
last_name = forms.CharField(label="Last Name", required=True)
email = forms.EmailField(label="Email", required=True)
password1 = forms.CharField(label="New Password", widget=forms.PasswordInput)
password2 = forms.CharField(label="Repeat New Password", widget=forms.PasswordInput)
class Meta:
model = User
fields = ("first_name", "last_name", "email", "username", "password1", "password2")
def clean_email(self):
email = self.cleaned_data.get('email')
if email:
if User.objects.filter(email=email).exists():
raise forms.ValidationError('This email is already in use.')
return email
def save(self, commit=True):
user = super(EditProfileForm, self).save(commit=False)
user.email = self.cleaned_data['email']
if commit:
user.save()
return user
views.py
def register(request):
if request.method == 'POST':
form = UserProfileForm(request.POST)
if form.is_valid():
form.save()
new_user = authenticate(username=form.cleaned_data['username'],
password=form.cleaned_data['password1'])
login(request, new_user)
return redirect('/overview')
else:
if request.user.is_authenticated():
return redirect('/overview')
else:
form = UserProfileForm()
return render(request, "/register.html", {'form': form})
#login_required
def edit_profile(request):
if request.method == 'POST':
print request.POST
form = EditProfileForm(request.POST, instance=request.user)
if form.is_valid():
form.save()
return redirect('/profile')
else:
form = EditProfileForm()
return render(request, '/edit_profile.html', {'form': form})
navbar.html
<li class="">
<a href="javascript:;" class="user-profile dropdown-toggle" data-toggle="dropdown" aria-expanded="false">
<img src="/ui/assets/images/user.png" alt="">{{ user.first_name }} {{ user.last_name }}
<span class=" fa fa-angle-down"></span>
</a>
<ul class="dropdown-menu dropdown-usermenu pull-right">
<li> Profile</li>
<li><i class="fa fa-sign-out pull-right"></i> Log Out</li>
</ul>
</li>
Fetch a separate instance of the user from the db to use with the form. This way, the request.user will not be modified when the form is validated.
user = User.objects.get(id=request.user.id)
form = EditProfileForm(request.POST, instance=user)
Related
I have issue is that in template, I automatically get access of username of Superuser (if that is logged-in) but not username of user based on Buyer (Model). User is getting registered and also can login (I can see it in database). But in template I am unable to get username of user other than superuser. I don't what i am missing here. So i am putting all code of view.py here. Also after user logging he sees bookrepo:home and i am using user logic in header.html (bookrepo:home extends header.html)
I have model named Buyer in models.py file. And based on this model, two modelForm has made.
This is code of model.py
class Buyer(models.Model):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
user = models.OneToOneField(User, on_delete=models.DO_NOTHING)
# additional attributes
contact = models.CharField('Contact #', max_length=16, unique=True, validators=[
RegexValidator(
regex=r'^\+?1?\d{9,15}$',
message="Phone number (Up to 15 digits) must be entered in the format: '+923001234567'."
),
], )
devices = models.CharField('Devices', unique=False, max_length=115, blank=True)
picture = models.ImageField(upload_to=profile_pic_path, null=True,blank=True)
def __str__(self):
return "{} {}".format(self.user.first_name, self.user.last_name)
class Meta:
get_latest_by = '-user.date_joined'
This is code of modelForms
class RegistrationForm(forms.ModelForm):
password = forms.CharField(widget=forms.PasswordInput())
confirm_password = forms.CharField(widget=forms.PasswordInput())
class Meta():
model = User
fields = ('username',
'email',
'password')
def clean(self):
cleaned_data = super(RegistrationForm, self).clean()
password = cleaned_data.get("password")
confirm_password = cleaned_data.get("confirm_password")
if password != confirm_password:
raise forms.ValidationError(
"Password and Confirm Password does not match"
)
class RegistrationFormPlus(forms.ModelForm):
class Meta():
model = Buyer
fields = ('contact',)
This is code of header.html (NOT the home.html)
{% if user.is_authenticated %}
<a class="nav-link" href="{% url 'bookrepo:logout' %}">Logout</a>
<h2>Welcome {{ user.username }}!</h2>
{% else %}
<a class="nav-link" href="{% url 'bookrepo:user_login' %}">Login</a>
{% endif %}
This is code of views.py
def home(req):
bookz = Book.objects.order_by('title')
var = {'books': bookz, 'range': 10}
return render(req, 'bookrepo/home.html', context=var)
def registration(request):
registered = False
if request.method == 'POST':
reg_form = RegistrationForm(data=request.POST)
reg_form_plus = RegistrationFormPlus(data=request.POST)
if reg_form.is_valid() and reg_form_plus.is_valid():
user = reg_form.save()
user.set_password(user.password)
user.save()
user_plus = reg_form_plus.save(commit=False)
user_plus.user = user
user_plus.save()
registered = True
else:
print(reg_form.errors, reg_form_plus.errors)
print("else 2 chala")
else:
reg_form = RegistrationForm()
reg_form_plus = RegistrationFormPlus()
return render(request, 'bookrepo/signup.html',
{'reg_form': reg_form,
'reg_form_plus': reg_form_plus,
'registered': registered
})
#login_required
def special(request):
return HttpResponse("You are logged in. Nice!")
#login_required
def user_logout(request):
logout(request)
return HttpResponseRedirect(reverse('bookrepo:home'))
def user_login(request):
if request.method == 'POST':
username = request.POST.get('username')
password = request.POST.get('password')
user = authenticate(username=username, password=password)
if user:
return HttpResponseRedirect(reverse('bookrepo:home'))
else:
print("Someone tried to login and failed.")
print("They used username: {} and password: {}".format(username, password))
return HttpResponse("Invalid login details supplied.")
else:
return render(request, 'bookrepo/login.html', {})
You should use {{ buyer.user.username }} in your template to show the username of a user.
You are trying to extend your django user framework with a One To One Field . new extended Django Model used to store the extra information that relates to the User Model. {{user.username}} gives the username from session.
use this code to authenticate users don't forgot to import
from django.contrib.auth.models import User,auth
def login(request):
if request.method == "POST":
username = request.POST['username']
password = request.POST['password']
user=auth.authenticate(username=username,password=password)
if user is not None:
auth.login(request,user)
return redirect('index')
else:
messages.info(request,'invalid user')
return redirect('login')
else:
return render(request,"login.html")
views.py. My default user login template, I have tried both methods listed below and don't know where I am makeing a mistake - I get an error that my credentials are incorrect every time
def signup(request):
if request.method == 'POST':
form = SignUpForm(request.POST)
if form.is_valid():
user = form.save()
user.refresh_from_db() # load the profile instance created by the signal
user.profile.university = form.cleaned_data.get('university')
user.save()
raw_password = form.cleaned_data.get('password1')
user = authenticate(username=user.username, password=raw_password)
#user_login(request, user)
return redirect('main:main_page')
else:
form = SignUpForm()
return render(request, 'signup.html', {'form': form})
def user_login(request):
'''
Using different method for getting username, tried this and didn't work either
if request.method == 'POST':
form = AuthenticationForm(request, data=request.POST)
if form.is_valid():
username = form.cleaned_data.get('username')
password = form.cleaned_data.get('password')
user = authenticate(username=username, password=password)
if user is not None:
login(request,user)
messages.info(request, "Successfully signed in")
return redirect('main:home')
else:
message = 'Sorry, the username or password you entered is not valid please try again.'
return render(request, 'login.html', {'message':message})
else:
message = 'Invalid'
return render(request, 'login.html', {'message':message})
else:
form=AuthenticationForm()
return render(request, 'login.html', {"form":form})
'''
if request.method == 'POST':
username = request.POST.get('username')
password = request.POST.get('password')
user = authenticate(username=username, password=password)
if user is not None:
if user.is_active:
login(request,user)
return HttpResponseRedirect(reverse('index'))
else:
return HttpResponse("Your account was inactive.")
else:
message = 'Sorry, the username or password you entered is not valid please try again.'
return render(request, 'login.html', {'message':message})
else:
message = 'Request failed please try again.'
return render(request, 'login.html', {'message':message})
models.py
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
first_name = models.CharField(max_length=100, blank=True)
last_name = models.CharField(max_length=100, blank=True)
email = models.EmailField(max_length=150)
bio = models.TextField()
university = models.CharField(max_length=30)
def __str__(self):
return self.user.username
#receiver(post_save, sender=User)
def update_profile_signal(sender, instance, created, **kwargs):
if created:
Profile.objects.create(user=instance)
instance.profile.save()
forms.py
class SignUpForm(UserCreationForm):
university = forms.CharField(max_length=30)
class Meta:
model = User
fields = ('username', 'first_name', 'last_name', 'email','university', 'password1', 'password2',)
app urls.py
app_name = 'main'
urlpatterns=[
path('signup/',views.signup,name='signup'),
path('user_login/',views.user_login,name='user_login'),
path('main_page/',views.main_page,name='main_page'),
]
login.html form
<form method="POST" action="{% url 'main:user_login' %}/" class="form-signin">
{%csrf_token%}
<div class="form-label-group">
<input type="text" name="username" id="inputText" class="form-control" placeholder="Username" required autofocus>
<br/>
</div>
<div class="form-label-group">
<input type="password" name="password" id="inputPassword" class="form-control" placeholder="Password" required>
</div>
<div class="custom-control custom-checkbox mb-3">
<input type="checkbox" class="custom-control-input" id="customCheck1">
<label class="custom-control-label" for="customCheck1">Remember password</label>
</div>
<input type="submit" class="form-control" name="" value="Login">
<hr class="my-4">
<p>Don't have account? Sign up here</p>
{% if message %}<p style="color: red;">{{message}}</p>{% endif %}
Forgot Password
</form>
I cannot figure out why my Django does not accept correct credentials. Which part of my code seems to be incorrect?
make sure to define the right user model to django settings, add
# AUTH_USER_MODEL = 'YOUR_APP_NAME.YOUR_CUSTOM_USER_MODEL'
to your django settings .like # AUTH_USER_MODEL = 'users.User'
and you need to write an abstract user model .
from django.contrib.auth.models import AbstractUser
class RightsSupport(models.Model):
class Meta:
managed = False # No database table creation or deletion \
# operations will be performed for this model.
permissions = (
("add_user", "Can Create User"),
("view_user", "Can View Single User"),
("change_user", "Can Change User"),
("list_user", "Can View User List"),
("add_plan", "Can Create Plan"),
("view_plan", "Can View Single Plan"),
("change_plan", "Can Change Plan"),
("list_plan", "Can View Plan List"),
)
class User(AbstractUser):
CREATED = 0
ACTIVE = 1
BANNED = 2
KICKED = 3
UPGRADE = 4
STS = (
(CREATED, 'Just Created'),
(ACTIVE, 'Activated'),
(BANNED, 'Disabled'),
(KICKED, 'Disabled'),
(UPGRADE, 'Active'),
)
status = models.IntegerField(choices=STS, default=CREATED, blank=True, null=True)
def __str__(self):
return self.username
also update your view, that code has a huge mistake on it . you forget to close docstring .
def signup(request):
if request.method == 'POST':
form = SignUpForm(request.POST)
if form.is_valid():
user = form.save()
user.refresh_from_db() # load the profile instance created by the signal
user.profile.university = form.cleaned_data.get('university')
user.save()
raw_password = form.cleaned_data.get('password1')
user = authenticate(username=user.username, password=raw_password)
#user_login(request, user)
return redirect('main:main_page')
else:
form = SignUpForm()
return render(request, 'signup.html', {'form': form})
def user_login(request):
'''
Using different method for getting username, tried this and didnt work either
'''
if request.method == 'POST':
form = AuthenticationForm(request, data=request.POST)
if form.is_valid():
username = form.cleaned_data.get('username')
password = form.cleaned_data.get('password')
user = authenticate(username=username, password=password)
if user is not None:
login(request,user)
messages.info(request, "Successfully signed in")
return redirect('main:home')
else:
message = 'Sorry, the username or password you entered is not valid please try again.'
return render(request, 'login.html', {'message':message})
else:
message = 'Invalid'
return render(request, 'login.html', {'message':message})
else:
form=AuthenticationForm()
return render(request, 'login.html', {"form":form})
When new users register I want to store:
fields = ['username', 'email', 'password1', 'password2', 'city']
so I extended UserRegisterForm by adding 'city' to the form.
It renders fine in the template and save everything except 'city'. There is no even column 'city' in the new users profile when checking by admin page so looks like its not creating one.
I found few similar posts and been following Doc but that didint help.
Have tried many different ways but will post two I think mostly sensible ones.
EXAMPLE 1
- *forms.py*
...
from django import forms
from django.contrib.auth.models import User
from django.contrib.auth.forms import UserCreationForm
class UserRegisterForm(UserCreationForm):
email = forms.EmailField()
city = forms.CharField(required=True)
class Meta:
model = User
fields = ['username', 'email', 'password1', 'password2', 'city']
def save(self, commit=True):
user = super(UserRegisterForm, self).save(commit=False)
user.city = self.cleaned_data['city']
if commit:
user.save()
return user
- *views.py*
...
from django.contrib.auth.forms import UserCreationFormfrom
from .forms import UserRegisterForm
def register(request):
if request.method == 'POST':
form = UserRegisterForm(request.POST)
if form.is_valid():
form.save()
print('VALID')
username = form.cleaned_data.get('username')
messages.success(request,
'{} Your account has been created! You can now Log In'.format(username))
return redirect('/login/')
else:
form = UserRegisterForm()
context = {
'form': form,
}
return render(request, 'users/register.html', context)
#login_required
def profile(request):
return render(request, 'users/profile.html')
- *template*
...
<form method="POST">
{% csrf_token %}
{{ form|crispy }}
<!-- {{ form2 }} -->
<button class="btn-signup" type="submit">Sign Up</button>
</form>
In Example 2 Iam creating new class 'ProfileForm' with new model as separate form and including it in the views.py in one function with UserRegisterForm.
EXAMPLE 2
- *models.py*
...
class Profile(models.Model):
city = models.CharField(max_length=25, blank=False)
def __str__(self):
return self.city
- *forms.py*
...
class UserRegisterForm(UserCreationForm):
email = forms.EmailField()
city = forms.CharField(required=True)
class Meta:
model = User
fields = ['username', 'email', 'password1', 'password2', 'city']
class ProfileForm(forms.ModelForm):
class Meta:
model = Profile
fields = ['city']
def save(self, commit=True):
user = super(UserRegisterForm, self).save(commit=False)
user.city = self.cleaned_data['city']
if commit:
user.save()
return user
- *views.py*
...
from django.contrib.auth.forms import UserCreationFormfrom
from .forms import UserRegisterForm, ProfileForm
def register(request):
if request.method == 'POST':
form = UserRegisterForm(request.POST)
form2 = ProfileForm(request.POST)
if form.is_valid() and form2.is_valid():
form.save()
form2.save()
print('VALID')
username = form.cleaned_data.get('username')
messages.success(request,
'{} Your account has been created! You can now Log In'.format(username))
return redirect('/login/')
else:
form = UserRegisterForm()
form2 = ProfileForm()
context = {
'form': form,
'form2': form2
}
return render(request, 'users/register.html', context)
- *template*
...
<form method="POST">
{% csrf_token %}
{{ form|crispy }}
{{ form2 }}
<button class="btn-signup" type="submit">Sign Up</button>
</form>
Your Profile model should have a OneToOne relation with the User model like this:
Class Profile (models.Model):
user = models.OneToOneField (User,on_delete=models.CASCADE)
city = models.CharField (max_length=25,blank=False)
You don't need to define ProfileForm.You can create profile objects for the user like this.
form = UserRegisterForm (request.POST)
if form.is_valid ():
city = form.cleaned_data ['city']
user = form.save ()
Profile.objects.create (user=user,city=city)
return redirect ('some_view)
I'd like to make auth_user_model login but I need to login with Email and Password. So I thought I can do that if I can save email value in 'username' field.
class HeepooUser(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
phone = models.CharField(max_length=15, null=True)
allow_phone = models.BooleanField(default=False)
school = models.ForeignKey(School)
date_join = models.DateTimeField(auto_now_add=True)
def register(request):
registered = False
if request.method == 'POST':
user_form = UserForm(request.POST)
profile_form = RegisterForm(request.POST)
if user_form.is_valid() and profile_form.is_valid():
user = user_form.save(commit=False)
user.set_password(user.password)
user = user_form.save()
profile = profile_form.save(commit=False)
profile.user = user
profile = profile_form.save()
registered = True
return HttpResponseRedirect("/books/")
else:
return HttpResponse('Wrong access1')
else:
user_form = UserForm()
profile_form = RegisterForm()
return render(request, "register.html", {
'user_form': user_form,
'profile_form': profile_form,
'registered': registered,
})
forms.py
class UserForm(forms.ModelForm):
email = forms.EmailField(max_length=50, required=True,
widget=forms.TextInput(attrs={'class':'form-control', }),
)
password = forms.CharField(widget=forms.PasswordInput())
class Meta:
model = User
fields = ('email', 'password',)
class RegisterForm(forms.ModelForm):
class Meta:
model = HeepooUser
exclude = ('allow_phone', 'user',)
Register.html
<form action="" method="post">
{% csrf_token %}
{{ user_form.as_p }}
{{ profile_form.as_p }}
<input type="submit" value="Register">
</form>
Could you please help me on?
Thanks!
You can request the email instead of username to the user in your login form in order to use it for loggin him, then just generate a username for that user, you can do it using his email or name.
EDIT:
You only need to generate an username. Let's say that you are requesting name and last name to the user. Let's create a method to generate it.
def generate_username(first_name, last_name):
username = '%s.%s' % (first_name.lower(), last_name.lower())
username = '{:.29}'.format(username)
counter = User.objects.filter(first_name=first_name,last_name=last_name).count()
if counter > 0:
username += '%s' % (counter + 1)
return username
Then you can use it on your view.
user = user_form.save(commit=False)
user.set_password(user.password)
user.username = generate_username(first_name, last_name)
.....
If you don't want to request first name or last name, you can generate the username using his email too.
My forms.py file:
class RegisterForm(ModelForm):
"""This form lets people register as members."""
help_string = "Please choose a password that is at 6 characters long,"\
"and contains at least on speacial character or number"
First_Name = forms.CharField(max_length=50)
Last_Name = forms.CharField(max_length=50)
Username = forms.CharField(max_length=50)
Password = forms.CharField(max_length=50)
Confirm_Password = forms.CharField(max_length=50)
Email_Address = forms.EmailField()
Address = forms.CharField(widget=forms.Textarea)
def save(self, commit=True):
cd = self.cleaned_data
u = User.objects.create_user(
username=self.cleaned_data['Username'],
email=self.cleaned_data['Email_Address'],
password=self.cleaned_data['Password'],
)
u.is_staff = True
u.save()
u.First_Name = self.cleaned_data['First_Name']
u.Last_Name = self.cleaned_data['Last_Name']
m = self.instance
m.user = u
if not commit:
return [m, u]
u.save()
m.save()
return m
My views.py file:
def register(request):
if request.method == "POST":
form = RegisterForm(request.POST)
if form.is_valid():
try:
instance = form.save()
return HttpResponseRedirect('/registered/')
except:
return HttpResponseRedirect('/validation/')
else:
form = RegisterForm()
return render_to_response(
'homepage/register.html',
{'form':form,},
context_instance=RequestContext(request),
)
My register.html template:
<h4>Register</h4>
<form action="" method="POST">
<table border="0" cellpadding="1" cellspacing="1" id="eric">
<tr>
<td>{{ form.as_table }}</td>
</tr>
<tr>
<td></td>
<td>
<input type="submit" value="Create Account">
<input type="Reset" value="Clear"></td>
</tr>
</table>
</form>
The thing what it does in views.py is skip the try block and execute the except.
What should I do or change?
So, You are saving the data twice. And in your model definition username must be unique. So, throwing integrity error. You are saving data in
1.) Forms save
2.) again same data you are saving in Views.
My suggestion.
clean your data in the forms.
Remove save() from forms.
save form in views.
class RegisterForm(ModelForm):
"""This form lets people register as members."""
help_string = "Please choose a password that is at 6 characters long,"\
"and contains at least on speacial character or number"
First_Name = forms.CharField(max_length=50)
Last_Name = forms.CharField(max_length=50)
Username = forms.CharField(max_length=50)
Password = forms.CharField(max_length=50)
Confirm_Password = forms.CharField(max_length=50)
Email_Address = forms.EmailField()
Address = forms.CharField(widget=forms.Textarea)
def clean_name(self,):
username = self.cleaned_data['Username']
return username
def clean_email(self,):
email = self.cleaned_data['Email_Address']
param = {'email': email}
if dbapi.get_user(**param):
raise ValidationError('Email already registered')
return email
def clean_password(self,):
// your logic here
In views.
Not resembles your code
All values are dummy here You just fit according to your values
register_name should be the instance of your Form
username = register_form.cleaned_data['username']
email = register_form.cleaned_data['email']
password = register_form.cleaned_data['password']
name = register_form.cleaned_data['name']
# Create a user obj
user_obj = create_user(username, email, password) // to create a user_obj
# https://docs.djangoproject.com/en/dev/topics/auth/#creating-users
user_obj.first_name = 'xxxxxxxxx'
user_obj.last_name = 'xxxxxxxxxx'
user_obj.save()
Ok. I am writting here a create_user method:
from django.contrib.auth.models import User
def create_user(username, email, password):
# This will return the user_obj
return User.objects.create_user(username, email, password)
Since you are using ModelForm, I suggest you remove the 'except' in your registration function. It should look like this:
def register(request):
if request.method == "POST":
form = RegisterForm(request.POST)
if form.is_valid():
instance = form.save()
return HttpResponseRedirect('/registered/')
else:
form = RegisterForm()
return render_to_response(
'homepage/register.html',
{'form':form,},
context_instance=RequestContext(request),
)
The reason of removing the 'except' is that you are already using modelform and it provides you with form validations. You don't have to create a template telling the user that their input is invalid (that is if you are using /validation/ to tell the user that they have invalid input).