Skip to content

Create Storage

In this video, we are going to learn about generic Create View.

Generic CreateView is a class-based view that provides a pre-built implementation for creating new objects and saving them to the database. It simplifies the process of handling form submission and object creation in Django.

In this video, we are going to write a Create View api for Storage model.

Resources:

View

At first open your views.py of center and then create a class named "CreateStorage".

class CreateStorage(generic.CreateView):

This class will inherits generic.CreateView.

Now, we need to specify which model we are using to perform Create operation.

    model = Storage

After that, we need to specify form_class.

    form_class = StorageForm

Since, we haven't created this form, so, open forms.py file of center to write this form.

class StorageForm(ModelForm):
    class Meta:
        model = Storage
        fields = "__all__"

In this way, we have wrote StorageForm.

Now, import this form in the views.py.

from center.forms import CenterForm, StorageForm

After specifying form class, we need to specify the template name for this View.

    template_name = "storage/storage-create.html"

Now, create an html file in the storage folder having name "storage-create.html".

Templates

In the html file, we will include the form.html component which we have created in the previous section of videos.

{% include "components/form.html" with form_name="Create Storage" %}

URL

Now, we need to setup url for this view.

In the urls.py of center, add a new path.

path("<int:center_id>/storage/create/", views.CreateStorage.as_view(), name="create-storage"),

We need to use this url in the storage-list.html file. So, open it.

<a href="{% url 'center:create-storage' center_id %}"><i class="fas fa-plus"></i> Create Storage</a>

Since, our url needs center_id, so we need to pass center_id to this storage-list template. Therefore, open the StorageList view and then lets add context data to this view.

def get_context_data(self, **kwargs):
    # At first, grab the context data from the super() method
    context = super().get_context_data(**kwargs)
    # Now, add center_id to the context data
    context["center_id"] = self.kwargs["center_id"]
    return context

[Run the development server and see the changes.]

Modifying Queryset for Center

Currently, you can see all the center in the center dropdown. But we already know the center_id for which we are creating the storage. Therefore, lets utilize the center_id to modify the dropdown items for center and show only that center on which we are working.

Now, In order to modify the dropdown items for center and apply filter on the queryset for that dropdown, you need to pass additional data to the form and that additional data is center_id.

That means we will pass center_id to the form and modify the dropdown queryset for center using the center_id.

So, to pass additional data to the form, you need to override get_form_kwargs method.

def get_form_kwargs(self):
    # At first, grab the kwargs from the super() method
    kwargs = super().get_form_kwargs()
    # Now, add the center_id in the kwargs
    kwargs["center_id"] = self.kwargs["center_id"]
    return kwargs

Now, we are passing the center_id to the form so that we can modify the queryset for the dropdown of center. But we also need to modify our form in order to use that center_id.

So, we will modify the way our form is being initialized.

def __init__(self, center_id, *args, **kwargs):
    # At first initialize the constructor of this form.
    super(StorageForm, self).__init__(*args, **kwargs)
    # Now lets apply filter on the center field.
    self.fields["center"].queryset = Center.objects.filter(id=center_id)

[Run the development server and see the changes.]

Setting initial for center

Now, in the dropdown list for center, you can see only one option. But this option is not selected by default. I want a feature where this center_id which we have filtered out, should be selected by default.

To make this possible, we need to override get_initial method.

def get_initial(self):
    # Grab the initial data from the super() method
    initial = super().get_initial()
    # Now add initial for our center field in the form
    initial["center"] = Center.objects.get(id=self.kwargs["center_id"])
    return initial

Now, if you refresh the page, the center field value is set by default. It is because we are setting the initial value for the Center by overriding the get_initial method.

Making Fields Read Only

Now, you can notice that, there are two fields which we don't need to show to the user. The first field is center. Because user already knows the center on which they are creating storage and we already have applied filter on the center option list. So techically, user doesn't need to manipulate the center field. It is being handled from our backend code. So, we will make the center field as read only.

Similarly, the booked_quantity field should also be read only. Beacause, this field value increment only if patient performs registration. So, this field is not going to be manipulated directly by the user who is creating this storage. So, lets make this field read only.

To make any form field, read only, open your form.py file.

self.fields["center"].disabled = True
self.fields["booked_quantity"].disabled = True

In this way, we have made the center and booked_quantity fields read only.

Now, let us also add form-control class to every form fields. This is just a bootstrap class to make our form, look more better.

for visible in self.visible_fields():
    visible.field.widget.attrs["class"] = "form-control"

Setting Success URL

Now, one last thing is remaining in this CreateView class and it is sucess URL. Whenever you create any data using generic CreateView, you need to specify the url on which django will redirect the user once the object creation is successful.

So, to add success url, we need to override the get_success_url method.

def get_success_url(self):
    # Instead of hard-coding the url, we will use reverse method
    from django.urls import reverse # import at the top of file.
    return reverse("center:storage-list", kwargs={"center_id": self.kwargs["center_id"]})

Template Modification

Finally, we have created our storage create feature using generic CreateView. Now, its time to modify the template of our storage create page.

I have attached storage-create.html file in the resources section. Download it, copy its content and paste it in the html file.

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

{% block title %}
    <title>Create Storage</title>
{% endblock title %} 

{% block content %}
<div class="m-2 p-2">
  <h4 class="mb-3">Fill the following details to create a new storage</h4>
  {% include "components/form.html" with form_name="Create Storage" %}
</div>
{% endblock content %}

Now, our create storage page looks much more better.

In this way, we have learnt how to perform create operation using generic CreateView for any given model.