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?
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:
lower_case_with_underscores
names for your fields. MyField_1
should have been my_field_1
.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)
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With