Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Add data to Django form before it is saved?

In this simplified use case, I have a Django form that contains MyField_1 and MyField_2. The user fills out MyField_1. Before the form is saved as a model, I want the computer to add MyField_2 programmatically which is some data pulled in from another data source. The view I currently have looks like this:

class MyCreate(CreateView):
    model = MyModel
    fields = ['MyField_1']

How can I add the data to MyField_2 before the model is saved?

like image 278
Alexis Avatar asked Jul 20 '17 17:07

Alexis


3 Answers

There are various ways to do it (for instance overriding the ModelForm.save() method) , however the one I recommend is overriding the ModelFormMixin.form_valid() method. So change your view like this:

class MyCreate(CreateView):
  model = MyModel
  fields = ['MyField_1']

  def form_valid(self, form):
    self.object = form.save(commit=False)
    self.object.MyField_2 = 43
    self.object.save()
    return super(ModelFormMixin, self).form_valid(form)

Two suggestions:

  • For all your CBV needs always take a look at the great CBV inspector tool: https://ccbv.co.uk/projects/Django/1.11/django.views.generic.edit/CreateView/
  • Plase use proper lower_case_with_underscores names for your fields. MyField_1 should have been my_field_1.
like image 110
Serafeim Avatar answered Nov 10 '22 05:11

Serafeim


You can do this by(See second example for class based views):

if request.method == 'POST':
    form = Form(request.POST)
    if form.is_valid():
        instance = form.save(commit=False)
        instance.my_field_2 = #Put value here
        instance.save()
        return #Put return here
else:
    form = Form()

This way you can initialize any value to form which user don't input.

In Class based CreateView you can override form_valid method by:

def form_valid(self, form):
    form.instance.field_2 = # Put value here
    return super(YourCreateView, self).form_valid(form)
like image 8
Piyush Maurya Avatar answered Nov 10 '22 06:11

Piyush Maurya


I would override either ModelForm.save() or the models save(). You should push your logic as far back towards models as possible. If you're only going to create instances of this model without MyField_2, then you should override the models save(). This follows the encapsolation practice of object oriented programming which, when done correctly is quite a beautiful thing.

class MyModelForm(forms.ModelForm):
    model = MyModel
    fields = ["field_1"]
    # no changes needed in form because the model itself will handle auto-population of field_2.

class MyModel(models.Model):
    field_1 = models.SomeFieldType(...)
    field_2 = models.SomeFieldType(...)

    def save(self, *args, **kwargs):
        if self.id: # If true, this is being created. If false, this is just being edited and it already exists.
            # auto populate field_2
        else:
            # it's being edited and already exists so I'm guessing we just want this to do the default logic.
            super(MyModel, self).save(*args, **kwargs)

If you really want, you can even pass a variable through the models save methods **kwargs that tells the logic that it's being created by a form. In this case, you do the auto population but if it's not created by a form it could choose not to auto populate field_2

NOTE: I agree with @sarafeim that said you should use underscored names for fields and not camel case.

like image 1
Ian Kirkpatrick Avatar answered Nov 10 '22 06:11

Ian Kirkpatrick