Wednesday, 14 July 2021

*Episode 19* PYTHON (Creating items of Django)

 


Working with forms: creating items


This episode covers :-


 1) How to create forms with ModelForm.


  •  Setup :-

Terminal

cp -fr 15-Base-Project 21-Forms-Create

cd 21-Forms-Create

source ../venv/bin/activate


  • Creating the edit form :-

    Create an edit.html file in the myapp templates folder:

Template location

├── myapp

│ ├── templates

│ │ └── myapp

│ │ ├── edit.html # < here

│ │ ├── index.html


      Fill it with these lines:

myapp/templates/myapp/edit.html

{% extends 'base/base.html' %}

{% block content %}

<form action="" method="post">

{% csrf_token %}

<div class="row justify-content-center">

<div class="col-6">

{{ form }}

<hr class="mb-3">

<button class="btn btn-primary btn-lg btn-block" ty\

pe="submit">Submit</button>

</div>

</div>

</form>

{% endblock %}


     We will use this template to create and edit flower items.


  •  Creating the form class :-

     Create forms.py file in the myapp folder:

forms.py location

├── myapp

..

│ ├── admin.py

│ ├── apps.py

│ ├── forms.py # < here


     Fill it with these lines:

myapp/forms.py

from django import forms

from django.forms import ModelForm

from .models import Flower

class MyForm(ModelForm):

title = forms.CharField(label='Title',

widget= forms.TextInput(attrs={'class': 'form-contr\

ol '}))

class Meta:

model = Flower

fields = ['title']


  •  Updating urlpatterns :-

     Edit mysite app urls.py file and add the create path:

mysite/urls.py

urlpatterns = [

path('admin/', admin.site.urls),

path('', myapp_views.index, name='index'),

path('flower/create/', myapp_views.create, name='create\

'), # < here

]


  • Creating the view function :-

    Edit myapp views.py file and add a create view below the index view:

myapp/views.py

from django.shortcuts import render

from .models import Flower

from django.http import HttpResponseRedirect # < here

from .forms import MyForm # < here

def index(request):

...

def create(request): # < here

if request.method == 'POST':

form = MyForm(request.POST)

if form.is_valid():

form.save()

return HttpResponseRedirect('/')

else:

form = MyForm()

return render(request, 'myapp/edit.html', {'form': form\

})


  •  Adding a menu item :-

     Edit base app base.html file and add a menu link to the flower creation form:

base/templates/base/base.html

<ul>

<li><a>Home</a></li>

<li class="nav-item"> <!-- here -->

<a class="nav-link" href="flowercreate/">

Create Flower

</a>

</li>

</ul>


     I removed unimportant CSS classes for the book. The complete markup is available at the GitHub repository.

    Visit flowercreate/ and create a flower:




    The new flower will now show up on the frontpage:



      Note that the bootstrap class card-columns creates a masonry like arrangement, not a grid.


In Details :-


  •  Protecting against cross site request forgeries :-

     In the myapp edit.html file we define a CSRF token:

myapp/templates/myapp/edit.html

<form action="" method="post">

{% csrf_token %} # < here

...

</form>


     This token adds protection against Cross Site Request Forgeries where malicious parties can cause visitor’s browser to make a request to your website. The cookies in the visitor browser make the app think that the request came from an authorized source.


    Use the token only in POST requests. You don’t need it with GET requests. Any request that has a potential to change the system shoud be a POST request. Like when we add flowers to the database.


    GET requests are often used in situations where the system state is not changed, like when we query database with the search form. The q search word parameter is public data we don’t need to hide. You want to be able to share links like this: https://samulinatri.com/search?q=Django.


     Also you shouldn’t use the token with forms that point to external URLS. This introduces a vulnerability as the token is leaked. action="" in the form means that the POST data is sent to the current internal URL (flowercreate/).


  •  Adding form fields :-

     Easiest way to generate HTML markup for the form fields is to use the {{ form }} template variable:

myapp/templates/myapp/edit.html

<div class="col-6">

{{ form }}

</div>


     This will produce the following HTML:

Generated HTML

<div class="col-6">

<label for="id_title">Title:</label>

<input type="text" name="title" maxlength="255" class="\

form-control" required="" id="id_title">

</div>


  •  Using the Form class :-

     Form class represents a form. It describes a form in a similar way the Flower model describes how fields map to database fields. With forms the fields map to HTML elements.


    ModelForm is a helper class that creates that Form class from a Model:

myapp/forms.py

class MyForm(ModelForm):

title = forms.CharField(label='Title',

widget= forms.TextInput(attrs={'class': 'form-contr\

ol '}))

class Meta:

model = Flower

fields = ['title']


     With ModelForm we don’t need to specify the fields again. We already add the fields in the Flower model:

Fields are already specified in the models.py file

class Flower(models.Model):

title = models.CharField(max_length=255, default='')

description = models.TextField(default='')


     This would be enough to create a form to edit all Flower fields:

myapp/forms.py

class MyForm(ModelForm):

class Meta:

model = Flower

fields = '__all__' # < here


     It’s recommended to explicitly specify all the fields like this though:

Fields should be explicitly specified

fields = ['title', 'description']


    Otherwise you could unintentionally expose fields to users when you add them to the model.


    A form field is represented as an HTML “widget” that produces some default markup. We can modify that widget in the form definition:

Adding CSS class for Bootstrap

title = forms.CharField(label='Title',

widget = forms.TextInput(attrs={'class': 'form-cont\

rol '}))


     The only reason we did this is because we wanted to add the form-control CSS class to the title input element. This way we can take advantage of the Bootstrap textual form control styling.

 

  •  Examining the view function :-

     In the myapp views.py file we added the create view function:

myapp/views.py

def create(request):

if request.method == 'POST':

form = MyForm(request.POST)

if form.is_valid():

form.save()

return HttpResponseRedirect('/')

else:

form = MyForm()

return render(request, 'myapp/edit.html', {'form': form\

})


     First we check if the request is POST. If it’s not, we create an empty form that we pass to the edit.html template:

Empty form is passed to the template

if request.method == 'POST':

..

else

form = MyForm()

return render(request, 'myapp/edit.html', {'form': form})


     This is the default scenario when you first visit the flowercreate/ page. We need to create the form object so that the form HTML can be generated using the template tags.


     If the request is POST, we create the form object and populate it with the data from the request:

Populating the form object with the POST data

if request.method == 'POST':

form = MyForm(request.POST)


     Then we check if the form data is valid and save the flower:

Validating and saving the data

if form.is_valid():

form.save()

return HttpResponseRedirect('/')


     Django has built-in validators that it uses internally. For example EmailValidator for email addresses and validate_slug for slugs. If the input doesn’t satisfy the validator, a ValidationError is raised.


     The save() method creates the flower object from the data bound to the form and stores it in the database.


    When we submit a form using a POST request, our create view will instantiate the form object and populate it with the form data from the request. We “bind” the data to the form. It’s now a “bound” form.


    The validated data can be accessed in the form.cleaned_data dictionary:

Accessing validated data

if form.is_valid():

print(form.cleaned_data['title']) # < here

form.save()

return HttpResponseRedirect('/')


    This will print the validated title field data in the terminal:



    And finally HttpResponseRedirect('/') redirects the visitor to the frontpage.

 

Summary :-


  •  Use {% csrf_token %} with internal POST forms to protect against Cross Site Request Forgeries.
  •  {{ form }} template variable generates markup for all form fields.
  •  Form class represents a form. Its fields map to HTML elements.
  •  ModelForm is a helper class that allows us create the Form class from a Django model.
  •  A form field is represented as an HTML “widget”. You can modify this widget in the form definition.
  •  The submitted form is processed in the create view.
  •  Django has built-in validation that triggers a ValidationError when the data doesn’t validate.
  •  validated data is stored in the form.cleaned_data dictionary.
  •  In the create view we bind the form data to the form instance.
  •  form.save() method creates a database object using the bound data.

👈Episode 18(P).                                                                          Episode 20(P)👉
Share This Post

PRINT THIS POST

No comments:

Post a Comment

If you have any doubts. Please let me know.

Featured post

*Episode 1* MCQ for Govt. Job/ Private Job/ MNCs

  Topic:- One Word Substitution 1) Especially skilled in storytelling  Answer:- Raconteur 2) Fear of loneliness Answer:- Eremophobia  3) Usa...