Django PasswordInput - django

I'm using PasswordInput, for an attribute that is optional.
models.py
password = models.CharField(_('Site Password'), max_length=128,
blank=True, null=True)
forms.py
from django.forms import PasswordInput
...
class Meta:
model = ...
widgets = {
'password': PasswordInput(),
}
Which works as expected. However using this widget means there is no way to clear this input, once the password has been set once!
I was hoping to have something like the AdminFileWidget, where there is an option to clear the image/file by selecting the 'clear' checkbox.
Other option is to add an additional 'clear_password' field to the ModelForm.
clear_password = forms.BooleanField(label=_('Clear'), initial=False,
required=False)
And clear the password on save method:
def save(self, commit=True):
...
if self.cleaned_data['clear_password']:
obj.password = None
else:
# Save the provided password in hashed format
obj.password = make_password(self.cleaned_data['password'])
And this works too. But I was hoping a more cleaner solution ..
I had a look at django.forms.widgets.ClearableFileInput .. but it's way too complex for a newbie like me :-(.
Any help will be appreciated. Many Thanks

You could clear the value of the form by passing a null value to the value attribute.
Something like that :
from django.forms import PasswordInput
from models import YourModel
password = forms.PasswordInput(attrs={'value': ''})
class Meta:
model = YourModel

Related

Add help_text to UserCreationForm

I'm using UserCreationForm in Django and I'm trying add help_text to the email field.
Here's the forms.py code:
from django.contrib.auth import get_user_model
from django.contrib.auth.forms import UserCreationForm, UserChangeForm
class CustomUserCreationForm(UserCreationForm):
class Meta(UserCreationForm):
model = get_user_model()
fields = ('email','username',)
help_texts = {
'email': 'Use your work email',
}
I'm using Crispy Forms to render it and it isn't rendering the help_text.
As another approach, I tried adding this to the class:
def __init__(self, *args, **kwargs):
super(CustomUserCreationForm, self).__init__(*args, **kwargs)
self.fields['email'].help_text = 'hello'
But it didn't work either.
What am I missing?
EDIT: I realised I made a mistake with this question. This project had switched to using django-allauth, but left forms.py in the user app of this django project. Therefore none of the changes in these forms were having any effect. A check of the settings would've shown that it was using allauth.
help_texts is not an attribute of the Meta class of a form. You can add the help text for the email field in your model, like this:
email = models.EmailField(max_length=200, help_text='use your work email', blank=True, null=True)
Since email is not one of the fields of UserCreationForm (see https://docs.djangoproject.com/en/3.0/topics/auth/default/#django.contrib.auth.forms.UserCreationForm), setting the field via init will not work.

Validation for model forms

I am trying to do validation for model forms to check if both 'email' and 'confirm_email' have same value. I tried searching online but getting some errors. I am making custom validators in models.py file.
Can you please help me with that. What would be the best way of validating model forms.
Here is my code.
MODELS.PY
from django.db import models
from django.core import validators
from django.core.exceptions import ValidationError
# Create your models here.
def validate_equal(self, email, confirm_email):
if email != confirm_email:
raise ValidationError(
('email does not match'),
params={'email': email, 'confirm_email': confirm_email}
)
class NewSubscriber(models.Model):
first_name = models.CharField(max_length=128)
last_name = models.CharField(max_length=128)
email = models.EmailField(max_length=254,unique=True)
confirm_email = models.EmailField(max_length=254, validators=[validate_equal('self', 'email', 'confirm_email')])
You can't do validation like that, especially when you want to compare fields. All you're doing here is passing the literal strings 'email' and 'confirm_email' (as well as 'self', for some reason) - and you're calling the validation function at define time.
Instead, use a clean method on the form itself.
class NewSubscriberForm(forms.ModelForm):
class Meta:
fields = '__all__'
def clean(self):
if self.cleaned_data['email'] != self.cleaned_data['confirm_email']:
raise forms.ValidationError('email does not match')
return self.cleaned_data

form validation with django CBV FormView

Can someone explain me how can I validate my form, it's rather simple stuff and some how I can I just don't get it, need to validate my select field so I can return and display data, can someone explain how to do this
from django import forms
from statistics.choices import MONTH_CHOICES
class StatisticsForm(forms.Form):
invoice_year = forms.CharField(max_length=255, required=False,
widget=forms.TextInput(attrs={'placeholder': 'Search Year'}))
month_choice = forms.ChoiceField(choices=MONTH_CHOICES)
from django import forms
from statistics.choices import MONTH_CHOICES
class StatisticsForm(forms.Form):
invoice_year = forms.CharField(max_length=255, required=False,
widget=forms.TextInput(attrs={'placeholder': 'Search Year'}))
month_choice = forms.ChoiceField(choices=MONTH_CHOICES)
def clean_invoice_year(self):
invoice_year_val = self.cleaned_data.get('invoice_year')
if condition_not_satisfied:
raise forms.ValidationError('Invalid invoice year')
return invoice_year_val

Instantiating a ModelForm with initial values in CBVs

I am a Django newbie working with Django CBVs and having difficulty setting initial values for my ModelForm. To give an overview, I am trying to learn by creating a simple messaging app.
Here is my code:
models.py
import datetime
from django.contrib.auth.models import User
from django.db import models
from django.utils.translation import ugettext_lazy as _
from django.utils import timezone
class Message(models.Model):
subject = models.CharField(_("Subject"), max_length=100)
body = models.TextField(_("Body"))
sender = models.ForeignKey(User, db_index=True, related_name='sent_messages')
recipient = models.ForeignKey(User, db_index=True, related_name='received_messages')
parent_msg = models.ForeignKey('self', related_name='next_messages', null=True, blank=True)
forms.py
from django.forms import ModelForm
from .models import Message
class MessageForm(ModelForm):
class Meta:
model = Message
exclude = ('sender', 'recipient', 'parent_msg',)
views.py
class MessageCreateView(CreateView):
form_class = MessageForm
model = Message
template_name = 'messages/compose.html'
def form_valid(self, form):
form.instance.sender = self.request.user
return super(MessageCreateView, self).form_valid(form)
urls.py
...
url(r'^compose/(?P<recipient>[\w.#+-]+)/$', MessageCreateView.as_view(), name='messages_compose_to'),
...
As you can see from the urls.py file, I am using the 'recipient' parameter as such: http://localhost:8000/members/compose/someusername
Now my problem is that I wish to open the compose message view, and initialize the recipient field by getting the username from the URL, then using the username from the url to get User with that particular username, and instantiate the form with it.
Where do I do this, in the view itself or in the form? Unless their is a better way of how to handle this.
You can add get_initial() method to return appropriate dict, something as below.
class MessageCreateView(CreateView):
...
def get_initial(self):
data = { 'recipient':
User.objects.get(username=self.kwargs.get('recipient'))
}
return data
Handle error appropriately.

How to create password input field in django

Hi I am using the django model class with some field and a password field. Instead of displaying regular plain text I want to display password input. I created a model class like this:
class UserForm(ModelForm):
class Meta:
password = forms.CharField(widget=forms.PasswordInput)
model = User
widgets = {
'password': forms.PasswordInput(),
}
But i am getting the following error: NameError: name 'forms' is not defined.
I am using django version 1.4.0. I followed this link : Django password problems
Still getting the same error. What should i do. Where am i getting wrong.Please help
The widget needs to be a function call, not a property. You were missing parenthesis.
class UserForm(ModelForm):
password = forms.CharField(widget=forms.PasswordInput())
class Meta:
model = User
You need to include the following in your imports;
from django import forms
Why not just create your own password field that you can use in all your models.
from django import forms
class PasswordField(forms.CharField):
widget = forms.PasswordInput
class PasswordModelField(models.CharField):
def formfield(self, **kwargs):
defaults = {'form_class': PasswordField}
defaults.update(kwargs)
return super(PasswordModelField, self).formfield(**defaults)
So now in your model you use
password = PasswordModelField()
#DrTyrsa is correct. Don't forget your parentheses.
from django.forms import CharField, Form, PasswordInput
class UserForm(Form):
password = CharField(widget=PasswordInput())
I did as a follow without any extra import
from django import forms
class Loginform(forms.Form):
attrs = {
"type": "password"
}
password = forms.CharField(widget=forms.TextInput(attrs=attrs))
The idea comes form source code:
https://docs.djangoproject.com/en/2.0/_modules/django/forms/fields/#CharField
Since this question was asked a couple years ago, and it is well indexed on search results, this answer might help some people coming here with the same problem but be using a more recent Django version.
I'm using Django 1.11 but it should work for Django 2.0 as well.
Taking into account that you using a model user I will assume that you are using the default User() model from Django.
Since the User() model already has a password field, we can just add a widget to it.
from django import forms
from django.contrib.auth.models import User
# also, it will work with a custom user model if needed.
# from .models import User
class UserRegistrationForm(forms.ModelForm):
class Meta:
model = User
fields = ['username', 'password']
widgets = {
# telling Django your password field in the mode is a password input on the template
'password': forms.PasswordInput()
}
Check the docs
I'm fairly new to Django, if my answer was not accurate enough, please let us know, I'd be happy to edit it later on.
** Try to use this **
password1 = forms.CharField(widget=forms.PasswordInput(attrs={
'class': 'input-text with-border', 'placeholder': 'Password'}))
password2 = forms.CharField(widget=forms.PasswordInput(attrs={
'class': 'input-text with-border', 'placeholder': 'Repeat Password'}))
It's very simple.
You should get password form field out of Meta class.
What was written by the OP at password = forms.Charfield(widget=forms.PasswordInput) was correct. It just does not belong in the class Meta: section. Instead, it should be above it, indented one level below class UserForm....
The solutions above works if the field is nullable. Using render_value will render the password into the input field and show the value as asterix placeholders.
Attention: This is great if you simply want to hide the password from users, but the password will be readable by using javascript.
class UserForm(forms.ModelForm):
class Meta:
model = Org
fields = '__all__'
widgets = {
'password': forms.PasswordInput(render_value=True),
}
Edit:
Found a better solution without exposing the current password.
PASSWORD_ASTERIX_PLACEHOLDER will be set as value when loading the input. Before saving the model, it reverts the value to the old one if a user is not setting an explicit new password.
FormInput:
class PrefilledPasswordInput(PasswordInput):
PASSWORD_ASTERIX_PLACEHOLDER: str = 'hidden-password'
def __init__(self, attrs: dict = None, *args, **kwargs):
if not attrs:
attrs = {}
attrs.setdefault('value', PrefilledPasswordInput.PASSWORD_ASTERIX_PLACEHOLDER)
super().__init__(attrs=attrs, *args, **kwargs)
ModelField:
class PasswordCharField(models.CharField):
def to_python(self, value):
return super().to_python(value)
def pre_save(self, model_instance, add):
attr_name = self.get_attname()
if not add:
# Reset to old value if matching with PASSWORD_ASTERIX_PLACEHOLDER
old_instance = self.model.objects.get(id=model_instance.id)
current_value: str = getattr(model_instance, attr_name)
if current_value == PrefilledPasswordInput.PASSWORD_ASTERIX_PLACEHOLDER:
old_value: str = getattr(old_instance, attr_name)
setattr(model_instance, attr_name, old_value)
return super().pre_save(model_instance, add)
Your admin-(form):
class UserForm(forms.ModelForm):
class Meta:
model = Org
fields = '__all__'
widgets = {
'password': PrefilledPasswordInput(),
}
Your model:
class User(SomeBaseModel):
...
password = PasswordCharField(max_length=32, null=False, blank=False)
from django import forms
class loginForm(forms.Form):
username = forms.CharField(
widget=forms.TextInput(attrs={'class': 'form-control', 'placeholder': 'Enter Your userName'}))
password = forms.CharField(
widget=forms.PasswordInput(attrs={'class': 'form-control', 'placeholder': 'please enter password'}))