I created a user profile update page. There are several fields like name, surname, email, profile picture and password. If you leave the password field blank, parts other than the password can be updated. If you If you want to change the password, you can fill in the password field.
When a user updates their fields other than the password, the page redirects the user to the homepage, which is something we want. But when the user wants to change the password, the user gets logout and redirect to the logout page. How can I fix it and redirect the user to the homepage?
views.py
#login_required
def update_user(request, id):
user = get_object_or_404(UserProfile, id=id)
form = SignUpChangeForm(request.POST or None, request.FILES or None, instance=user)
if form.is_valid():
form.save()
if form.cleaned_data['password1'] != "":
user.set_password(form.cleaned_data['password1'])
user.save()
return redirect('home')
context = {
'form': form,
}
return render(request, "update_user.html", context)
forms.py
class SignUpChangeForm(forms.ModelForm):
password1 = forms.CharField(max_length=250, required=False,
label="New Password (leave blank if you do not want to change it)",
widget=forms.PasswordInput)
password2 = forms.CharField(max_length=250, required=False,
label="New Password Confirmation (leave blank if you do not want to change it)",
widget=forms.PasswordInput)
class Meta:
model = UserProfile
fields = ('username', 'first_name', 'last_name', 'email', 'image')
widgets = {
'password1': forms.PasswordInput(),
'password2': forms.PasswordInput(),
}
def clean(self):
cleaned_data = super(SignUpChangeForm, self).clean()
if cleaned_data['password1'] != cleaned_data['password2']:
raise ValidationError("Password confirmation does not match!")
return cleaned_data
models.py
class UserProfile(AbstractUser):
company = models.ForeignKey(CompanyProfile, on_delete=models.CASCADE, null=True, unique=False)
user_id = models.UUIDField(default=uuid.uuid4(), editable=False, unique=True)
username = models.CharField(max_length=500, unique=True)
first_name = models.CharField(max_length=200)
last_name = models.CharField(max_length=200)
password = models.CharField(max_length=250)
email = models.EmailField(max_length=254)
rank = models.ForeignKey(Rank, on_delete=models.CASCADE, null=True, unique=False)
image = models.ImageField(upload_to='profile_image', blank=True, null= True, default='profile.png')
isUserActive = models.BooleanField(default=False)
You can log the user in again:
from django.contrib.auth import login as auth_login
#login_required
def update_user(request, id):
user = get_object_or_404(UserProfile, id=id)
form = SignUpChangeForm(request.POST or None, request.FILES or None, instance=user)
if form.is_valid():
form.save()
if form.cleaned_data['password1'] != "":
user.set_password(form.cleaned_data['password1'])
user.save()
auth_login(request, user)
return redirect('home')
context = {
'form': form,
}
return render(request, 'update_user.html', context)
It is however not really clear why you pass an id to the view. Right now everyone can edit another user, since I simply have to login and use the id of another user to change their password. Why not work with request.user as the instance?
Note: Usually it is not a good idea to work with SignUpChangeForm(request.POST or None, request.FILES or None).
It is possible that you make a POST request with no data, but still valid, for example if no
fields are required. Normally you check if it is a POST request, and then construct a form with SignUpChangeForm(request.POST, request.FILES).
Related
I have a user registration form that asks for user information and also asks a question: "Are you a PSMC member?"
The options are:
rank = [
('Supporter', 'Supporter (non-member)'),
('Anak', 'Anak'),
('Uso', 'Uso'),
('Chief', 'Chief'),
]
If Supporter is selected, then the registration form proceeds and saves user info, etc. This part works fine. However, if Anak is selected, I want it to take the user to another form that asks additional questions.
In my forms.py, I have class RegisterForm which is the main registration form for all users. I also have class AnakRegisterForm which is what I want it to continue on to. I used Django's AuthenticationForm based off what I read from their website (but I could be wrong). I know the issue is in views.py register function. Specifically:
if rank == 'Anak':
anak_register(response)
During my debug session, after it moves response to anak_register function, it gets a bunch of scrambled information. I'm pretty lost, any help would be appreciated. Here is my code:
forms.py
class RegisterForm(UserCreationForm):
email = forms.EmailField(
initial='',
required=True,
help_text='Please enter a valid email address'
)
rank = forms.ChoiceField(
label='Are you a PSMC member?',
choices=SavBlock.models.User.rank,
initial=False,
required=True,
help_text='Member accounts will be validated with your HC.'
)
class Meta:
model = User
# username = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
fields = ['username', 'first_name', 'last_name', 'email',
'rank', 'password1', 'password2']
def save(self, commit=True):
user = super(RegisterForm, self).save(commit=False)
user.email = self.cleaned_data['email']
user.ranking = self.cleaned_data['rank']
if commit:
user.save()
return user
class AnakRegisterForm(AuthenticationForm):
tribe = forms.ChoiceField(
label='What tribe are you from, Uce?',
choices=SavBlock.models.Anak.tribe,
initial=False,
required=True,
help_text='Member accounts will be validated with your HC.'
)
class Meta:
model = Anak
fields = ['tribe']
def save(self, commit=True):
user = super(AnakRegisterForm, self).save(commit=False)
user.tribe = self.cleaned_data['tribe']
if commit:
user.save()
return user
class UsoRegisterForm(AuthenticationForm):
pass
class ChiefRegisterForm(AuthenticationForm):
pass
views.py
def register(response):
context = {}
if response.method == "POST":
form = RegisterForm(response.POST)
if form.is_valid():
form.save()
rank = form.cleaned_data.get('rank')
if rank == 'Anak':
anak_register(response)
else:
form.save()
messages.success(response, 'Registration successful. Please login.')
return redirect('login')
else:
context['register'] = form
else:
form = RegisterForm()
context['register'] = form
return render(request=response, template_name='register/register.html', context={'form': form})
def anak_register(response):
# context = {}
if response.method == "POST":
form = AnakRegisterForm(response.POST)
if form.request.is_valid():
form.save()
messages.success(response, 'Registration successful. Please login.')
return redirect('login')
else:
'''
context['register'] = form
'''
else:
form = AnakRegisterForm()
# context['register'] = form
# messages.error(request, 'Unsuccessful registration. Invalid information.')
# form = RegisterForm
return render(request=response, template_name='register/register.html', context={'form': form})
models.py
class User(AbstractBaseUser, PermissionsMixin):
rank = [
('Supporter', 'Supporter (non-member)'),
('Anak', 'Anak'),
('Uso', 'Uso'),
('Chief', 'Chief'),
]
tribe = [
('NaKoaHema', 'Na Koa Hema'),
('Alakai', 'Alaka\'i')
]
username = models.CharField("user name", max_length=50, default='', unique=True)
email = models.EmailField("email address", max_length=30, unique=True, blank=True)
first_name = models.CharField("first name", max_length=50)
last_name = models.CharField("last name", max_length=50)
is_active = models.BooleanField('active', default=True)
# password = models.CharField("password", unique=True, max_length=32, default='')
id = models.AutoField(primary_key=True)
is_staff = models.BooleanField('staff status', default=False)
date_joined = models.DateField('date_joined', default=timezone.now)
ranking = models.CharField(choices=rank, max_length=50, default="Supporter")
objects = UserManager()
USERNAME_FIELD = 'username'
REQUIRED_FIELDS = ['email', 'password', 'ranking']
# Magic method returns string of self
def __str__(self):
return f"User {self.first_name} {self.last_name} rank {self.rank}".strip()
#property
def get_full_name(self):
return f"{self.first_name} {self.last_name}".strip()
class Anak(User):
def __init__(self, first_name, last_name, tribe):
super().__init__(first_name, last_name)
self.tribe = tribe.title()
self.rank = User.rank[1]
EDIT
I changed AuthenticationForm to UserCreationForm and now it accepts the form. However, when I try to run it, I get the following error:
TypeError at /register/
__init__() missing 1 required positional argument: 'tribe'
If someone could point me in the right direction, I'd appreciate it!
Not sure how I missed this, but the best solution that I found is to implement Django Form Wizard. More information can be found here:
https://django-formtools.readthedocs.io/en/latest/wizard.html
I am adding in some functionality that allows a user to edit their personal profile page information. When the user updates their info and hit submit they are getting a NameErrorsaying that the user is not defined. Below is how I am trying to implement the editing functionality.
forms
#this is all the information that the user is allowed to edit.
class UpdateProfile(forms.ModelForm):
username = forms.CharField(required=False)
email = forms.EmailField(required=False)
first_name = forms.CharField(required=False)
last_name = forms.CharField(required=False)
age = forms.IntegerField(required=False)
height = forms.IntegerField(required=False)
weight = forms.IntegerField(required=False)
class Meta:
model = User
fields = ('username', 'email', 'first_name', 'last_name', 'age', 'height', 'weight')
def clean_email(self):
username = self.cleaned_data.get('username')
email = self.cleaned_data.get('email')
if email and User.objects.filter(email=email).exclude(username=username).count():
raise forms.ValidationError('This email address is already in use. Please supply a different email address.')
return email
def save(self, commit=True):
# user = super(RegisterUserForm, self).save(commit=False)
user.email = self.cleaned_data['email']
#This is where i am trying to save the new information.
if commit:
user.save()
#This is where i am returning the user.
return user
Views
def update_profile(request):
args = {}
if request.method == 'POST':
form = UpdateProfile(request.POST, instance=request.user)
form.actual_user = request.user
if form.is_valid():
form.save()
return HttpResponseRedirect(reverse('account:profile.html'))
else:
form = UpdateProfile()
args['form'] = form
return render(request, 'account/edit_profile.html', args)
Weird issue with by registration form, not sure i am doing wrong.
I have StudentProfile Model, that I am trying to save data from StudentResistrationForm but the data is not being saved into database
ERROR: NameError at /register/ name 'StudentProfile' is not defined
Is the view logic correct? What am I missing? Ideas please
model
class Accounts(AbstractUser):
email = models.EmailField('email address', unique=True)
first_name = models.CharField('first name', max_length=30, blank=True)
last_name = models.CharField('last name', max_length=30, blank=True)
date_joined = models.DateTimeField('date joined', auto_now_add=True)
# asdd
bio = models.TextField(max_length=500, blank=True)
location = models.CharField(max_length=30, blank=True)
birth_date = models.DateField(null=True, blank=True)
class StudentProfile(models.Model):
user = models.OneToOneField('Accounts', related_name='student_profile')
# additional fields for students
AMEB_Ratings = models.PositiveIntegerField(default=0)
is_student = models.BooleanField('student status', default=False)
form
class StudentResistrationForm(forms.ModelForm):
class Meta:
model = StudentProfile
fields = (
'AMEB_Ratings',
)
def save(self, commit=True):
user = super(StudentResistrationForm, self).save(commit=False)
# user.first_name = self.cleaned_data['first_name']
# user.last_name = self.cleaned_data['last_name']
user.AMEB_Ratings = self.cleaned_data['AMEB_Ratings']
if commit:
user.save()
return user
class UserForm(forms.ModelForm):
class Meta:
model = get_user_model()
fields = ('username', 'email', 'password')
view
def registerStudent(request):
# Once register page loads, either it will send to the server POST data (if the form is submitted), else if it don't send post data create a user form to register
if request.method == "POST":
user_form = UserForm(request.POST)
form = StudentResistrationForm(request.POST)
if form.is_valid() and user_form.is_valid():
User = get_user_model()
username = user_form.cleaned_data['username']
email = user_form.cleaned_data['email']
password = user_form.cleaned_data['password']
new_user = User.objects.create_user(username=username, email=email, password=password)
Student_profile = StudentProfile()
Student_profile.user = new_user
Student_profile.AMEB_Ratings = request.POST['AMEB_Ratings']
# Student_profile = StudentProfile.create_user(AMEB_Ratings=AMEB_Ratings)
new_user.save()
Student_profile.save()
# form.save()
# AMEB_Ratings = form.cleaned_data['AMEB_Ratings']
return redirect('/')
else:
# Create the django default user form and send it as a dictionary in args to the reg_form.html page.
user_form = UserForm()
form = StudentResistrationForm()
# args = {'form_student': form, 'user_form': user_form }
return render(request, 'accounts/reg_form_students.html', {'form_student': form, 'user_form': user_form })
Looks like you have a few typos you currently are setting your email variable to the email data then setting it to the password data. Correct this first.
email = user_form.cleaned_data['email']
password = user_form.cleaned_data['password']
So I have a Accounts model that extends AbstractUser model.
I Also have StudentProfile and TeacherApplications that have a
one to one relation with Accounts.
I ALSO have two forms for teacher and student to fill out.
Requirement: Enable students/teachers to register via their forms.
Issue: In the student/teacher form I am asking for fields that the User model needs such as email, username, first and last name etc.. However I am getting this:.
Error: 1
AttributeError at /register/ Manager isn't available; 'auth.User' has
been swapped for 'accounts.Accounts'
Error 2
Student_profile.save()
^ TabError: inconsistent use of tabs and spaces in indentation
ISSUE: I need to register the user with user fields otherwise User fields would be null and generate error as well.. But is the best approach? Or what am I doing wrong?
models
class Accounts(AbstractUser):
email = models.EmailField('email address', unique=True)
first_name = models.CharField('first name', max_length=30, blank=True)
last_name = models.CharField('last name', max_length=30, blank=True)
date_joined = models.DateTimeField('date joined', auto_now_add=True)
# asdd
bio = models.TextField(max_length=500, blank=True)
location = models.CharField(max_length=30, blank=True)
birth_date = models.DateField(null=True, blank=True)
class StudentProfile(models.Model):
user = models.OneToOneField('Accounts', related_name='student_profile')
# additional fields for students
AMEB_Ratings = models.PositiveIntegerField(default=0)
is_student = models.BooleanField('student status', default=False)
class TeacherApplications(models.Model):
user = models.OneToOneField('Accounts', related_name='teacher_profile')
# additional fields for teachers
instrument = models.TextField(max_length=500, blank=True)
skill = models.CharField(max_length=30, blank=True)
experience_in_years = models.PositiveIntegerField(blank=True)
is_teacher = models.BooleanField('teacher status', default=False)
forms
class StudentResistrationForm(forms.ModelForm):
class Meta:
model = StudentProfile
fields = (
# 'username',
'first_name',
'last_name',
'email',
'date_joined',
# 'password1',
# 'password2',
'AMEB_Ratings',
'is_student',
)
def save(self, commit=True):
user = super(StudentResistrationForm, self).save(commit=False)
# user.first_name = self.cleaned_data['first_name']
# user.last_name = self.cleaned_data['last_name']
user.AMEB_Ratings = self.cleaned_data['AMEB_Ratings']
if commit:
user.save()
return user
class TeacherRegistrationForm(forms.ModelForm):
class Meta:
model = TeacherApplications
fields = (
'instrument',
'skill',
'experience_in_years',
'is_teacher',
)
views
def registerStudent(request):
# Once register page loads, either it will send to the server POST data (if the form is submitted), else if it don't send post data create a user form to register
if request.method == "POST":
user_form = UserForm(request.POST)
form = StudentResistrationForm(request.POST)
if form.is_valid() and user_form.is_valid():
User = get_user_model()
username = user_form.cleaned_data['username']
email = user_form.cleaned_data['email']
email = user_form.cleaned_data['password']
new_user = User.objects.create_user(username=username, email=email, password=password)
Student_profile = StudentProfile()
Student_profile.user = new_user
Student_profile.AMEB_Ratings = request.POST['AMEB_Ratings']
# Student_profile = StudentProfile.create_user(AMEB_Ratings=AMEB_Ratings)
new_user.save()
Student_profile.save()
# form.save()
# AMEB_Ratings = form.cleaned_data['AMEB_Ratings']
return redirect('../home/')
else:
# Create the django default user form and send it as a dictionary in args to the reg_form.html page.
user_form = UserForm()
form = StudentResistrationForm()
args = {'form_student': form, 'user_form': user_form }
return render(request, 'accounts/reg_form_students.html', args)
def teacherApplication(request):
# # Once register page loads, either it will send to the server POST data (if the form is submitted), else if it don't send post data create a user form to register
# if request.method == "POST":
# form = TeacherRegistrationForm(request.POST)
# if form.is_valid():
# instrument = form.cleaned_data['instrument']
# skill = form.cleaned_data['skill']
# experience_in_years = form.cleaned_data['experience_in_years']
# is_teacher = form.cleaned_data['is_teacher']
# form.save()
# return redirect('../home/')
# else:
# # Create the django default user form and send it as a dictionary in args to the reg_form.html page.
# user_form = UserForm()
# form = StudentResistrationForm()
# return render(request, 'accounts/reg_form_teachers.html', {'form_student': form, 'user_form': user_form })
pass
I think you should change your model to something like this, I mean that Student and Teacher should inherit from account, so you dont need is_teacher and is_student anymore.
class StudentProfile(Accounts):
AMEB_Ratings = models.PositiveIntegerField(default=0)
class TeacherApplications(Accounts):
instrument = models.TextField(max_length=500, blank=True)
skill = models.CharField(max_length=30, blank=True)
experience_in_years = models.PositiveIntegerField(blank=True)
For your second error, I have to say the problem is indention and you should replace your tabs with 4 spaces.
Also I need your urls.py file to figure out it completely, I think problem might be there.
this link might be useful
Manager isn't available; User has been swapped for 'pet.Person'
I'm using a view to create new users in Django. And then I have another view to log them in.
But when I create a user, and I try to log in with authenticate(username=username_post, password=password_post), I get None, so it displays in the template 'Wrong username or password.'.
In my database, I see new registers every time I create a new user. However, as the password is encrypted, I can't say if the problem is the login view, or the register view.
However, the super user that I created through the command line after I first installed django, is able to login with no problem, so that makes me thing that the problem is when I create the user.
These are my Login and Register views:
class Login(View):
form = LoginForm()
message = None
template = 'settings/blog_login.html'
def get(self, request, *args, **kwargs):
if request.user.is_authenticated():
return redirect('settings:index')
return render(request, self.template, self.get_context())
def post(self, request, *args, **kwargs):
username_post = request.POST['username']
password_post = request.POST['password']
user = authenticate(username=username_post, password=password_post)
if user is not None:
login(request, user)
return redirect('settings:index')
else:
self.message = 'Wrong username or password.'
return render(request, self.template, self.get_context())
def get_context(self):
return {'form': self.form, 'message': self.message}
class Register(CreateView):
success_url = reverse_lazy('settings:login')
model = User
template_name = 'settings/blog_register.html'
form_class = RegisterForm
def form_valid(self, form):
self.object = form.save(commit=False)
self.object.set_password(self.object.password)
self.object.save()
return HttpResponseRedirect(self.get_success_url())
And these are my forms:
class LoginForm(forms.Form):
username = forms.CharField(max_length=20, label='Username')
password = forms.CharField(label='Password', widget=forms.PasswordInput())
class RegisterForm(forms.ModelForm):
username = forms.CharField(max_length=20, label='Username')
password1 = forms.CharField(label='Password', widget=forms.PasswordInput(),
error_messages={'required': 'Required field.',
'unique': 'Username already used.',
'invalid': 'Not valid username.'})
password2 = forms.CharField(label='Retype password', widget=forms.PasswordInput(),
error_messages={'required': 'Required field.'})
email = forms.EmailField(error_messages={'required': 'Required field.',
'invalid': 'Invalid email.'})
def clean(self):
clean_data = super(RegisterForm, self).clean()
password1 = clean_data.get('password1')
password2 = clean_data.get('password2')
if password1 != password2:
raise forms.ValidationError('Passwords are different.')
return self.cleaned_data
def clean_email(self):
email = self.cleaned_data.get('email')
username = self.cleaned_data.get('username')
if email and User.objects.filter(email=email).exclude(
username=username).exists():
raise forms.ValidationError('Email already used.')
return email
class Meta:
model = User
fields = ('username', 'password1', 'password2', 'email')
Please, let me know if you need more info.
You don't have a field called 'password' in your form - you just have 'password1' and 'password2' - so nothing is saved to the model object's actual password field. So, when you do self.object.set_password(self.object.password), you're actually setting a blank password.
Instead, you should get the value from your form's password1 field:
self.object.set_password(self.form.cleaned_data['password1'])