Django makes creating forms for entering data extremely easy. We will go through each of these steps:
- Add forms to the forms.py file
- Add a view for each form
- Add the forms to the urls.py
- Create templates for the forms
- Add the hyperlinks to the forms in the base.html file
- Run the server and test the forms
- Generate test in tests.py for the forms
Add forms to forms.py
Forms are defined in a forms.py file. This file is not added by default when you create the app. Right click on the app directory and add a file. It must be named "forms.py." The first thing to do in this new file is to import forms and your models:
from django import forms from .models import Product, ProductType, Review
The forms themselves are defined as classes. The classes inherit from classes in forms. We are going to use the simplest form of form, a ModelForm. The class has a subclass Meta, much like the Models did. In it we need to define only two things: what model we are using, and what fields from the model we wish to include. Here is the code for the first form.
class ProductForm(forms.ModelForm): class Meta: model=Product fields='__all__'_'
As you can see our model is "Product" and we are going to use all the fields.
It is possible to create much more complex form definitions, but we will stick with simplicity for now.
Create a view for the form
The view for the form is a bit more complex than the form definition itself. The view must account for the POST data and save it to the database. That said, it is still remarkably simple compared to similar functions in other languages. A lot happens underneath by "magic."
Before we write our view we need to import the form from forms.py.
from .forms import ProductForm
Here is the view function for the form. I will discuss each line afterwards.
def newProduct(request): form=ProductForm if request.method=='POST': form=ProductForm(request.POST) if form.is_valid(): post=form.save(commit=True) post.save() form=ProductForm() else: form=ProductForm() return render(request, 'techapp/newproduct.html', {'form': form})
The first line of the function is just like all the other views so far. It receives the "request" from the server.
In the second line we establish which form from forms.py this view is addressing. Next it checks to see if the form method is POST. (It could also be GET.) If it is POST and if the form is valid, then it will commit the post and save it to the database.
After the save, it returns to the empty form, ready for another entry.
If the method is not POST, or if the form is not valid, django returns an empty form. This is important in that the first time you go to the form it should be empty. There is nothing to POST yet.
As always, we return the request, the name of the html file and the context. In this case "form" is the context.
Add the Form to urls.py
There is nothing special about the url for a form view. It looks just like all the others.
urlpatterns=[ path('', views.index, name='index'), path('gettypes/', views.gettypes, name='types'), path('getproducts/', views.getproducts, name='products'), path('productdetails/<int:id>', views.productdetails, name='productdetails'), path('newProduct/', views.newProduct, name='newproduct'), ]
The Form template
The template for the form is also quite simple. I will show the code and then talk through the parts.
{% extends 'base.html' %} {% block content %} <h2>Add Product</h2> <form method='POST' class="post-form"> <table class='table'> {% csrf_token %} {{ form.as_table }} </table> <button type="submit" class="save btn btn-default"> Save </button> </form> {% endblock %}
The overall body is the same as all our templates. It extends base.html and sets the block content.
I added a heading to let the user know what the form is for. You could also add instructions if needed.
We start the form and set its Method to POST. This is just HTML. The class is a bootstrap class to apply some css to the form .
To house the form we create a table. There are other ways to set the form up. You can do it as a list or as paragraph tags.
The crsf_token is a security check to make sure the request is legitimate.
Form.as_table is one of Django's built in template for forms. It makes it remarkably easy. It will provide the field names and the appropriate text boxes. You can customize the form. The context we passed has all the fields. You can access them each individually and set the kind of control you want for them, but we are going to take the easy way.
After the table, but before we close the form tags, we add the submit button.
Add the hyperlink to base.html
The last thing to do before we can do a test run of the form is to add a hyperlink to the form so that it appears on the menu.
<ul class="nav navbar-nav"> <li><a href="{% url 'types' %}">Product Types</a></li> <li><a href="{% url 'products' %}">Products</a></li> <li><a href="{% url 'newproduct' %}">Add Product</a></li> </ul>
Run the server and test the forms
Make sure everything is saved, the run the server. Correct any errors and save again. Here is the empty Product FORM
We will add some data.
Now we will save and then check the products page to see if it was added. It is there.
An if we check the details, by clicking on the product name. . .
Generate Unit tests for forms
I am going to create a simpler form to demonstrate testing. The product form has two foreign keys, which requires creating the related objects before creating the test forms. For now I am going to create a ProductTypeForm to show the tests at their most simple. In forms.py I add this form:
class ProductTypeForm(forms.ModelForm): class Meta: model=ProductType fields='__all__'
Save the forms.py file. I am not going to bother creating the view for the form or a template. We can test the form definition directly. (However if you want to make this a more complete app, you should create the view and template for this form and one for Reviews.)
The first test I add to our tests is one to test that the form is valid with all its fields entered.
#Form tests class ProductType_Form_Test(TestCase): def test_typeform_is_valid(self): form=ProductTypeForm(data={'typename': "type1", 'typedescription' : "some type"}) self.assertTrue(form.is_valid())
We enter sample data for the fields and then assert it is true that the form is valid. Test this. It should pass.
The second test asserts that the form is still valid when we leave out the optional description field.
def test_typeform_minus_descript(self): form=ProductTypeForm(data={'typename': "type1"}) self.assertTrue(form.is_valid())
Our final test for this simple form is to assert that the form will fail if we don't enter anything at all
def test_typeform_empty(self): form=ProductTypeForm(data={'typename': ""}) self.assertFalse(form.is_valid())
This gives some idea of form testing.
No comments:
Post a Comment