I am new to Django and is currently trying to make a user registration form for my application. Does anyone know why form.is_valid() is returning False?
forms.py
class RegistrationForm(forms.ModelForm):
username = forms.CharField(widget=forms.TextInput)
password = forms.CharField(widget=forms.PasswordInput)
email = forms.CharField(widget=forms.EmailInput)
class Meta:
model = User
fields = ['username', 'password', 'email']
views.py
def registration(request):
if request.method == 'POST':
form = RegistrationForm(request.POST)
if form.is_valid():
print "valid"
username = form.cleaned_data['username']
email = form.cleaned_data['email']
password = form.cleaned_data['password']
User.objects.create_user(username=username, email=email, password=password)
user = authenticate(username=username, passsword=password)
if user is not None:
login(request, user)
return redirect('/admin')
else:
# return a blank form
print "invalid"
return render(request, 'registration/register.html', {'form': form})
register.html
<div class="container ">
<form method="post" action=".">
{% csrf_token %}
<h2 class="form-signin-heading">Register</h2>
<input type="text" id="inputUsername" class="form-control" placeholder="Username" required autofocus>
<input type="password" id="inputPassword" class="form-control" placeholder="Password" required>
<input type="email" id="inputEmail" class="form-control" placeholder="Email" required autofocus>
<button class="btn btn-lg btn-primary btn-block" type="submit">Sign in</button>
</form>
I see that you defined the form in the view, but you are not using it inside the template (register.html). I would have done something more like this:
<div class="container">
<h2 class="form-signin-heading">Register</h2>
<form method="post">
{% csrf_token %}
{{ form.as_p }}
<button class="btn btn-lg btn-primary btn-block" type="submit">Sign Up</button>
</form>
</div>
Also, if you haven't noticed, your "return render(...)" line is within the else block. And while not necessary, I think it's good practice to define context as a dict and pass it in using context=context in the view or whatever you name it. However, for the case you have here, I'd suggest using a class-based view. It's much cleaner for signing a user up.
from django.views.generic import CreateView
from django.urls import reverse_lazy
class Registration(CreateView):
form_class = RegistrationForm
template_name = 'register.html'
success_url = reverse_lazy('login')
# in the urls.py, set name='login' for the login page
# signing a user up will not grant admin priveleges, that is only done through the
# creation of a super user or if you coded your model to do so (not recommended)
and as for any validation, look into creating a clean(self) method inside the forms.py Like this:
# this will be on the same block as class Meta you defined
# ensures no other user has the username with a different case
def clean(self):
cleaned_data = super(RegistrationForm, self).clean()
username = cleaned_data.get('username')
email = cleaned_data.get('email')
# checks if username is provided and ensures the username is not already in use
if username and User.objects.filter(username__iexact=username).exists():
self.add_error('username', 'A user with that username already exists.')
# checks if email is provided and ensures this email is not already in use
if email and User.objects.filter(email__iexact=email).exists():
self.add_error('email', 'That email address is already in use.')
return cleaned_data
I saw that you were setting some labels in your template, this can be done within the forms.py on the same block as the class Meta and def clean(self) I just provided:
# method to overwrite the form label names
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields['username'].label = 'Username'
self.fields['email'].label = 'Email Address'
I have not tested this, I'm going off of memory but I think this is a route similar to your use case, and it's utilizing the Django resources available to you :) Good Luck and I hope this helps!
P.S: You should look into django-crispy-forms since you're using bootstrap.
You haven't given any of your HTML input elements a name attribute. Without that, the browser can't send any data to the server.
Note that if you had used Django itself to produce the fields, they would not only include the name, but would also be populated when the invalid form was redisplayed.
Related
I'm a beginner in Django, I try to use for="id_<field-name>" method to create a signup form interface, but the default validation like "This field is required." or "This username already exists" is not showing. I don't want to use {{ form.as_p }} because I want to separate the field. The registration still working if i input the true the valid things.
HTML
<form method="POST" class="register-form" id="register-form" enctype="multipart/form-data" >
{% csrf_token %}
<div class="form-group">
<label for="id_username"><i class="zmdi zmdi-account material-icons-name"></i></label>
<input type="text" name="username" id="username" placeholder="Username"/>
</div>
<div class="form-group">
<label for="id_email"><i class="zmdi zmdi-email"></i></label>
<input type="email" name="email" id="email" placeholder="Your Email" />
</div>
<div class="form-group">
<label for="id_password"><i class="zmdi zmdi-lock"></i></label>
<input type="password" name="password" id="password" placeholder="Password"/>
</div>
<div class="form-group">
<input type="checkbox" name="agree-term" id="agree-term" class="agree-term" />
<label for="agree-term" class="label-agree-term"><span><span></span></span>I agree all statements in Terms of service</label>
</div>
<div class="form-group form-button">
<input type="submit" name="signup" id="signup" class="form-submit" value="Register"/>
</div>
</form>
views.py
def register(request):
registered = False
if request.method == 'POST':
# Get info from "both" forms
# It appears as one form to the user on the .html page
user_form = UserForm(data=request.POST)
profile_form = UserProfileInfoForm(data=request.POST)
# Check to see both forms are valid
if user_form.is_valid() and profile_form.is_valid():
# Save User Form to Database
user = user_form.save()
# Hash the password
user.set_password(user.password)
# Update with Hashed password
user.save()
# Now we deal with the extra info!
# Can't commit yet because we still need to manipulate
profile = profile_form.save(commit=False)
# Set One to One relationship between
# UserForm and UserProfileInfoForm
profile.user = user
# Check if they provided a profile picture
if 'profile_pic' in request.FILES:
print('found it')
# If yes, then grab it from the POST form reply
profile.profile_pic = request.FILES['profile_pic']
# Now save model
profile.save()
# Registration Successful!
registered = True
else:
# One of the forms was invalid if this else gets called.
print(user_form.errors,profile_form.errors)
else:
# Was not an HTTP post so we just render the forms as blank.
user_form = UserForm()
profile_form = UserProfileInfoForm()
# This is the render and context dictionary to feed
# back to the registration.html file page.
return render(request,'basic_app/registration.html',
{'user_form':user_form,
'profile_form':profile_form,
'registered':registered,
})
forms.py
from django import forms
from django.contrib.auth.models import User
from .models import UserProfileInfo, TeaProfileInfo
class UserForm(forms.ModelForm):
password = forms.CharField(widget=forms.PasswordInput())
class Meta():
model = User
fields = ('username','email','password')
My signup page interface
A quick way to validate your form by adding the following to your form.py
def clean(self):
super(UserForm, self).clean()
username = self.cleaned_data.get('username')
email = self.cleaned_data.get('email')
password = self.cleaned_data.get('password')
if username == "" or email == "" or password == "":
raise forms.ValidationError(['This field is required.'])
In your HTML make sure to add the following after/before each field
{{ username.errors }}
{{ email.errors }}
{{ password.errors }}
Already registered user name can be registered in user creation form. I'm making Django application.
I wrote in views.py
def regist(request):
regist_form = RegisterForm(request.POST or None)
context = {
'regist_form': regist_form,
}
return render(request, 'registration/regist.html', context)
def regist_save(request):
regist_form = RegisterForm(request.POST or None)
if request.method == "POST" and regist_form.is_valid():
regist = regist_form.save(commit=False)
regist.is_staff = True
regist.save()
advertisements = Advertisement.objects.all()
return render(request, 'registration/detail.html', {'advertisements': advertisements})
in regist.html
<form class="form-horizontal" action="/accounts/regist_save/" method="POST">
<div class="form-group-lg">
<label for="id_username">Username</label>
{{ regist_form.username }}
<p class="help-block">{{ regist_form.username.help_text }}</p>
</div>
<div class="form-group-lg">
<label for="id_email">Email</label>
{{ regist_form.email }}
<p class="help-block">{{ regist_form.email.help_text }}</p>
</div>
<div class="form-group-lg">
<label for="id_password">Password</label>
{{ regist_form.password1 }}
<p class="help-block">{{ regist_form.password1.help_text }}</p>
</div>
<div class="form-group-lg">
<label for="id_password">Password(Confirmation)</label>
{{ regist_form.password2 }}
<p class="help-block">{{ regist_form.password2.help_text }}</p>
</div>
<div class="form-group-lg">
<div class="col-xs-offset-2">
<button type="submit" class="btn-lg regist">Register</button>
<input name="next" type="hidden" />
</div>
</div>
{% csrf_token %}
</form>
in forms.py
class RegisterForm(UserCreationForm):
class Meta:
model = User
fields = ('username', 'email','password1','password1',)
def __init__(self, *args, **kwargs):
super(RegisterForm, self).__init__(*args, **kwargs)
self.fields['username'].widget.attrs['class'] = 'form-control'
self.fields['email'].widget.attrs['class'] = 'form-control'
self.fields['password1'].widget.attrs['class'] = 'form-control'
self.fields['password2'].widget.attrs['class'] = 'form-control'
Now in this user registration form, if I write already registered user name&email&password, these data is not registered but detail.html is load. I wanna show alert if I do so like "this user name is already registered". Why isn't my web page not my ideal one? Why can I resist already registered user name in my site? How should I fix this? I did not make User model in models.py.
from django.contrib.auth.models import User
from django.contrib import messages
from django.db.models import Q
if request.method == "POST" and regist_form.is_valid():
try:
username = form.cleaned_data.get('username', None)
email = form.cleaned_data.get('email', None)
# if username or email already exist in the User table
# if you want to use the user object you can make it
# if you want to check username and email with or, then it would work
user = User.objects.get(Q(username=username) | Q(email=email))
# if you want to check username and email with and, then it would work
user = User.objects.get(username=username, email=email)
# else if you have no username but only email you just only filter for email
user = User.objects.get(email=email)
# else if no need for user detail, you can do this
User.objects.get(Q(username=username) | Q(email=email))
messages.warning(request, 'That detailed use is already available.')
# return to register form / template page
# whatever your page is
except User.DoesNotExist:
# save the user
regist = regist_form.save(commit=False)
regist.is_staff = True
regist.save()
I suggest using a custom model and extending auth. By default if unique is set to true, django fill raise a form error during submit itself.
In models.py
class User(AbstractUser):
"""User model."""
username = models.CharField(max_length=128, unique=True)
email = models.EmailField(_('email address'), unique=True)
def __str__(self):
return self.username
PS: Override where ever required. Also suggest looking in the django tutorials, and simpleisbetterthancomplex. Mr Vitor has an easy tutorial
I have created models.py, forms.py, views.py & registeration.html.
At the moment in registeration.html I am directly importing the django form like {{reg_form.as_p}}, I can also do it in following two ways: {{ form.as_table }} or {{ form.as_ul }}. what I want is to have a real control over the fields to be displayed. Meaning to say some fields may be tabular, some may be list etc with specific css.
What I tried in html to access the field is mentioned below:
id={{form.id_FullName}} name={{form.FullName}}
In models.py I have:
FullName = models.CharField(max_length = 100)
The above way didnt work, I want some way to access the django fields in HTML.
Add name and pass the modelname ,
Change like this,
<input type="text" id="id_FullName" value="" name="FullName" />.
and submit your form.
Example , lets say signup form :
forms.py,
class SignUpForm(forms.ModelForm):
email = forms.CharField(label='email', max_length=100)
password = forms.CharField(label='password', max_length=100)
def __init__(self, *args, **kargs):
super(SignUpForm, self).__init__(*args, **kargs)
class Meta:
model = User
fields = '__all__'
views.py,
def signup(request):
form = SignUpForm(request.POST or None)
if request.method == 'POST':
form = SignUpForm(request.POST or None)
if not form.is_valid():
print form.errors
return render(request, 'signup.html', {'form': form})
else:
email = form.cleaned_data.get("email")
password = form.cleaned_data.get("password")
new_user = User.objects.create_user(email=email,
password=password,
)
new_user.is_active = True
new_user.save()
return redirect('login')
else:
return render(request, 'signup.html', {'form': form})
urls.py
url(r'^signup', views.signup, name='signup'),
Finally in your templates ie signup.html,
<form action="." method="post"> {% csrf_token %}
<div class="form-group">
<input type="text" class="form-control" name="email" id="inputUsernameEmail" placeholder="Email">
</div>
<div class="form-group">
<input type="password" name="password" class="form-control" id="inputPassword" placeholder="Password">
</div>
<input type="submit" name="Sign up" value="Sign up" id="Sign_up" class="button_drop outline">
</form>
You can render the field manually.[Documentation]
Here is a sample taken from the docs for a subject field
<div class="fieldWrapper">
{{ form.subject.errors }}
{{ form.subject.label_tag }}
{{ form.subject }}
</div>
I have created a Profile and attached to user model using OneToOneField. I have a registration form where user enters input which corresponds to user and profile. Django provides User.objects.create_user to save fields which are related to User model, but i don't know how to save details of Profile model manually.
Here is my code:
models.py
from django.db import models
from django.contrib.auth.models import User
def Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
full_name = models.CharField(max_length=150, required=True)
# lot more fields here
views.py
#csrf_protect
def register(request):
if request.method == 'POST':
full_name = request.POST.get('full_name', '')
username = request.POST.get('username', '')
password = request.POST.get('password', '')
User.objects.create_user(username=username, password=password)
# how to save Profile full_name here
return render(request, 'register.html')
register.html
<form method="post" action="/register/">{% csrf_token %}
<div class="form-group">
<label for="full_name">Name</label>
<input type="text" name="full_name" id="full_name">
</div>
<div class="form-group">
<label for="username">Username</label>
<input type="text" name="username" value="" id="username">
</div>
<div class="form">
<label for="password">Password</label>
<input type="pass" name="password" value="" id="password">
</div>
<button type="submit" class="btn btn-primary">Submit</button>
</form>
1) How can i save full_name of Profile model in views.py ? Can I do this without creating form class for every model in the future that want to save or Signals?
2) Do I need to change auth_user_model in settings.py in order to save profile details manually?
3) How to validate the fields without creating a new Form class?
#csrf_protect
def register(request):
if request.method == 'POST':
full_name = request.POST.get('full_name', '')
username = request.POST.get('username', '')
password = request.POST.get('password', '')
user = User.objects.create_user(username=username, password=password)
Profile.objects.create(user=user,full_name=full_name)
# how to save Profile full_name here
return render(request, 'register.html')
you can use the created user instance to create the profile associated with that user
I have a simple password reset form where I take a user's email as input. The relevant class is as below. The code works well on my local machine but the exact code doesn't work in production server. Upon inspecting source of rendered view, I see the value field missing.
Expected o/p is
<form method="POST" action="/accounts/password/reset/" class="password_reset">
<ul class="errorlist"><li>The e-mail address is not assigned to any user account</li></ul>
<p><label for="id_email">E-mail:</label> <input id="id_email" name="email" size="30" type="email" value="someemail#gmail.com" /></p>
<input type="submit" value="Reset My Password" />
In production server, value for the email field is missing. I am totally lost why this may be the case. Any pointers will be appreciated.
class PasswordResetView(FormView):
template_name = "account/password_reset.html"
form_class = ResetPasswordForm
success_url = reverse_lazy("account_reset_password_done")
def get_form_class(self):
return get_form_class(app_settings.FORMS,
'reset_password',
self.form_class)
def form_valid(self, form):
form.save()
return super(PasswordResetView, self).form_valid(form)
def get_context_data(self, **kwargs):
ret = super(PasswordResetView, self).get_context_data(**kwargs)
# NOTE: For backwards compatibility
ret['password_reset_form'] = ret.get('form')
# (end NOTE)
return ret
password_reset = PasswordResetView.as_view()