How to add placeholder UserCreationForm django? - django

I'm trying to add a placeholder to the username field in the UserCreationForm
but i can't understand how to do it.
I have already change the forms.py file in this way /lib/site-packages/django/contrib/auth/forms.py.
I add a placeholder to password1 and password2 fields and work like this:
class UserCreationForm(forms.ModelForm):
"""
A form that creates a user, with no privileges, from the given username and
password.
"""
error_messages = {
'password_mismatch': _("The two password fields didn't match."),
}
password1 = forms.CharField(
label=_("Password"),
strip=False,
widget=forms.PasswordInput(attrs={'placeholder':'Password'}),
help_text=password_validation.password_validators_help_text_html(),
)
password2 = forms.CharField(
label=_("Password confirmation"),
widget=forms.PasswordInput(attrs={'placeholder':'Confirmar Password'}),
strip=False,
help_text=_("Enter the same password as before, for verification."),
)
I can see probably the username field is coming from class meta:
class Meta:
model = User
fields = ("username",)
field_classes = {'username': UsernameField}
from this class but i'm not sure about that
class UsernameField(forms.CharField):
def to_python(self, value):
return unicodedata.normalize('NFKC', super().to_python(value))
I don't understand how add a placeholder to username field
this is my html
<form method="post" action=".">
{% csrf_token %}
{% for field in form %}
{{ field }}<br />
{% for error in field.errors %}
<p style="color: red">{{ error }}</p>
{% endfor %}
{% endfor %}
<input id="submit-signup-btn" type="submit" value="Iniciar"/>
</form>

After a while looking at this, i found a way to do it, this is the way i did it:
in the file /lib/site-packages/django/contrib/auth/forms.py, in class UserCreationForm, under class Meta there is a init function where you can see this line
self.fields[self._meta.model.USERNAME_FIELD].widget.attrs.update({'autofocus':
True})
i added the placeholder to the end of the line in the update method like this:
self.fields[self._meta.model.USERNAME_FIELD].widget.attrs.update({'autofocus': True,
'placeholder':'Nome Perfil'})

Based on #Gabriel costa answer, I came up with this solution:
class AccountCreationForm(UserCreationForm):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields['username'].widget.attrs.update({'placeholder':_('Username')})
self.fields['email'].widget.attrs.update({'placeholder':_('Email')})
self.fields['password1'].widget.attrs.update({'placeholder':_('Password')})
self.fields['password2'].widget.attrs.update({'placeholder':_('Repeat password')})
Other solutions don't work in this scenario.

I had a similiar problem before, this is how i solved it :
class Meta:
......
widgets = {
'username': forms.fields.TextInput(attrs={'placeholder': 'random stuff'})
}
or internally , e.g
city = forms.CharField(widget=forms.TextInput(attrs={'placeholder':'text'}))

You can also define widgets in form's Meta class.
class Meta:
model = User
fields = ("username",)
field_classes = {'username': UsernameField}
widgets = {
'username': form.fields.TextInput(attrs={'placeholder': 'Your text for placeholder'})
}

Related

Django FormModel fields not found

Currently, the template is only generating the Submit button without any input fields.
Also, if I change fields = "all" to fields= ["email","name"] it tells me that these fields do not exist.
Model:
class NewsletterSubscriber(models.Model):
email = EmailField(required=True, label='Email')
name = CharField(required=True, label='Name')
Serializer:
class SubscribeForm(forms.ModelForm):
class Meta:
model = NewsletterSubscriber
fields = "__all__"
View:
def subscribe(request):
form = SubscribeForm()
if request.method == 'POST':
form = SubscribeForm(request.POST)
if form.is_valid():
form.save()
# redirect to a success page
return render(request, 'subscribe.html', {'subscribeForm': form})
Template:
<form action="{% url 'subscribe' %}" method="post">
{% csrf_token %}
{{ subscribeForm.as_p }}
<input type="submit" value="Subscribe">
</form>
Give this a try:
class NewsletterSubscriber(models.Model):
email = EmailField(required=True)
name = CharField(required=True)
class SubscribeForm(forms.ModelForm):
class Meta:
model = NewsletterSubscriber
fields = ['email', 'name']
labels = {'email': 'Email', 'name': 'Name'}
Instead of fields you could instead also go for exclude which would then obviously list the fields that you do not want to show up.
All these attributes you can put in the Meta class: Modelformfactory
Solved.
Wrong:
class NewsletterSubscriber(models.Model):
email = EmailField(required=True, label='Email')
name = CharField(required=True, label='Name')
Correct:
class NewsletterSubscriber(models.Model):
email = models.EmailField(required=True, label='Email')
name = models.CharField(required=True, label='Name')

django form not submitting when rendering specific fields in template

I have an UpdateUserForm:
class UserUpdateForm(UserChangeForm):
email = forms.EmailField()
first_name = forms.CharField(max_length=100)
last_name = forms.CharField(max_length=100)
username = forms.CharField(max_length=100, widget=forms.TextInput())
last_login = forms.CharField(max_length=100, widget=forms.TextInput(attrs={'type': 'hidden'}))
is_superuser = forms.CharField(max_length=100, widget=forms.CheckboxInput(attrs={'type': 'hidden'}))
is_staff = forms.CharField(max_length=100, widget=forms.CheckboxInput(attrs={'type': 'hidden'}))
is_active = forms.CharField(max_length=100, widget=forms.CheckboxInput(attrs={'type': 'hidden'}))
date_joined = forms.CharField(max_length=100, widget=forms.TextInput(attrs={'type': 'hidden'}))
class Meta:
model = User
fields = ('username', 'first_name', 'last_name', 'email', 'last_login', 'date_joined')
def update_user_notification(self):
email = self.cleaned_data['email']
username = self.cleaned_data['username']
if self.is_valid():
update_user_notification_task.delay(email, username)
and a UserUpdate view:
class UserUpdate(generic.UpdateView):
model = User
form_class = UserUpdateForm
template_name = 'accounts/update_user.html'
def get_object(self):
return self.request.user
def form_valid(self, form):
instance = form.save()
form.update_user_notification()
return HttpResponseRedirect(reverse('user_detail', args=[str(instance.pk)]))
I originally wrote this form in the template as {{form.as_p}} and it worked, but there were some things I wanted to fix:
<h1>Update Information...</h1>
<form method="POST">
{% csrf_token %}
{{form.as_p}}
<button>UPDATE</button>
</form>
<br></br>
Back
Home
{% endblock %}
Rendered as this:
I wanted to get rid of those password related things at the bottom so I changed my form to:
<form method="POST">
{% csrf_token %}
<p><label>{{form.email.label}}: </label>{{form.email}}</p>
<p><label>{{form.username.label}}: </label>{{form.username}}</p>
<p><label>{{form.first_name.label}}: </label>{{form.first_name}}</p>
<p><label>{{form.last_name.label}}: </label>{{form.last_name}}</p>
<button>UPDATE</button>
</form>
This worked on the frontend, but now my form isn't submitting. When I click update, the page looks as if it's loading, but my database doesn't updating and my celery task isn't run. What's the issue?
Do I need to have all the fields in order to submit the form? Is there a way to just exclude the password related fields? And is that a better option?
The answer was actually really simple. I added {{form.errors}} to see if any errors were occurring in the actual form, since there were no errors in my network tab.
Turns out that last_login and date_joined are both required in order to POST the form. Once I added them in:
<form method="POST">
{% csrf_token %}
<p><label>{{form.email.label}}: </label>{{form.email}}</p>
<p><label>{{form.username.label}}: </label>{{form.username}}</p>
<p><label>{{form.first_name.label}}: </label>{{form.first_name}}</p>
<p><label>{{form.last_name.label}}: </label>{{form.last_name}}</p>
<p>{{form.last_login}}</p>
<p>{{form.date_joined}}</p>
<button>UPDATE</button>
</form>
The form was able to submit and update the database. I left out the label because those forms for me are attrs={'type': 'hidden'} anyway. Although this brings up another question as to why are these fields required to submit? Is there a way to just not require them and save the trouble of hiding them?

Django custom Management: Unable for an "administrator" to update an user

I'm currently creating a django customer management/admin interface for a web application(I know of the built-in one, but as part of this project, a custom one needs to be created).
I'm supposed to be able to create/update/delete users from this interface, while connected as a Manager/Admin.
While connected as a manager/admin I can successfully create or delete an user, I'm unable to update one (I keep getting the error that the user "already exists")
Help or the wright direction to follow would be much apreciated as I've been struging with this for a while and am blocked atm.
Hereunder the code.
(models.py) class UserProfile (one to one to built-in Django User class)
class UserProfile(models.Model):
"""
The Class UserProfile extends the built-in "User" class of Django
Used here to add extra fields in the forms
"""
user = models.OneToOneField(User, on_delete=models.CASCADE,verbose_name="User")
vpn_enabled = models.BooleanField(default=False, verbose_name="VPN Enabled")
language = models.CharField(max_length=2, choices=LANGUAGES, default='EN', verbose_name="Language")
birth_date = models.DateField(null=True,blank=True, verbose_name="Birth Date")
address = models.CharField(max_length=200, null=True, blank=True, verbose_name="Address")
postal_code = models.CharField(max_length=50,null=True, blank=True, verbose_name="Postal Code")
country = models.CharField(max_length=20, blank=True, null=True, verbose_name="Country")
class Meta:
verbose_name = 'User Profile'
verbose_name_plural = 'User Profiles'
def __str__(self):
return self.user.username
views.py
#group_required('Administrator', 'Manager')
def update_user(request, id):
user = User.objects.get(id=id)
user_update_form = UserUpdateForm(request.POST or None, instance = user)
user_profile_update_form = UserProfileUpdateForm (request.POST or None, instance = user.userprofile)
if user_update_form.is_valid() and user_profile_update_form.is_valid():
user_update_form.save()
user_profile_update_form.save()
return redirect("manager_home")
context = {
'user_update_form': user_update_form,
'user_profile_update_form': user_profile_update_form,
}
return render (request, "update_user.html", context)
forms.py
class UserUpdateForm(forms.ModelForm):
"""UserUpdateForm custom made class"""
class Meta:
""" Meta definitioon of UserUpdateForm"""
model = User
fields = [
'username',
'last_name',
'first_name',
'email',
]
class UserProfileUpdateForm(forms.ModelForm):
'''UserProfileUpdateForm custom made class'''
class Meta:
"""Meta definition of UserProfileUpdateForm"""
model = UserProfile
fields = [
'language',
'birth_date',
'address',
'postal_code',
'country',
]
template
<!-- template update_user.html -->
{% extends 'base.html' %}
{% block title %} Edit User {% endblock %}
{% block content %}
<form method="POST" class="post-form" action="{% url 'update_user' user.id %}">
{% csrf_token %}
{{user_update_form.as_p}}
{{user_profile_update_form.as_p}}
{{user_update_form.errors}}
<hr>
<button type="submit">Update User</button>
</form>
{% endblock %}
result (while trying to update, for example, user country)
enter image description here
The problem is with the view. If you are using function as a view you need to say explicitly what you do in case of the post request, otherwise everything will be processed as GET request, and this is not something that you want.
#group_required('Administrator', 'Manager')
def update_user(request, id):
if request.method == 'GET':
# get request processing code
# you are missing POST request processing part
if request.method == 'POST':
# post request processing code

Django One-To-One relationships on forms

I have the following model that links to "user":
class Profile(models.Model):
user = models.OneToOneField(User)
title = models.CharField(max_length=10)
dob = models.DateField(max_length=8)
class Meta:
managed = True
db_table = 'fbf_profile'
I then have the following registration form:
class RegistrationForm(BootstrapModelForm, UserCreationForm):
def __init__(self, *args, **kwargs):
super(RegistrationForm, self).__init__(*args, **kwargs)
# The default Django user model doesn't require these fields to be set
# but we do.
self.fields['first_name'].required = True
self.fields['last_name'].required = True
self.fields['email'].required = True
def clean_email(self):
email = self.cleaned_data['email']
if User.objects.filter(email__iexact=email).exists():
raise ValidationError('There is already an account registered with this e-mail address.')
return email
class Meta:
model = User
fields = ['first_name', 'last_name', 'email', 'username']
I am then able to use them in my templates like so:
<div class="form-group">
<label class="col-sm-5 control-label">{{ form.first_name.label }}:</label>
<div class="col-sm-7">
{{ form.first_name }}
<div class="text-danger">
{% for error in form.first_name.errors %}{{ error }}<br/>{% endfor %}
</div>
</div>
</div>
However, how can I use the "dob" from the Profile model within the template in much the same way as I have done with form.first_name.label and form.first_name above. Many thanks in advance, Alan.
If using modelForms you well need two distinct forms - one for the User model and one for the Profile model. You then display both within the same <form> tag in your template, and validate / save both in your view.
The other solution is to define a plain (non 'model') form with fields for both models, and write the save method by yourself.
Assuming that form is an User object which you're using in the template, you should be able to access the dob field using form.profile.dob.
Many thanks to Bruno who gave the correct answer above. It led me to the following link:
https://simpleisbetterthancomplex.com/tutorial/2016/07/22/how-to-extend-django-user-model.html#onetoone
I hope it helps someone.

Django passing object ID in hiddeninput by populating

I have an form which allows a user to edit an object description.
How can I populate an object ID in a form's hidden input value.
What I done so far is I added an field called hidden_field in forms.py but it only show the hidden_field . How can I link the hidden_field with the object ID
models.py
class School(models.Model):
user = models.ForeignKey(User)
name = models.CharField(max_length=55)
description = models.CharField(max_length=300,blank=True)
forms.py
class SchoolDescriptionForm(forms.ModelForm):
description = forms.CharField(widget=forms.Textarea,max_length=300)
hidden_field = forms.CharField(widget=forms.HiddenInput())
class Meta:
model = School
fields = ()
views.py
def SchoolEditor(request,school_id):
school = School.objects.get(pk=school_id,user=request.user)
form = SchoolDescriptionForm(instance=school) # I want to populate the object ID
return render(request,'schooleditor.html',{'school':school,'form':form})
template
<form method="POST" enctype="multipart/form-data">
{% csrf_token %}
{{ form.as_p }}
<input type = "submit" value= "save" />
{{ form.field.as_hidden }}
</form>
Change hidden_field to id and tell Django to include the School's id.
class SchoolDescriptionForm(forms.ModelForm):
description = forms.CharField(widget=forms.Textarea,max_length=300)
id = forms.CharField(widget=forms.HiddenInput())
class Meta:
model = School
fields = ('id', 'name', 'description')
EDIT:
If you want to conserve hidden_field as name you should then add a custom init method:
def __init__(self, *args, **kwargs):
super(SchoolDescriptionForm, self).__init__(*args, **kwargs)
if self.instance:
self.fields['hidden_field'].initial = instance.id
Just pass the object id in the form initial:
def SchoolEditor(request,school_id):
initial = {}
school = School.objects.get(pk=school_id,user=request.user)
if school:
initial.update({'hidden_field': school.id})
form = SchoolDescriptionForm(instance=school, initial=initial) # I want to populate the object ID
return render(request,'schooleditor.html',{'school':school,'form':form})