[Django]-How do I create and submit a form from a model inside a modal?

4👍

It’s a bit hard to understand what you want from the beggining. I assume that you want the user to see the products catalog then, when he clicks the update button from a particular product, you need to trigger the modal with a form with correct loaded data from that product.
So I base my answer in this assumption

First change needed, in your products_catalog.html, is from this :

<a class="btn btn-outline-warning" href="{% url "simple_app:edit_product" product.pk %}"><i class="fa fa-pencil-square-o fa-1x" aria-hidden="true"></i></a>

to a button that triggers a function: <button onclick="findMyForm()">Update product</button>

Then you should add that modal snippet to the end of your products_catalog.html, except the launch button. You don’t need that. Also add an empty div inside the modal body <div id='showForm'></div>.

Now the findMyForm function should do three things. Lauch the modal, pick up the correct form from the server and put the form on modal body.

findMyForm(){
//the name myModal should be ID, as jquery notation suggests.
$('#myModal').modal('show');
$.ajax({
    type: 'GET',
    url: '/product/'+{{product.pk}}+'/edit/',
    success: function(res){          
        $(#showForm).html(res)   
    }

})

GET is important here, so the call go into the right if of the view. So this should call your edit_product_view, acording to your url settings, and it should return the form you want. The form is picked up by the success callback on ajax and put inside our empty div in the modal body.

But there is still a big problem. Your view is rendering the template again from scratch, and you don’t want that. So the trick is to use JsonResponse instead of render to avoid reloading (well, it wont work with render anyway). So this part in your view:

return render(request, 'simple_app/edit_product.html', {'form': form})

should turn into (remember to import from django.http import JsonResponse):

return JsonResponse({'form': form})

See that you don’t need edit_product.html any longer. The above procedure builds its content inside the modal dynamically in the product_catalog.html page.

Ok. Now you should be able to push a button in products catalog that will pop a modal with the form revelant to the product without reloading. Let’s say you make changes and want to save (POST part of the view). Pattern is similar:

  • You need a button inside your modal that will trigger a function save_form.
  • Function will pick up new values from the form using jquery (use browser tools to find out what {{form.as_p}} renders to) and make an ajax POST call to '/product/'+{{product.pk}}+'/edit/' passing form data.
  • Save data in your view and render index.html (or return JsonResponse({‘res’:’Your data was saved’}) and use ajax success callback to print that somewhere in your html).

EDIT:

To add a new product in a modal:

  • Change your ProductView to pass an empty form to the products.html template.
  • Minimal products.html is a modal (with default button). In the modal body you should render an empty form {{form.as_p}}. In the modal footer you should change the <input> to a <button> tag and link the button to a js function addNew(). Doing this will prevent default form submission.
  • addNew is like this:

    addNew(){
    
      var data = {
         title: $('#title').val()  //Not sure if title is the correct selector. 
         description: $('#description').val() // get correct id with browser tools.
          ...
      }
      // Ajax calls view. Stringify format your js object to a json string.
      $.ajax({
        type: 'POST',
        url: '/product/new/',
        data:JSON.stringify(data),
        success: function(res){          
            alert(res['msg'])   
        }
    
      })
    
    } 
    

The data formatting is the tricky part. I’m not sure how django forms expects the data to come. You probably have to print this in your view and manipulate before passing default validation functions. Let me know how this goes to you.

  • Last you view is fine. Just change return index(request) to return JsonResponse({'msg':'Data saved'}) to be sure you understand it works.

So your ADD NEW button is the default modal button. You press it and you get modal openned with an pre rendered empty form that comes from your class view. Then you have a ok BUTTON tied to a function. This function collects data from your form and send to server via Ajax, where you save data to your model. You can also send something back from the view (for other use cases) with JsonResponse, which will be picked up by success callback.

Hope this helps!

👤Alex

Leave a comment