Is there a way to pre-populate a Django form password field so that it display something in the resulting <input type="password"> html element?
The default behavior seems to be not to display anything when the MyForm(initial = {'passfield':'something'}) is set.
I need this in order to implement an user edit form. I want to display a random string which if the user doesn't modify I will know that he does not want to change the password. So I don't think there is ANY security issue in what I'm trying to do.
It seems that using the render_value argument works not just for the case listed in the Django docs and can be used:
class MyForm(forms.Form):
password_field = forms.CharField(widget = forms.PasswordInput(render_value = True))
According to the docs, Django PasswordField does not support initial value. So even when you pass it, it would not render.
You can either subclass the field and make your own password widget which will allow you to do so or you can use HTML5 placeholder. HTML5 is much more secure bevause you can display something to the user, but not the password itself.
For HTML5 support, you can use https://github.com/adamcupial/django-html5-forms. Then you can do something like (not exact syntax but something along the lines of):
class FooForm(forms.Form):
...
password = forms.PasswordField(..., placeholder="Your password here")
I came across similar situation and I did the following:
class UserForm(forms.ModelForm):
password1 = PasswordField(label="Password")
In the PasswordField there is PasswordInput field you will need to set render_value = True as mentioned above which is by default False, then during initialization of UserForm I passed initial value for password.
UserForm(instance=user, initial={'password1': settings.dummy_password})
Now this initial value was predefined in settings file which I compare if the password is changed then update the password else leave the original as is.
Related
In my Contact model I use an EmailField to assure I'm saving a valid email address.
In my form however, I only want the user to be able to change the part before the #, the domain part is not user defined. (e.g. every email needs to end with #gmail.com)
I have looked at a lot of questions about modifying Django form field values before and after validation and display phase, but a lot of the answers are kind of 'hacky' or seem to much of a workaround for my case.
Is there some support of kind of a display filter, which manages a fixed prefix/suffix of a Django form field, without having to edit POST values or needing to suppress certain validations?
Use the clean method in your form to validate the email. It'll be something like this
def clean(self):
"""Check if valid email for institution."""
super().clean()
cleaned_data = self.cleaned_data
if not '#gmail.com' in cleaned_data['email']
msg = forms.ValidationError("Your email must be #gmail")
self.add_error('email', msg)
When using an email field, attempting to submit a form with an invalid email address raises and error like this:
What I like about this:
doesn't reload the page, rather doesn't submit at all and instead displays an error
the look
Here is what I am able to accomplish currently with Name and Password (CharFields)
The "A name is needed!" and "This field is required" messages only display after the form is submitted, which is not as sleek as displaying without the form even needing to be submitted.
The popup that you see for the email it is not django validation. It is the build in in-browser html5 email field checking (and some older browsers will not do it for you).
And you can't get any kind of validation in html5, but for checking field presents you can add required attribute to the rendered input field.
There are several ways to add attibutes to widgets in django. take a look to the How do I get Django forms to show the html required attribute? and select appropriate for you.
kmmbvnr directed me to what I was looking for. To add the type of validation I was looking for, add code similar to that below:
class UserForm(forms.ModelForm):
...
username = forms.CharField(
widget=forms.TextInput(attrs={'required': 'true'}),#HERE
)
password = forms.CharField(
widget=forms.PasswordInput(attrs={'required': 'true'}),#OR HERE
)
...
Say I have a model User, which has a credits field (IntegerField). When a user registers, I will set the credits field to 0, and I will update the credits for certain events.
I don't want the user know there is a field like this in the db table.
What attribute should I set to the field?
To accomplish the defaulting to 0 part, you can simply use the default argument of the model field.
For the part where you don't want your users to know about the field, you have a couple choices.
Solution 1: Field.editable
Defining your field as follows will cause the field to never show up in a model form.
credits = models.IntegerField(default=0, editable=False)
Downsides
You won't be able to edit the field's value in the admin
Form validation will never take this field into account (e.g., def clean_credits(self): won't run)
Solution 2: ModelForm.exclude|fields
Creating a ModelForm for the model is something you're going to be doing. You can define an exclude attribute on the form's Meta class, and add "credits" to the list. See the docs linked above. You can instead define fields on the Meta class, and omit "credits". The latter of the two options is considered a better practice, particularly when pertaining to security, and is known as a whitelist.
Downsides
You have to remember to define exclude or fields on every exposed form
Updating the "secret" field
The proper way to handle specifying a "secret" field's value when the field isn't in the form is:
# Inside your view's post method (or FormView.form_valid, if you're using generic views)
instance = form.save(commit=False) # Does everything except INSERT into the database
instance.credits = <however many credits you feel like giving the user>
instance.save()
If you didn't do that, and instead just saved the form as-is, the value specified by default would be set to the instance's credits field.
You'll want to use an IntegerField with default=0: credits = models.IntegerField(default=0). Just take care not to show this field to the user in any forms or when displaying the user.
E.g., if you had a ModelForm for User, do not include credits in the fields field of Meta
My Model
class Collaborator(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL)
My Form:
class CollaboratorForm(forms.ModelForm):
user = forms.CharField(max_length=30, required=False)
class Meta:
model = Collaborator
fields = ('user',)
The template render the user input text as an autocomplete field loaded from User model.
The page shows the user input text field correctly, however when I go to edit a Collaborator the user input text field shows the user Id and I want to show the username instead.
You want to figure out first what the exact behavior you want is.
Let's say I'm user with id=1, username="Joel". When you produce your CollaboratorForm and it shows "Joel" (my username) on the form and you edit it to read "Jane", are you:
trying to edit my name to "Jane", so that id=1 now has a username=Jane ?
or trying to change the associated user to the user matching that username?
Once you know that, you can proceed.
I'd change the user = forms.CharField(..) to username = forms.CharField(..); that's what your really showing, after all.
In your view, when you create your form, pass it the initial values of {'username':username-of-user-that-is-currently-related}.
In your view, when you process the form, before you save it, use the cleaned_data['username'] to either (a) update the username of that user (if the first case above) or (b) get the ID of the new user and save that to the .user field (if the second case above).
Of course, if what you want is really at a higher-level "let people pick the user based on the username", you might be able to solve this differently and more easily--by not using a CharField at all, and using a ChoiceField instead, so you could show a drop down menu of users with the key=ID and value=name. Depending on how many users you have, though, that might not scale well.
I have a form like this:
class StoreForm(forms.Form):
title = forms.CharField()
link = forms.URLField(verify_exists=True, required=False, initial='http://')
When I fill out the form and leave the link field untouched, I raise an error, because http:// is obviously not a valid link. What would be the best way to remove the initial value to get a valid form?
You can play with the submitted values by overriding clean_foo() method for field.
class StoreForm(forms.Form):
title = forms.CharField()
link = forms.URLField(verify_exists=True, required=False, initial='http://')
def clean_link(self):
data = self.cleaned_data['link']
if data == 'http://':
return ''
else:
return data
Proper way of doing this I think would be extend the default widget and override value_from_datadict method as can be seen here:
Custom widget with custom value in Django admin
Pseudo-form in Django admin that generates a json object on save
You could also override clean() method on Field (extend URLField).
Idea would be to check if value == initial and return None in that case.
Also keep in mind that verify_exists has some security issues as can be seen here:
https://www.djangoproject.com/weblog/2011/sep/09/security-releases-issued/ (Denial of service attack via URLField)