I am fairly new to Django and I have set up a sign up form with some additional fields.
In my forms.py file I have the following code:
class SignUpForm(UserCreationForm):
first_name = forms.CharField(max_length=30, required=False, help_text='Optional.')
last_name = forms.CharField(max_length=30, required=False, help_text='Optional.')
email = forms.EmailField(max_length=254, help_text='Required. Inform a valid email address.')
class Meta:
model = User
fields = ('username', 'first_name', 'last_name', 'email', 'password1', 'password2', )
In my views.py I have the following code:
def signup(request):
if request.method == 'POST':
form = SignUpForm(request.POST)
if form.is_valid():
form.save()
username = form.cleaned_data.get('username')
raw_password = form.cleaned_data.get('password1')
user = authenticate(username=username, password=raw_password)
login(request, user)
return redirect('index')
else:
form = SignUpForm()
return render(request, 'signup.html', {'form': form})
Then in my signup.html view I am rendering the following:
<form method="post">
{% csrf_token %}
{% for field in form %}
<p>
{{ field.label_tag }}<br>
{{ field }}
{% for error in field.errors %}
<p style="color: red">{{ error }}</p>
{% endfor %}
</p>
{% endfor %}
<button class="btn-contact" type="submit">Let's Go!</button>
</form>
Essentially what I want to do is add placeholder text in each field but this is not appearing the way I have set it up.
To do this I need more control over the forms fields but I don't know how to do that because of the way I am rendering fields in a loop.
How would I go about doing this?
For placeholders, take a look at How do I add a placeholder on a CharField in Django?
One good advice that I have to give you, is that you shouldn't manually render your form, because Django has mechanisms to do that quite well (like {{form.as_p}} in your case). See Working with forms.
Related
I'm trying to implement a simple sign up form and slightly tearing my hair out. For some reason, the view doesn't seem to be properly passing the context object I pass it (regardless of what it is.)
here's my code:
urls.py
path(r"signup/", client_views.signup_view, name="page-signup")
views.py
def signup_view(request):
if request.method == 'POST':
form = SignUpForm(request.POST)
if form.is_valid():
form.save()
username = form.cleaned_data.get('username')
raw_password = form.cleaned_data.get('password1')
user = authenticate(username=username, password=raw_password)
login(request, user)
return redirect('page-index')
else:
form = SignUpForm()
context = {'form': form}
return render(request, 'registration/signup.html', context=context)
registration/signup.html
{% extends "base.html" %}
{% load static %}
{% block header %}
Sign Up
{% endblock %}
{% block content %}
<form method="post">
{% csrf_token %}
{{ form.as_p }}
<button type="submit">Sign Up</button>
</form>
{% endblock %}
forms.py
class SignUpForm(UserCreationForm):
first_name = forms.CharField(max_length=30, required=False, help_text='Optional.')
last_name = forms.CharField(max_length=30, required=False, help_text='Optional.')
email = forms.EmailField(max_length=254, help_text='Required. Inform a valid email address.')
class Meta:
model = User
fields = ('first_name', 'last_name', 'email', 'password1', 'password2', )
I've confirmed it's
generating the form properly as html
it's also definitely rendering the correct template
doesn't pass any context even if it's just a string or something
doesn't work with any forms
doesn't work in other templates, implying to me it's in the view
I'm sure this is some stupid mistake but I've been tearing my hair out over this - any help would be greatly appreciated!
It was because my template tags didn't match up
Specifically, I wrote:
{% bloc content %}
instead of
{% block body %}
I want to update user info with UserChangeForm and things go pretty well except for the ManyToManyField. When I render the page I can see that all user informations are displayed in correct order of each field like user's username will be in the username field but it's blank in manytomanyfield.
#model.py
class Department(models.Model):
name = models.CharField(max_length=100)
class CustomUser(AbstractUser):
username = None
email = models.EmailField(_('Email Address'), unique=True)
department = models.ManyToManyField(Department)
# some other fields
# forms.py
class EditUserForm(UserChangeForm):
class Meta:
model = CustomUser
fields = ['email', 'department', ..]
widgets = {'department': forms.CheckboxSelectMultiple()}
# view.py
def home(request):
template_name = "app/home.html"
edit_form = EditUserForm(instance=request.user)
if request.method == "POST":
edit_form = EditUserForm(request.POST, instance=request.user)
if edit_form.is_valid():
edit_form.save()
return JsonResponse({'success': True}, status=200)
else:
return JsonResponse({'error': edit_form.errors}, status=400)
return render(request, template_name, {'edit_form': edit_form})
# template
<form action="{% url 'home' %}" method="POST">
<div class="row">
{{edit_form.email}}
{{edit_form.first_name}}
{% for department in edit_form.department %}
<h6 id="checkbox">{{department.tag}} {{department.choice_label}}</h6>
{% endfor %}
</div>
</form>
here is the picture
As you can see the names and email are displaying inside the form field but why all checkboxes are empty? (Checkbox fields are department)
If you just want to render the field you don't need a for loop. You can just use {{edit_form.department}}. In case you need to modify each input field in CheckboxSelectMultiple you should loop through edit_form.department.field.choices.
For example:
{% for choice, value in edit_form.department.field.choices %}
<input type="checkbox" name="{{choice.instance.value}}" value="{{choice.instance.pk}}" id="id_{{choice.instance.value}}">
{% endfor %}
Note that this will work only in django 3.0 and newer.
you need pass the value and the name in the input in your template
{% for value, name in edit_form.fields.department.choices %}
<input type="checkbox" name="{{name}}" value="{{value}}" id="{{name}}">
{% endfor %}
I want to modify my UserCreationForm so that when users request to sign up to my site they get given a username of last_name+'.'+first_name.
my django forms.py:
from django import forms
from django.contrib.auth.forms import UserCreationForm
from django.contrib.auth.models import User
class SignUpForm(UserCreationForm):
first_name = forms.CharField(max_length=30, required=False)
last_name = forms.CharField(max_length=30, required=False)
email = forms.EmailField(max_length=254)
class Meta:
model = User
fields = ('first_name', 'last_name', 'email', 'password1', 'password2', )
exclude = ['username', ]
So I have excluded the username from the actual form:
<h2>Sign up</h2>
<form 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 %}
<button type="submit">Sign up</button>
</form>
and in my views.py:
def signup(request):
if request.method == 'POST':
form = SignUpForm(request.POST)
I have tried putting in form.save() here and then trying to get cleaned_data first_name.last_name = username, but it does not work
if form.is_valid():
form.save()
first_name = form.cleaned_data.get('first_name')
last_name = form.cleaned_data.get('last_name')
raw_password = form.cleaned_data.get('password1')
#username = form.cleaned_data.get('username')
username = firstname+'.'+lastname
user = authenticate(username=username, password=raw_password)
user.is_active = False
user.save()
return render(request, 'registration/signedup.html', {'user': user})
else:
return render(request, 'registration/signup.html', {'form': form, 'invalid': 'Please try again.'})
else:
form = SignUpForm()
return render(request, 'registration/signup.html', {'form': form})
By default the UserCreationForm on init checks if the User model USERNAME_FIELD attribute exists in the forms fields so you don't want to exclude the username attribute unless you've selected another field to be your USERNAME_FIELD.
If you want to use username as the USERNAME_FIELD but you don't want it shown on the front end, you can set it as hidden in your html using the template syntax like {{ form.username.as_hidden }}
You can then override the save method for the SignUpForm, this will allow you to do any post processing once the form is valid.
You also don't need to add password1 and password2 to the fields because they're inherited.
You should set the first_name and last_name to be required if you plan on setting the username attribute to be the combined value of the 2 otherwise the code i've provided below won't work when users DON'T enter their first_name and last_name.
class SignUpForm(UserCreationForm):
first_name = forms.CharField(max_length=30, required=False)
last_name = forms.CharField(max_length=30, required=False)
email = forms.EmailField(max_length=254)
class Meta:
model = User
fields = ('email', 'username', 'first_name', 'last_name')
def save(self, commit=True):
user = super(UserCreationForm, self).save(commit=False)
user.set_password(self.cleaned_data["password1"])
user.username = '{}.{}'.format(
self.cleaned_data['last_name'],
self.cleaned_data['first_name']
)
if commit:
user.save()
return user
views.py
def crave_view(request):
if (request.method=="POST"):
form1=CraveDataForm(request.POST, request.FILES)
form2 = CraveReplyForm(request.POST, request.FILES)
print form1
print form2
if form1.is_valid() and form2.is_valid():
crave_made = form1.save(commit=False)
crave_made.person = request.user
crave_made.save()
reply = form2.save(commit=False)
reply.person=request.user
reply.crave = crave_made
reply.save()
#login(request,crave_made.username,form1.clean_password2())
messages.success(request, 'You Registered Successfully')
#return HttpResponseRedirect('/details/')
else:
print form1
print form2
messages.error(request, 'Please enter all required fields')
else:
form2 = CraveReplyForm()
form1=CraveDataForm()
return render(request, "crave/crave.html", { 'form1' : form1, 'form2' : form2 })
models.py
class crave_data(models.Model):
person = models.ForeignKey(User)
post=models.TextField(blank = True,null = True)
date= models.DateTimeField(auto_now_add=True, blank=True)
def __unicode__(self):
return self.post
class comments(models.Model):
crave=models.ForeignKey(crave_data)
reply=models.CharField(max_length=1000, blank = True,null = True)
date= models.DateTimeField(auto_now_add=True, blank=True)
def __unicode__(self):
return self.reply
forms.py
class CraveDataForm(forms.ModelForm):
class Meta:
model = crave_data
exclude=['date', 'password1', 'password2', 'username', 'person']
class CraveReplyForm(forms.ModelForm):
class Meta:
model = comments
exclude=['date', 'crave', 'password1', 'password2', 'username']
crave.html
<form class="horizontal-form" role="form" action="." method="post" style="padding: 10px;">
{% csrf_token %}
<div class="form-group" >
<div class="col-sm-10">
{{ form1.post.label_tag }}{{ form1.post }} <br /><br>
</div>
</div>
<input type="submit" class="btn btn-success" value="crave" />
</form>
<form class="horizontal-form" role="form" action="." method="post" style="padding: 10px;">
{% csrf_token %}
<div class="form-group" >
<div class="col-sm-10">
{{ form2.reply.label_tag }} {{ form2.reply }} </br> </br>
</div>
</div>
<input type="submit" class="btn btn-success" value="reply" />
</form>
i want to submit data of form one only, but the thing is happening that for form2 i.e. for comment blank object is getting created, its due to a foriegn key i given in comment class.
i dont want the blank object getting created for form2. The data should get saved for form2 after clicking on the submit button of form2. And i can not remove foreign key relationship from there also. reply should get submitted for that relative crave only. and data should get submitted independantlly.
I dont want data to be saved for both form after clicking on submit button of one form.
You shouldn't use one view function for two different actions.
You should do view for add/edit Crave objects like this:
from django.shortcuts import get_object_or_404
from django.core.exceptions import PermissionDenied
from django.contrib.auth.decorators import login_required
#login_required
def crave_edit(request, id=None):
instance = get_object_or_404(crave_data, pk=id) if id else None
if instance and instance.person != request.user:
raise PermissionDenied()
if request.method=="POST":
form=CraveDataForm(request.POST, request.FILES, instance=instance)
if form.is_valid():
crave_made = form.save(commit=False)
crave_made.person = request.user
crave_made.save()
else:
form=CraveDataForm(instance=instance)
return render(request, "crave/crave_edit.html", {'form' : form})
Once again, you shouldn't mix add/edit Crave with add comments. You can't add comment to non-exist entity:
#login_required
def crave_view(request, id):
crave = get_object_or_404(crave_data, pk=id)
if request.method=="POST":
form=CraveReplyForm(request.POST, request.FILES)
if form.is_valid():
reply = form.save(commit=False)
reply.person=request.user
reply.crave = crave
reply.save()
else:
form=CraveReplyForm()
return render(request, "crave/crave_view.html", {'crave': crave, 'form' : form})
And please note that names for models should be capitalised, without underlines - "crave_data" is bad style
You can make the foreign key field optional in Django model
Try this way,
crave=models.ForeignKey(crave_data, blank=True, null=True)
If you want submit the forms independently. then put the hidden input field in one form and separate the form logic in view based on hidden input. Like this,
if 'hidden_input' in request.POST.keys():
I need your help.
I extending class User and add same field, than extending UserCreationForm, but form is not valid.
Code crash in if form.is_valid().
Please help, why my form is not correctly?
models.py
class UserProfile(models.Model):
user = models.ForeignKey(User, unique=True, related_name='profile')
nick_name = models.CharField(max_length=15)
My register form
forms.py
class MyRegisterForm(UserCreationForm):
print "OK!"
nick_name = forms.CharField(max_length=30, required=True, widget=forms.TextInput)
print "Ook"
class Meta:
model = UserProfile
def save(self, commit=True):
if not commit:
raise NotImplementedError("Can't create User and UserProfile without database save")
print "Saving..."
user = super(MyRegisterForm, self).save(commit=False)
user.nick_name = self.cleaned_data["nick_name"]
user_profile = UserProfile(user=user, nick_name=self.cleaned_data['nick_name'])
user_profile.save()
print "Saving complete"
return user, user_profile
Register function
views.py
def reg(request):
if request.method =='POST':
form = MyRegisterForm(request.POST)
if form.is_valid():
username = form.cleaned_data['username']
print username
password1 = form.cleaned_data['password1']
print password1
password2 = form.cleaned_data['password2']
print password2
nick_name = form.cleaned_data['nick_name']
print nick_name
form.clean_username()
if password1 == password2:
new_user = form.save()
return render_to_response('registration/registration_complete.html')
else:
print "Password error"
return render_to_response('registration/registration_fail.html')
else:
print "FORM error" #ТУТ ВАЛИТСЯ :(
return render_to_response('registration/registration_fail.html')
else:
form = UserCreationForm() # An unbound form
return render_to_response('registration/registration_new_user.html', {
'form': form,
},context_instance=RequestContext(request))
In setting
settings.py
AUTH_PROFILE_MODULE = 'registration.UserProfile'
Registration template
registration_new_user.html
{% extends "base.html" %}
{% block content %}
<h1>Registration</h1>
<form action="registration" method="post">
{% if form.error_dict %}
<p class="error">Please fix the error.</p>
{% endif %}
{% if form.username.errors %}
{{ form.username.html_error_list }}
{% endif %}
<label for="id_username">Login:</label><br> {{ form.username }}<br>
{% if form.password1.errors %}
{{ form.password1.html_error_list }}
{% endif %}
<label for="id_password1">pass:</label><br> {{ form.password1 }}<br>
{% if form.password2.errors %}
{{ form.password2.html_error_list }}
{% endif %}
<label for="id_password2">pass(again):</label><br> {{ form.password2 }}<br>
{% if form.nick_name.errors %}
{{ form.nick_name.html_error_list }}
{% endif %}
<label for="id_nick_name">nick:</label><br> {{ form.nick_name }}<br>
<br>
<input type="submit" value="Reg" />
</form>
{% endblock %}
Well, you have several issues in your code. For instance, you override UserCreationForm with MyRegistrationForm and indeed you instantiate the latter when the request is a POST, but when is not, you pass the template a normal UserCreationForm.
You do have a user in your UserCreationForm because this is a ModelForm whose model is UserProfile and there you have defined a user field. So it makes perfect sense that the forms complaint about this when you create it with the POST.
I don't see a very clear solution here because your code is somewhat tricky but first of all, use the same form with both GET and POST request type so this line in your views
form = UserCreationForm() # An unbound form
Would change for this one:
form = MyRegistrationForm() # An unbound form
In the template it won't appear the field user because you don't include them but it is in the form. As you are creating a new user, that field should be set to non-required because no user will be associated with the UserProfile because you are creating the user. You can set it to non-required adding the parameter blank=True to the model:
class UserProfile(models.Model):
user = models.ForeignKey(User, unique=True, related_name='profile', blank=True)
nick_name = models.CharField(max_length=15)
UPDATE:
This is the code for your base class UserCreationForm save method:
def save(self, commit=True):
user = super(UserCreationForm, self).save(commit=False)
user.set_password(self.cleaned_data["password1"])
if commit:
user.save()
return user
As you can see, this code assumes that the user has a set_password attribute, in order to fix this, you have to add a def set_password(self, raw_password) method to your UserProfile class. This error happens because the form base class is designed to be used with normal Django User class, any other error you may encounter like this you will probably solve it by adding the fields required to your UserProfile. This one solves like this:
class UserProfile:
...
def set_password(self, raw_password):
# whatever logic you need to set the password for your user or maybe
self.user.set_password(raw_password)
...
I hope this bring some light to the problem. Good luck!