I have a signup view which takes an email, password, confirm password, and extra string, which must be unique. All of my validation errors return properly (e.g. if an email is duplicated, it displays this must be unique, and if the passwords don't match is displays passwords don't match). However, the extra string displays the django debug page with the validation error, rather than displaying it to the form. Why is this happening?
Django debug page error:
ValidationError at /signup/
['Extra string must be unique.']
Excerpt of template:
{% for field in form %}
<div class="form-group">
{% for error in field.errors %}
<p style="color: red">{{ error }}</p>
{% endfor %}
<label for="{{ field.id_for_label }}">{{ field.label }}:</label>
{{ field }}
</div>
{% endfor %}
Form:
class UserCreationForm(forms.ModelForm):
password1 = forms.CharField(label='Password', widget=forms.PasswordInput(attrs={'class': 'form-control'}))
password2 = forms.CharField(label='Password confirmation', widget=forms.PasswordInput(attrs={'class': 'form-control'}))
email = forms.CharField(label='Email', widget=forms.EmailInput(attrs={'class': 'form-control'}))
extra_string = forms.CharField(label='Extra String (Must be unique)', widget=forms.TextInput(attrs={'class': 'form-control'}))
class Meta:
model = User
fields = ('email',)
def clean_password2(self):
"""A function to check that the two passwords provided by the user match."""
# Check that the two password entries match
#: User's password.
password1 = self.cleaned_data.get("password1")
#: Password confirm.
password2 = self.cleaned_data.get("password2")
if password1 and password2 and password1 != password2:
raise forms.ValidationError("The passwords must match.") #: This displays properly
return password2
def ensure_unique_string(self):
"""Checks that the entered extra string is unique"""
extra= self.cleaned_data.get("extra_string")
if len(ExtraString.objects.filter(name=extra)) > 0:
raise forms.ValidationError("Ana Group Name must be unique.") #: This displays django debug page
return extra
def save(self, commit=True):
user = super(UserCreationForm, self).save(commit=False)
user.set_password(self.clean_password2())
user.extra_string = self.ensure_unique_string()
user.has_migrated_pwd = True
if commit:
user.save()
return user
Signup View:
class SignUpView(View):
template_name = "account/signup.html"
def get(self, request):
form = UserCreationForm()
return render(request=request, template_name=self.template_name, context={
"form": form
})
def post(self, request):
form = UserCreationForm(request.POST)
if form.is_valid():
user = form.save()
messages.success(request, 'Successfully Registered')
next_url = request.POST.get('next') if 'next' in request.POST else 'profile'
return redirect(next_url)
return render(request, template_name=self.template_name, context={"form": form})
that because you raise in save methods, when you are in the save, is telling your all field are validate, so you need to validate your field before call save methods.
you have 2 solution:
in clean_FIELD_NAME:
def clean_extra_string(self, data):
if len(ExtraString.objects.filter(name=data)) > 0:
raise forms.ValidationError("Ana Group Name must be unique.")
return data
in validate methods:
def validate(self, validate_data):
if len(ExtraString.objects.filter(name=validate_data['extra'])) > 0:
raise forms.ValidationError("Ana Group Name must be unique.")
return validate_data
Related
I am working on student management project and I am unable to get the branch for student as it is foreignkey of Course model to Student model and I want to get the selected option into student model in branch row
models.py:
class Course(models.Model):
id=models.AutoField(primary_key=True)
course = models.CharField(max_length=50)
course_code = models.BigIntegerField(null=True)
def __str__(self):
return self.course
class Student(models.Model):
id=models.AutoField(primary_key=True)
user=models.OneToOneField(User,on_delete=models.CASCADE)
branch=models.ForeignKey(Course,on_delete=models.CASCADE,null=True,blank=True)
middle_name=models.CharField(max_length=50,null=True)
roll_no=models.IntegerField()
mobile_no=PhoneNumberField(default='')
parents_mobile_no=PhoneNumberField(default='')
division=models.CharField(max_length=10,null=True)
batch=models.CharField(max_length=10,null=True)
def __str__(self):
return self.user.first_name + " " + self.user.last_name
views.py:
def studentregister(request):
if request.method == 'POST':
first_name = request.POST['first_name']
middle_name = request.POST['middle_name']
last_name = request.POST['last_name']
email = request.POST['email']
branch= request.POST['branch']
division = request.POST['division']
roll_no = request.POST['roll_no']
mobile_no = request.POST['mobile_no']
parents_mobile_no = request.POST['parents_mobile_no']
pass1 = request.POST['password']
pass2 = request.POST['confirmpassword']
if pass1 == pass2 :
if User.objects.filter(email=email).exists():
return HttpResponse('User already exsits')
else:
user = User.objects.create_user(email=email, password=pass1, first_name=first_name, last_name=last_name)
user.save();
studentdetails = Student ( user=user, middle_name=middle_name,roll_no=roll_no,mobile_no=mobile_no,parents_mobile_no=parents_mobile_no, branch=branch,division=division)
studentdetails.save();
return render (request, 'ms/homepage/index.html')
else:
return HttpResponse('password does not match')
else:
return HttpResponse('failed')
def staffstudent(request):
if request.user.is_authenticated and request.user.user_type==3:
courses = Course.objects.all()
return render(request, 'ms/staff/student.html',{'courses':courses})
else:
return render(request,'ms/login/login.html')
html file as student.py:
<form action="studentregister" method="POST" style = "background-color:#011B3C;">
{% csrf_token %}
<div class="form-group" name="branch">
<select >
<option selected disabled="true">Branch</option>
{% for course in courses%}
<option>{{course.course}}</option>
{%endfor%}
</select>
</div>
</form>
The error I am getting is
MultiValueDictKeyError at /staff/studentregister
'branch'
Please help me with this as soon as possible.
You haven't named that <select> (<select name="branch">) so any choice you make in it will not be transmitted to the server, and that's why you get a key error.
In addition, the <option>'s value must be the course's id:
<option value="{{ course.id }}">{{ course.course }}</option>
... so you can look it up in the view:
branch = Course.objects.get(id=request.POST['branch'])
However, please look at Django's built-in forms functionality, especially model forms – you would be done in a fraction of the HTML and Python code you have now, plus you'd actually have correct data validation.
This is not the conventional way to deal with Forms in Django although it can be done. Convention would be:
Creating a form in forms.py like so:
class MyForm(forms.Form):
dropdown_one = forms.ChoiceField(
label="Country",
widget=forms.Select(attrs={"class": "selecter form-control"}),
choices=[],
)
dropdown_two = forms.ChoiceField(
label="Category",
widget=forms.Select(attrs={"class": "selecter form-control"}),
choices=[(None, '...')],
required=True
)
Then use this form in views.py like so:
my_form = MyForm(initial={})
return render(request,{'my_form':my_form})
Then finally in html file:
{{my_form.media}}
{% for item in my_form %}
<div class="form-group col-lg-2" id="dropdown-content">
{{item.label_tag}}
{{item}}
</div>
{% endfor %}
</div>
For more refer to this:
https://docs.djangoproject.com/en/4.0/topics/forms/
My User login has some issue with the authentication process.
I am using Django 1.9 and Python 3.6
this is my code repository
user = authenticate(username=username, password=password)
Returns user as none
This is how my Accounts/views.py looks for login
def register(request):
registered = False
if request.method == 'POST':
reg_form = RegistrationForm(data=request.POST)
profile_form = UserProfileForm(data=request.POST)
if reg_form.is_valid() and profile_form.is_valid():
user = reg_form.save()
# print('before set password = ', user.password)
user.set_password(user.password)
# print('after set password = ', user.password)
user.save()
print(user.password)
profile = profile_form.save(commit=False)
profile.user = user
profile.email = user.email
profile.first_name = user.first_name
profile.last_name = user.last_name
if 'profile_pic' in request.FILES:
profile.profile_pic = request.FILES['profile_pic']
print('uploading pic .....')
profile.save()
args = {'reg_form': reg_form, 'profile_form': profile_form, 'registered': True}
head_list.update(args)
return render(request, 'registration.html', head_list)
else:
print(reg_form.errors, profile_form.errors)
args = {'reg_form': reg_form.errors, 'profile_form': profile_form.errors, 'registered': False}
head_list.update(args)
return render(request, 'registration.html', head_list, args)
else:
reg_form = RegistrationForm()
profile_form = UserProfileForm()
args = {'reg_form': reg_form, 'profile_form': profile_form, 'registered': False}
head_list.update(args)
print(head_list)
return render(request, 'registration.html', head_list)
def login_view(request):
params = {}
params.update(csrf(request))
if request.method == 'POST':
form = LoginForm(request.POST)
if form.is_valid():
username = form.cleaned_data.get('username')
password = form.cleaned_data.get('password')
# First get the username and password supplied
# username = request.POST.get('username', '')
# password = request.POST.get('password', '')
# Django's built-in authentication function:
print(username, password)
user = authenticate(username=username, password=password)
print('after aunthenticate', user)
# If we have a user
if user:
# Check it the account is active
if user.is_active:
# Log the user in.
login(request, username)
# Send the user back to some page.
# In this case their homepage.
# return HttpResponseRedirect(reverse('/user_login/'))
return render_to_response('user_login.html', RequestContext(request, {}))
else:
# If account is not active:
return HttpResponse("Your account is not active.")
else:
print("Someone tried to login and failed.")
print("They used username: {} and password: {}".format(username, password))
return HttpResponse("Invalid login details supplied.")
else:
form = LoginForm()
args = {'form': form}
head_list.update(args)
# Nothing has been provided for username or password.
return render(request, 'login.html', head_list)
The login.html page is shown below
{% block content %}
<section class="container">
<h1>LiquorApp Login Console</h1>
<div class="login">
<h1>Login to WebApp</h1>
<form method="post" action="/user_login/">
{% csrf_token %}
{{ form.as_p }}
{% comment %}Username: <input type="text" name="username" value="" size="50" />
<br />{% endcomment %}
{% comment %}<p><input type="text" name="username" value="" id="username" placeholder="username"></p>
<p><input id ="password" type="password" name="password" value="" placeholder="password"></p>
<p class="remember_me">{% endcomment %}
<label>
<input type="checkbox" name="remember_me" id="remember_me">
Remember me on this computer
</label>
</p>
<p class="submit"><input type="submit" name="commit" value="Login"></p>
</form>
</div>
</section>
{% endblock %}
Please suggest where am I doing it wrong that my authenticate module is returning none.
I have also added the following in the settings.py file
AUTHENTICATION_BACKENDS = (
'django.contrib.auth.backends.ModelBackend',
)
Django 2.1 authentication returns users for any authentication, only if user.is_active=TRUE and you need to first save the response of form.save(commit=False) and then set custom variables
if form.is_valid():
user= form.save(commit=False)
user.active=True
user.staff=False
user.admin=False
user.save()
messages.success(request, 'Account created successfully')
Remove
user.set_password(user.password)
from Accounts.views.register
You need to define check_password for your User class
def check_password(self, raw_password):
if self.password == raw_password:
return True
else:
return False
Because if you check the source code under django.contrib.auth.models,
check_password() raise and NotImplemented error.
Make sure that user.is_active is True before calling authenticate(username=user.username, password=password, request=request) in Django 1.11.
It worked fine in Django 1.8, but somewhere between LTS 1.8 and LTS 1.11 they added an additional check for user.is_active in ModelBackend class:
class ModelBackend(object):
"""
Authenticates against settings.AUTH_USER_MODEL.
"""
def authenticate(self, request, username=None, password=None, **kwargs):
if username is None:
username = kwargs.get(UserModel.USERNAME_FIELD)
try:
user = UserModel._default_manager.get_by_natural_key(username)
except UserModel.DoesNotExist:
# Run the default password hasher once to reduce the timing
# difference between an existing and a non-existing user (#20760).
UserModel().set_password(password)
else:
if user.check_password(password) and self.user_can_authenticate(user):
return user
def user_can_authenticate(self, user):
"""
Reject users with is_active=False. Custom user models that don't have
that attribute are allowed.
"""
is_active = getattr(user, 'is_active', None)
return is_active or is_active is None
As for the recommendation to use Django built-in auth views, they are not handy for customized non-standard authentication.
I've been trying to render HTML using form I made in forms.py, however this is not working, just fail to loaded without error message. Also, there is no message in console too, so I'm having hard time to fix this. Please take a look and tell me which part is wrong.
This is urls.py
url(r'^profile/(?P<username>[-\w.]+)/$', views.profile, name='profile'),
url(r'^password_change/(?P<username>[-\w.]+)/$', views.password_change, name='password_change'),
url(r'^password_change_done/$', views.password_change_done, name='password_change_done'),
forms.py
class PasswordChangeForm(forms.Form):
oldpassword = forms.CharField(max_length = 20, widget=forms.TextInput(attrs={'type':'password', 'placeholder':'your old Password', 'class' : 'span'}))
newpassword1 = forms.CharField(max_length = 20, widget=forms.TextInput(attrs={'type':'password', 'placeholder':'New Password', 'class' : 'span'}))
newpassword2 = forms.CharField(max_length = 20, widget=forms.TextInput(attrs={'type':'password', 'placeholder':'Confirm New Password', 'class' : 'span'}))
class Meta:
model = User
fields = ("username",)
field_classes = {'username': UsernameField}
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
if self._meta.model.USERNAME_FIELD in self.fields:
self.fields[self._meta.model.USERNAME_FIELD].widget.attrs.update({'autofocus': True})
def clean(self):
if 'newpassword1' in self.cleaned_data and 'newpassword2' in self.cleaned_data:
if self.cleaned_data['newpassword1'] != self.cleaned_data['newpassword2']:
raise forms.ValidationError(_("The two password fields did not match."))
return self.cleaned_data
def save(self, commit=True):
user = super().save(commit=False)
user.set_password(self.cleaned_data["password1"])
if commit:
user.save()
return user
views.py
#login_required
def password_change(request, username):
if request.method == 'POST':
form = PasswordChangeForm(data=request.POST, user=request.user)
print("username is "+username)
if form.is_valid():
#form.save()
update_session_auth_hash(request, form.user)
form.save()
print("A")
return HttpResponseRedirect('/blog/password_change_done/')
else:
update_session_auth_hash(request, form.user)
form.save()
print("B")
return redirect(reverse('blog:profile', args=[form.user.get_username()]))
else:
print("C")
form = PasswordChangeForm(user=request.user)#unbound
return redirect(reverse('blog:profile', args=[form.user.get_username()]))
profile.html (where password_change should be loaded.)
<h2>password change</h2>
{% if error_message %}
<p><strong>{{ error_message }}</strong></p>
{% else %}
{% endif %}
<form class="form-horizontal" role="form" action="{% url 'blog:password_change' user.username %}" method="post" enctype="multipart/form-data">
{% csrf_token %}
{{ form.as_p }}
<button type="submit" class="button-primary">password change</button></div>
</form>
Here is one of the examples how change_password view can be implemented
from django.contrib import messages
from django.contrib.auth import update_session_auth_hash
from django.contrib.auth.forms import PasswordChangeForm
from django.shortcuts import render, redirect
def change_password(request):
if request.method == 'POST':
form = PasswordChangeForm(request.user, request.POST)
if form.is_valid():
user = form.save()
update_session_auth_hash(request, user) # Important!
messages.success(request, 'Your password was successfully updated!')
return redirect('accounts:change_password')
else:
messages.error(request, 'Please correct the error below.')
else:
form = PasswordChangeForm(request.user)
return render(request, 'accounts/change_password.html', {
'form': form
})
Have a look at the part related to GET request. There you have to create the form and render the page with context. You should provide form to the context.
In your case you create the form and redirect to the profile page straight after that. That is why you see empty form page.
I'm trying to make register possible on the homepage, so I don't have a seperate URL to handle registration. I'm trying to send the form through get_context_data, however it's not working. Here's my code:
forms.py
class UserRegistrationForm(forms.ModelForm):
password = forms.CharField(widget=forms.PasswordInput)
class Meta:
model = User
fields = [
'username',
'password',
]
views.py
class BoxesView(ListView):
template_name = 'polls.html'
def get_context_data(self):
context = super(BoxesView, self).get_context_data()
# login
if self.request.method == 'POST':
form = UserRegistrationForm(self.request.POST or None)
context['form'] = form
if form.is_valid():
username = form.cleaned_data['username']
password = form.cleaned_data['password']
user = User.objects.create_user(username=username, password=password)
user.save()
return redirect('/')
else:
print(form.errors) #doesn't print anything
print(form.non_field_errors()) #doesn't print anything
print('Errors') #doesn't print anything
else:
form = UserRegistrationForm()
context['form'] = form
return context
def get_queryset(self):
pass
base.html
<form action="" enctype="multipart/form-data" method="post">{% csrf_token %}
<div class="registerBox">
{{ form.username }}
{{ form.password }}
<input type="submit" value="register"/>
</div>
</form>
So when I submit the form it gives this error: Method Not Allowed (POST): "POST / HTTP/1.1" 405 0
And it isn't creating a new User. Any idea what the problem is?
EDIT: Tried FormMixin, got this error: The view app.views.BoxesView didn't return an HttpResponse object. It returned None instead.
class BoxesView(ListView):
template_name = 'polls.html'
form_class = UserRegistrationForm
def post(self, request, *args, **kwargs):
form = self.get_form()
if form.is_valid():
username = form.cleaned_data['username']
password = form.cleaned_data['password']
user = User.objects.create_user(username=username, password=password)
user.save()
return redirect('/')
def get_context_data(self):
context = super(BoxesView, self).get_context_data()
context['form'] = self.get_form()
return context
def get_queryset(self):
pass
Ok I see the issue fix the indentation, your if statement should be inside the get_context_data function not outside ;)
You need to add post() method and FormMixin to your CBV like this:
class BoxesView(FormMixin, ListView):
template_name = 'polls.html'
form_class = UserRegistrationForm
# ...
def post(self, request, *args, **kwargs):
form = self.get_form()
if form.is_valid():
# ...
else:
# ...
return render(request, self.template_name, {'data': some_data})
first of all, I am new in programming with Django. Here is what I have:
The <form> inside my register.html template:
<form method='POST' action='/accounts/register/'>
{% csrf_token %}
{% for field in form %}
{{ field.label_tag }}{{ field }} {{field.help_text}} {{field.errors}{}
<br/>
{% endfor %}
<input type='submit' value='Register' />
</form>
This is inside my forms.py
class MyRegistrationForm(UserCreationForm):
email = forms.EmailField(required=True)
first_name = forms.CharField(required = True)
last_name = forms.CharField(required = True)
password1 = forms.RegexField(widget=forms.PasswordInput,
regex = r'[\w+]{8,}',
label = 'New password',
help_text = "Must be strong!",
error_messages = {'required' : "ASDASDA",
'invalid' : "ZZZZZ"}
)
password2 = forms.RegexField(widget=forms.PasswordInput,
regex = r'[\w+]{8,}',
label = 'Re-enter password',
)
class Meta:
model = User
fields = ('last_name', 'first_name', 'username', 'email', 'password1', 'password2')
def save(self, commit = True):
user = super(MyRegistrationForm, self).save(commit = False)
user.email = self.cleaned_data['email']
user.first_name = self.cleaned_data['first_name']
user.last_name = self.cleaned_data['last_name']
if commit:
user.save()
return user
This is inside my views.py
def User_Register_View(request):
if request.method == 'POST':
form = MyRegistrationForm(request.POST)
if form.is_valid():
form.save()
register_success = "Account successfuly created!"
return render(request,'index.html', locals())
args = {}
args.update(csrf(request))
args['form'] = MyRegistrationForm()
return render(request,'accounts/register.html',args)
My questions are the following:
{{field.errors}} is not working. No errors are printed. If I let all the fields of the form empty, and I click 'Register', no error is rendered.
If I add another field to this forum, "gender" as a CharField, will it create a column inside my DB for gender? ( I am working with the default sqlite3)
Is there a simple way to modify my code and make the 'User' field optional and, instead, make the 'Email' field be unique and required?
In the state in which my code is, where can I check for the unique property of my email in the DB? Is it inside my views.py, just before form.save() ?
Thank you. Let me know if you have any questions
def User_Register_View(request):
if request.method == 'POST':
form = MyRegistrationForm(request.POST)
if form.is_valid():
form.save()
register_success = "Account successfuly created!"
return render(request,'index.html', locals())
else:
form = MyRegistrationForm() # An unbound form
args = {}
args['form'] = form
return render(request,'accounts/register.html',args)
{{field.errors}} now showing because you are not returning the validated form instance if validation failed. You always return a new instance of MyRegistrationForm. See above example.
adding fields to forms will not affect your db since only models maps to db tables
& 4. You need custom user model to do so, see here for example on how to do it