38👍
Forms are just a tool to simplify and speed-up (the development of) the process of fetching POST data from the request. A manual way would be to do request.POST.get('somefield')
for all the fields there are in some HTML form. But Django can do better than that…
In its essence, a Form class holds a number of Fields and performs these tasks:
- display HTML inputs,
- collect and validate data when user submits it,
- if fields don’t validate, return the values along with error messages to HTML,
- if all fields validate, provide
form.cleaned_data
dictionary as a convenient way to access these values in view.
With these values, I could then manually create a new instance of a MyModel
and save it. Of course, I would have to define a Field in the Form for every Field in MyModel model.
This means that, basically, I could do something like this:
(forgive me for not testing this code, so I can’t vouch that it’s 100% correct)
models.py:
class MyModel(models.Model):
field1 = models.CharField(max_length=40, blank=False, null=False)
field2 = models.CharField(max_length=60, blank=True, null=True)
forms.py:
class FormForMyModel(forms.Form):
form_field1 = forms.CharField(max_length=40, required=True)
form_field2 = forms.CharField(max_length=60, required=False)
views.py:
def create_a_my_model(request):
if request.method == 'POST':
form = FormForMyModel(request.POST)
if form.is_valid():
my_model = MyModel()
my_model.field1 = form.cleaned_data.get('form_field1', 'default1')
my_model.field2 = form.cleaned_data.get('form_field2', 'default2')
my_model.save()
else:
form = FormForMyModel()
context_data = {'form': form}
return HttpResponse('templtate.html', context_data)
(this could be written with a few lines of code less, but it’s meant to be as clear as possible)
Notice there are no relation between model Fields and form Fields! We have to manually assign values to MyModel instance when creating it.
The above example outlines generic form workflow. It is often needed in complex situations, but not in such a simple one as is this example.
For this example (and a LOT of real-world examples), Django can do better than that…
You can notice two annoying issues in the above example:
- I have to define Fields on
MyModel
and Fields onFormForMyModel
separately. However, there is a lot of similarity between those two groups (types) of Fields, so that’s kind of duplicate work. The similarity grows when adding labels, validators, etc. - creating of
MyModel
instance is a bit silly, having to assign all those values manually.
This is where a ModelForm comes in.
These act basically just like a regular form (actually, they are extended from regular forms), but they can save me some of the work (the two issues I just outlined, of course 🙂 ).
So back to the two issues:
-
Instead of defining a form Field for each model Field, I simply define
model = MyModel
in the theMeta
class. This instructs the Form to automatically generate form Fields from model Fields. -
Model forms have
save
method available. This can be used to create instance of model in one line in the view, instead of manually assigning field-by-field.
So, lets make the example above with a ModelForm
:
models.py:
class MyModel(models.Model):
field1 = models.CharField(max_length=40, blank=False, null=False)
field2 = models.CharField(max_length=60, blank=True, null=True)
forms.py:
class MyModelForm(forms.ModelForm): # extending ModelForm, not Form as before
class Meta:
model = MyModel
views.py:
def create_a_my_model(request):
if request.method == 'POST':
form = MyModelForm(request.POST)
if form.is_valid():
# save the model to database, directly from the form:
my_model = form.save() # reference to my_model is often not needed at all, a simple form.save() is ok
# alternatively:
# my_model = form.save(commit=False) # create model, but don't save to database
# my.model.something = whatever # if I need to do something before saving it
# my.model.save()
else:
form = MyModelForm()
context_data = {'form': form}
return HttpResponse('templtate.html', context_data)
Hope this clears up the usage of Django forms a bit.
Just one more note – it is perfectly ok to define form Fields on a ModelForm
. These will not be used in form.save()
but can still be access with form.cleaned_data
just as in a regular Form.
2👍
Have you tried working with ModelForms before? As I understand, you’re looking to create a form based on the model you created right?
Lets say your model is called Temp. You can create a form that correlates with this model (and your question) like this:
forms.py
from django.forms import ModelForm
class TempForm(ModelForm):
class Meta:
model = Temp
The ModelForm will automatically map the selections/choices from your model to a form version.
If you plan on using this in a template later, doing something like this will automatically create a drop-down menu with choices:
<form>
<label for="id_size">Size</label>
{{ form.size }}
</form>
Hope that answers your question!
- Django CSRF when backend and frontend are separated
- Django how to reconnect after DatabaseError: query timeout
- Foreign Key to User model
- Passing an object created with SubFactory and LazyAttribute to a RelatedFactory in factory_boy
1👍
Simply use CharField in your modelform as below:
SIZES_CHOICES = (
('size1', 'M'),
('size2', 'L'),
)
size = models.CharField(max_length=100, choices=SIZES_CHOICES, default=size1)
in the above code, size1 is the value which will be going to store in your database as name ‘size1’ and in the drop-down menu, there will be an option is ‘M’ of right side.you can mentioned any name to these options.
- Using django models across apps?
- Nullable TextField or empty string in Django model?
- Get a list of python packages used by a Django Project