How can I change a Django form field value before saving?
Asked Answered
O

6

44
if request.method == 'POST':
    userf = UsersModelForm(request.POST)
    username = userf.data['username']
    password = userf.data['password']
    passwordrepeat = userf.data['passwordrepeat']
    email = userf.data['email']

I tried this:

    tempSalt = bcrypt.gensalt()
    password = bcrypt.hashpw(password,tempSalt)
    passwordrepeat = bcrypt.hashpw(passwordrepeat,tempSalt)

    userf.data['password'] = password
    userf.data['passwordrepeat'] = passwordrepeat

But i got error. How can i change the value of userf.data['password'] and userf.data['passwordrepeat'] before saving?

Error:

AttributeError at /register

This QueryDict instance is immutable

Request Method:     POST
Request URL:    http://127.0.0.1:8000/register
Django Version:     1.3.1
Exception Type:     AttributeError
Exception Value:    

This QueryDict instance is immutable

Exception Location:     /usr/local/lib/python2.6/dist-packages/django/http/__init__.py in _assert_mutable, line 359
Python Executable:  /usr/bin/python
Python Version:     2.6.6
Python Path:    

['/home/user1/djangoblog',
 '/usr/lib/python2.6',
 '/usr/lib/python2.6/plat-linux2',
 '/usr/lib/python2.6/lib-tk',
 '/usr/lib/python2.6/lib-old',
 '/usr/lib/python2.6/lib-dynload',
 '/usr/local/lib/python2.6/dist-packages',
 '/usr/lib/python2.6/dist-packages',
 '/usr/lib/python2.6/dist-packages/gst-0.10',
 '/usr/lib/pymodules/python2.6',
 '/usr/lib/pymodules/python2.6/gtk-2.0']
Overbearing answered 19/1, 2012 at 11:6 Comment(6)
What kind of error do you have ? Validation error, integrity error ? You must always post the error message. ALWAYS.Kurr
I have updated the error, see that again to understand.Overbearing
We need what you want to do as well: set a default value, set a value if not value exist, correct a value if it's not good, etc. There are several hooks on django forms.Kurr
I have updated the original post/question. See that again to understand.Overbearing
It doesn't tell us what you want to do, it tells use what you are doing. What result do you want ? Not at the programming level, at the feature level.Kurr
You might want to use the django internal hashing function django.contrib.auth.hashers.make_password instead bcrypt.hashpwBobettebobina
G
60

If you need to do something to the data before saving, just create a function like:

def clean_nameofdata(self):
    data = self.cleaned_data['nameofdata']
    # do some stuff
    return data

All you need is to create a function with the name **clean_***nameofdata* where nameofdata is the name of the field, so if you want to modify password field, you need:

def clean_password(self):

if you need to modify passwordrepeat

def clean_passwordrepeat(self):

So inside there, just encrypt your password and return the encrypted one.

I mean:

def clean_password(self):
    data = self.cleaned_data['password']
    # encrypt stuff
    return data

so when you valid the form, the password would be encrypted.

Gott answered 19/1, 2012 at 15:31 Comment(4)
I don't understand your question. Where? Inside the clean_foo, you get the plain password and transform it.Gott
I meant where would i create those def clean_password(self): functions?Overbearing
Oh, true, inside the form class you created.Gott
It should be 'self.cleaned_data['password']' (you forgot the 'ed' in the last code block)Infection
I
23

See the documentation for the save() method

if request.method == 'POST':
    userf = UsersModelForm(request.POST)
    new_user = userf.save(commit=False)

    username = userf.cleaned_data['username']
    password = userf.cleaned_data['password']
    passwordrepeat = userf.cleaned_data['passwordrepeat']
    email = userf.cleaned_data['email']

    new_user.password = new1
    new_user.passwordrepeat = new2

    new_user.save()
Insatiable answered 19/1, 2012 at 11:23 Comment(2)
It's one kind of updating. Is it possible to change/modify the value before saving?Overbearing
The linked section of the Django docs doesn't work anymore. As of today, the latest version of the framework (5.0) has this feature still working the same way, which is documented here: docs.djangoproject.com/en/5.0/topics/forms/modelforms/…Guidebook
F
9

You will have problems if you need to fill form from POST, change any form field value and render form again. Here is solution for it:

class StudentSignUpForm(forms.Form):
  step = forms.IntegerField()

  def set_step(self, step):
    data = self.data.copy()
    data['step'] = step
    self.data = data

And then:

form = StudentSignUpForm(request.POST)
if form.is_valid() and something():
  form.set_step(2)
  return  render_to_string('form.html', {'form': form})
Finesse answered 17/5, 2013 at 7:34 Comment(2)
I had a similar problem where I have two submit buttons. The first creates a preview and the second is the actual submission. The not submitted button's value would get wiped out by creating form with the POST data (naturally). This method work's perfectly for restoring the non-clicked button's value.Duval
This is nice and flexibleDovecote
K
6

Override _clean methods and put your checks in them. You can modify cleaned_data from there.

E.g:

def clean_password(self):
    new1 = self.cleaned_data['password']
    return new1

Every fields in the form will have a field_name_clean() method created automatically by Django. This method is called when you do form.is_valid().

Kurr answered 19/1, 2012 at 11:10 Comment(5)
I could not understand. Can you post complete code with explaination. That would be helpful.Overbearing
It's ModelForm, not Form, is cleaned_data available for ModelForm?Overbearing
When is the clean_passwor(self): function called?Overbearing
This is the complete code. I added a link to the documentation. It works with any form, including model forms. This function is trigged automatically before the model is saved.Kurr
docs.djangoproject.com/en/1.3/ref/forms/validation/…Skitter
W
3

In Views:

def post(self, request, *args, **kwargs):
    form = self.form_class(request.POST)
    if form.is_valid():
        obj = form.save(commit=False)
        obj.my_field = 'value'
        obj.save()

In Forms:

instance = form.instance
instance.user = request.user
instance.save()

But be careful, this does not check is_valid(). If you want to do that, you can instantiate the form with the new values:

# NOT TESTED, NOT SURE IF THIS WORKS...
form = MyForm(instance=instance)
if form.is_valid():
    form.save()
Wilder answered 14/2, 2018 at 20:27 Comment(0)
S
0

The original question is "to modify/update a form field value before saving". Some methods above seem to be used after saving. This reference may be useful in solving This QueryDict instance is immutable. You may try the following method

if request.method == 'POST':
    userf = UsersModelForm(request.POST)
    ...
    data = request.POST.copy()
    # remember old state
    _mutable = data._mutable

    # set to mutable
    data._mutable = True

    data['password'] = password
    data['passwordrepeat'] = passwordrepeat

    # set mutable flag back
    data._mutable = _mutable

    userf = UsersModelForm(data)

    if userf.is_valid():
        userf.save()
Subjugate answered 24/8, 2023 at 10:44 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.