I want to add placeholders to my fields but for some reason, this is not working. When I view page source, the placeholder attributes are not even there.
Here is my forms.py:
class RegistrationForm(UserCreationForm):
email = forms.EmailField(required=True, max_length=254)
class Meta:
model = User
fields = ('username', 'email', 'password1', 'password2',)
widgets = {
'username' : forms.TextInput(attrs={'placeholder': 'Username'}),
'email' : forms.TextInput(attrs={'placeholder': 'Email'}),
'password1' : forms.TextInput(attrs={'placeholder': 'Password'}),
'password2' : forms.TextInput(attrs={'placeholder': 'Confirm Password'}),
}
This is the template I am using for HTML:
<!DOCTYPE html>
{% extends 'base.html' %}
{% load staticfiles %}
{% block content %}
<section class="container">
<div class="row centre-v">
<div class="card login-card">
<div class="main card-block">
<h1>Sign up</h1>
<div class="login-or">
<hr class="hr-or">
</div>
<form action="." method="post" class="register-form">
{% csrf_token %}
{% for field in form %}
<p>
{{ field }}
{% for error in field.errors %}
<div class="alert alert-danger" role="alert"><strong>{{ error }}</strong></div>
{% endfor %}
</p>
{% endfor %}
<div class="btn-login">
<input class="btn btn-info" type="submit" value="Register">
</div>
</form>
</div>
</div>
</div>
</section>
{% endblock %}
According to the docs for ModelForm, the Meta class is only used to generate fields from the underlying model. Fields which are declared explicitly in the ModelForm class are not affected by the attributes set in Meta. You declare email in your class, and password1 and password2 are declared in the inherited UserCreationForm class. (username is generated automatically, so the widget attribute you set in the Meta class may have worked for that field.) To set attributes for declared fields you can use the self.fields dict.
class RegistrationForm(UserCreationForm):
email = forms.EmailField(required=True, max_length=254)
class Meta:
model = User
fields = ('username', 'email', 'password1', 'password2',)
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs):
self.fields['username'].widget.attrs['placeholder'] = 'Username'
self.fields['email'].widget.attrs['placeholder'] = 'Email'
self.fields['password1'].widget.attrs['placeholder'] = 'Password'
self.fields['password2'].widget.attrs['placeholder'] = 'Confirm Password'
Related
I am following a Django tutorial on Youtube, I added a bio field in the UserUpdateForm. There is a slot for me to edit the bio on change_profile.html but when I press the update button it updates everything else except for the bio.
from django import forms
from django.contrib.auth.models import User
from django.contrib.auth.forms import UserCreationForm
from .models import Profile
class UserRegisterForm(UserCreationForm):
email = forms.EmailField()
class Meta:
model = User
fields = ['username', 'email', 'password1', 'password2']
class UserUpdateForm(forms.ModelForm):
email = forms.EmailField()
# What I added
bio = forms.CharField(required=False)
class Meta:
model = User
fields = ['username', 'email', 'bio']
class ProfileUpdateForm(forms.ModelForm):
class Meta:
model = Profile
fields = ['image']
The function that saves the forms
#login_required
def change_profile(request):
if request.method == 'POST':
u_form = UserUpdateForm(request.POST, instance=request.user)
p_form = ProfileUpdateForm(request.POST, request.FILES, instance=request.user.profile)
if u_form.is_valid() and p_form.is_valid():
u_form.save()
p_form.save()
messages.success(request, 'Profile Updated')
return redirect('profile')
else:
u_form = UserUpdateForm(instance=request.user)
p_form = ProfileUpdateForm(instance=request.user.profile)
context = {
'u_form' : u_form,
'p_form' : p_form
}
return render(request, 'users/change_profile.html', context)
The change_profile.html
{% extends "blog/base.html" %}
{% load crispy_forms_tags %}
{% block title %}Change Profile{% endblock title %}
{% block content %}
<div class="content-section">
<form method="post" enctype="multipart/form-data">
{% csrf_token %}
<fieldset class="form-group">
<legend class="border-bottom mb-4">Edit Profile</legend>
{{ u_form|crispy }}
{{ p_form|crispy }}
</fieldset>
<div class="form-group">
<button class="btn btn-outline-info" type="submit">Update</button>
</div>
</form>
</div>
{% endblock content %}
And the profile.html
{% extends "blog/base.html" %}
{% block title %}Profile{% endblock title %}
{% block content %}
<div class="content-section">
<div class="media">
<img class="rounded-circle account-img" src="{{ user.profile.image.url }}">
<div class="media-body">
<h2 class="account-heading">{{ user.username }}</h2>
<p class="text-secondary">{{ user.email }}</p>
<p class="article-content">{{ user.bio }}</p>
</div>
</div>
<a class="ml-2" href="{% url 'change_profile' %}">Edit Profile</a>
{% endblock content %}
It's because the default User model has no attribute called bio, so there's nowhere to store the value you're getting from the form. You need to add it to the model first. You can create a custom user model, but since you already have a Profile model, you can store bio along with image:
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
image = models.ImageField()
bio = models.CharField(max_length=225, blank=True, null=True)
And in forms.py add the new field to the field list:
class ProfileUpdateForm(forms.ModelForm):
class Meta:
model = Profile
fields = ('image', 'bio')
You could have simply override the the User model and add your custom fields, then you don't need to add extra fields in your form. Check this example:
from django.contrib.auth.models import User
class UserProfile(models.Model):
user = models.OneToOneField(User)
bio = models.TextField()
def __str__(self):
return unicode(self.user)
Make sure you add mention your custom User model in settings:
AUTH_USER_MODEL ='your_app.UserProfile'
In views.py I've got a method called signup:
def signup(request):
context = {}
if request.method == 'POST':
form = SignUpForm(request.POST)
print("request", request.POST)
if form.is_valid():
user = form.save(commit=False)
login(request, user)
return redirect('index')
else:
context['form'] = form
else: # GET request
form = SignUpForm()
context['form'] = form
return render(request, 'registration/signup.html', context)
Request print gives me all the fields a user entered:
request <QueryDict: {'csrfmiddlewaretoken': ['***'], 'username': ['12312312gdsgdsg'], 'email': ['123123fsdfesgf#gmail.com'], 'password1': ['123fhfhfh'], 'password2': ['989898gdfjgndf']}>
When I call form.is_valid() it gets to clean data of my form of forms.py:
class SignUpForm(UserCreationForm):
username = forms.CharField(
label="username",
max_length=30,
required=True,
widget=forms.TextInput(
attrs={
'type': 'text',
'placeholder': 'Username',
}
),
)
email = forms.EmailField(
label="email",
max_length=60,
required=True,
widget=forms.TextInput(
attrs={
'type': 'text',
'placeholder': 'Email',
}
),
)
password1 = forms.CharField(
label="password1",
required=True,
widget=forms.PasswordInput(
attrs={
'type': 'password',
'placeholder': 'Password',
}
),
)
password2 = forms.CharField(
label="password2",
required=True,
widget=forms.PasswordInput(
attrs={
'type': 'password',
'placeholder': 'Confirm Password',
}
),
)
def clean(self):
cleaned_data = super(SignUpForm, self).clean()
print("cleaned data", cleaned_data)
password = cleaned_data["password1"]
confirm_password = cleaned_data["password2"]
if password != confirm_password:
self.add_error('confirm_password', "Password and confirm password do not match")
return cleaned_data
class Meta:
model = ServiceUser
fields = ('username', 'email', 'password1', 'password2')
The form's cleaned data print returns me the same dictionary as the post, but WITHOUT password2:
cleaned data {'username': '12312312gdsgdsg', 'email': '123123fsdfesgf#gmail.com', 'password1': '123fhfhfh'}
I'm new to Django and I don't understand why password2 cannot get to be in cleaned data. I have already watched the post about data validation (Django Forms cleaned_data missing certain fields), but the person of this problem made a wrong field and his data couldn't be validated. I've got 2 identical fields for passwords, password1 gets to be cleaned and password2 does not. I cannot understand the problem.
My signup.html template:
{% extends 'base.html' %}
{% load static %}
{% block head %}
<link href="https://cdn.jsdelivr.net/npm/bootstrap#5.1.1/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-F3w7mX95PdgyTmZZMECAngseQB83DfGTowi0iMjiWaeVhAn4FJkqJByhZMI3AhiU" crossorigin="anonymous">
<script src="https://cdn.jsdelivr.net/npm/bootstrap#5.1.1/dist/js/bootstrap.min.js"></script>
<link rel="stylesheet" type="text/css" href="{% static 'css/sign_template.css' %}">
<title>Signup</title>
{% endblock %}
{% block content %}
{% if user.is_authenticated %}
<meta http-equiv="refresh" content="0; URL={% url 'index' %}" />
{% else %}
<form method="post">
<div class="sign-card">
<h3>Signup</h3>
{% csrf_token %}
{{ form.errors }}
{{ form.non_field_errors }}
<div class="input-div">
<label for="{{ form.username.id_for_label }}">Username:</label>
{{ form.username }}
</div>
<div class="input-div">
<label for="{{ form.email.id_for_label }}">Email:</label>
{{ form.email }}
</div>
<div class="input-div">
<label for="{{ form.password.id_for_label }}">Password:</label>
{{ form.password1 }}
</div>
<div class="input-div">
<label for="{{ form.password.id_for_label }}">Confirm Password:</label>
{{ form.password2 }}
</div>
{% if form.errors %}
{% for field in form %}
{% for error in field.errors %}
<div class="alert alert-danger alert-dismissible fade show" role="alert">
<strong>{{ error|escape }}</strong>
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
</div>
{% endfor %}
{% endfor %}
{% endif %}
<button type="submit" class="btn-custom">Sign up</button>
<p>Already have account? Log In</p>
</div>
</form>
{% endif %}
{% endblock %}
Many thanks for your help!
Django's UserCreationForm [Django-doc] implements a clean_password2 that will check if the two passwords match, and raise an exception otherwise.
You can customize the error message with:
from django.utils.translation import gettext_lazy as _
class SignUpForm(UserCreationForm):
error_messages = {
'password_mismatch': _('some text to translate')
}
# ⋮
# do not override the clean method
Here the 'some text to translate' should be the text you want to use when the two passwords do not match.
I'm building a a sign up form. The form is defined as follows:
class UserSignUpForm(UserCreationForm):
username = forms.CharField(widget=forms.TextInput(attrs={'class':'form-control', 'placeholder':'Username'}))
first_name = forms.CharField(max_length=30, required=False, help_text='Optional.',widget=forms.TextInput(attrs={'class': 'form-control'}))
last_name = forms.CharField(max_length=30, required=False, help_text='Optional.',widget=forms.TextInput(attrs={'class': 'form-control'}))
email = forms.EmailField(max_length=100, help_text='Required',widget=forms.TextInput(attrs={'class': 'form-control', 'type':'email'}))
class Meta:
model = User
fields = ('username', 'first_name', 'last_name','email', 'password1', 'password2')
widgets = {
'password1': forms.TextInput(attrs={'class': 'form-control'}),
'password2': forms.TextInput(attrs={'class': 'form-control'}),
}
This is what signup.html looks like:
<form method="post">
{% csrf_token %}
{% for field in form %}
<div class="form-group">
<label for="{{ field.auto_id }}"> {{ field.label_tag }} </label>
{{ field }}
{% if field.help_text %}
<small class="form-text text-muted">{{ field.help_text }}</small>
{% endif %}
{% for error in field.errors %}
<p style="color: red">{{ error }}</p>
{% endfor %}
</div>
{% endfor %}
<button type="submit" class="btn btn-primary">Sign up</button>
</form>
With the above setup, the attributes passed to password1 and password2 fields do not get applied when the form is rendered.
One alternative to what you are trying to do is write your html code for password in separate html page and then apply class in the password
Like this: -
I hope this will help
password <input type="passsword" class='form-controle'>
I am trying to go to the author profile if i press on his name. This is my HTML which do these:
{% extends "blog/base.html" %}
{% load crispy_forms_tags %}
{% block content %}
<div class="content-section">
<div class="media">
<img class="rounded-circle account-img" src="{{ user.profile.image.url }}">
<div class="media-body">
<h2 class="account-heading">{{ user.username }}</h2>
</div>
</div>
<form method="POST" enctype="multipart/form-data">
{% csrf_token %}
<fieldset class="form-group">
<legend class="border-bottom mb-4">Profile Info</legend>
<p class="text-secondary"><h3>Contact Me Here: </h3>{{ user.email }}</p>
</fieldset>
</form>
</div>
{% endblock content %}
In my views.py i have this:
def author_profile(request):
user = Post.author
u_form = UserUpdateForm(instance=request.user)
p_form = ProfileUpdateForm(instance=request.user.profile)
context = {
'u_form': u_form,
'p_form': p_form
}
return render(request, 'blog/author_profile.html', context)
Where UserUpdateForm and ProfileUpdateForm from the forms.py have this code:
class UserUpdateForm(forms.ModelForm):
email = forms.EmailField()
class Meta:
model = User
fields = ['username', 'email']
class ProfileUpdateForm(forms.ModelForm):
class Meta:
model = Profile
fields = ['image']
Class for the Post:
class Post(models.Model):
title = models.CharField(max_length=100)
content = models.TextField()
date_posted = models.DateTimeField(default=timezone.now)
author = models.ForeignKey(User, on_delete=models.CASCADE)
def __str__(self):
return self.title
If i press on the name it is getting me to the user profile, I tried to work with Post.author but didn't worked.
It's my first time with django.
I have a Django model class that extends the django.contrib.auth.models.User:
class MyModel(models.Model):
user = models.OneToOneField(User, models.CASCADE, unique=True)
bio = models.TextField()
date_of_birth = models.DateField()
and out of this model I'm making a ModelForm:
class MyModelForm(forms.ModelForm):
class Meta:
model = MyModel
fields = ['bio', 'date_of_birth']
How can I tell the MyModelForm to take in the User's fields such as username, first_name, last_name?
Example in the class Meta fields I can add ['bio', 'date_of_birth', 'user'] but that will just provide me with the dropdown to select to whom shall the MyModel in the MyModelForm be related to.
Doing ['bio', 'date_of_birth', 'user.first_name'] throws an exception django.core.exceptions.FieldError: Unknown field(s) (user.first_name) specified for MyModel
Edit: here's the traceback
https://pastebin.com/0T42VKEP
I kinda found my own solution, by overriding ModelForm's __init__ method:
class MyModelForm(forms.ModelForm):
first_name = forms.CharField()
class Meta:
model = MyModel
fields = ['bio', 'date_of_birth']
def __init__(self, *args, **kwargs):
super(MyModelForm, self).__init__(*args, **kwargs)
my_user = kwargs.get('instance')
first_name = my_user.user.first_name
self.fields['first_name'].initial = first_name #this will show the first name in the html page when i request the instance
And when I'm instantiating my form I just pass an instance of MyModel as a
kwarg: form = MyModelForm(instance=my_model_instance)
You can use InlinFormset. Here I am posting a code sample used by me that might help you. I have modified a bit according to your need, so if anything doesn't work let me know.
#forms.py
class UserForm(forms.ModelForm):
class Meta:
model = User
class MyModelForm(forms.ModelForm):
class Meta:
model = MyModel
then in your views you should do like
def profileEdit(request,username):
# querying the User object with pk from url
user = User.objects.get(username=username)
# prepopulate MyModelForm with retrieved user values from above.
user_form = UserForm(instance=user)
MyModelInlineFormset = inlineformset_factory(User, MyModel,can_delete=False, fields="__all__")
formset = MyModelInlineFormset(instance=user)
if request.user.is_authenticated() and request.user.id == user.id:
if request.method == "POST":
user_form = UserForm(request.POST, request.FILES, instance=user)
formset = MyModelInlineFormset(request.POST, request.FILES, instance=user)
if user_form.is_valid():
created_user = user_form.save(commit=False)
formset = MyModelInlineFormset(request.POST, request.FILES, instance=created_user)
if formset.is_valid():
created_user.save()
formset.save()
return HttpResponseRedirect('/')
return render(request, "profile_edit.html", {
'title':'Edit -'+ user.get_full_name(),
"user_form": user_form,
"formset": formset,
})
else:
raise PermissionDenied
and in your profile_edit.html
{% extends "layout.html" %}
{% block content %}
{% if messages %}
<div>
{% for message in messages %}
<div class="alert alert-{{ message.tags }}"> <!-- singular -->
<a class="close" data-dismiss="alert">×</a>
{{ message|safe }}
</div>
{% endfor %}
</div>
{% endif %}
<div class="col-xs-8 col-xs-offset-2">
<div class="card">
<div class="card-content">
<h2 class="flow-text">Update your information</h2>
<form action="." method="POST" class="padding" enctype="multipart/form-data">
{% csrf_token %}
{% for field in user_form %}
<div class="form-group">
{{ field.errors }}
<label for="{{ field.label }}" >{{ field.label }}</label>
{{ field }}
{% if field.help_text %}
<small class="form-text text-muted">{{ field.help_text|safe }}</small>
{% endif %}
</div>
{% endfor %}
{{ formset.management_form }}
{% for form in formset %}
{% for hidden in form.hidden_fields %}
{{ hidden }}
{% endfor %}
{% for field in form.visible_fields %}
<div class="form-group">
{{ field.errors }}
<label for="{{ field.label }}" >{{ field.label }}</label>
{{ field }}
{% if field.help_text %}
<small class="form-text text-muted">{{ field.help_text|safe }}</small>
{% endif %}
</div>
{% endfor %}
{% endfor %}
<input type="submit" class="btn btn-primary" value="Save"></input>
</form>
</div>
</div>
</div>
{% endblock content %}