Monday, April 16, 2018

django url tag not being called

Leave a Comment

I have a template structure similar to this:

    #X_List.html     <div class="row">         {% include './X_List_Table.html' %}     </div>     <div id="confirm" class="modal fade" tabindex="-1" role="dialog" aria-labelledby="testmodal" aria-hidden="true">     <div class="modal-dialog modal-sm" role="document">         <div class="modal-content"></div>     </div> </div>      #X_List_Table.html     <table>       <thead>         <tr>           <th>Desc</th>           <th>Activate</th>         </tr>       </thead>       <tbody>         {% for item in x_list %}           <tr>             <td>{{ item.id }}</td>             <td><a data-toggle="modal" href="{% url 'x:x_quantity' item.id %}" data-target="#confirm">Click me</a></td>           </tr>         {% endfor %}           </tbody>     </table> 

My view is defined as:

#views.py def x_quantity(request, id):   return render(request, 'modal.html', {'quantity': X.objects.filter(pk=id).count()} 

and the modal.html:

<div class="modal-header">     <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>     <h3>Attention</h3> </div> <div class="modal-body">     <p>The number of elements is {{ quantity }}</p> </div> <div class="modal-footer"></div> 

The problem is:

Supposing that I have 2 elements in the table, their urls would be:

  • 'x/x_quantity/1'
  • 'x/x_quantity/2'

Consider that for these elements:

  • One returns a QuerySet with atleast 1 element
  • One returns an empty QuerySet

When I click on the link, it should run the view, get the quantity based on the id of the element, return it as a context variable to the modal so it can be displayed.

The problem is:

When I click on a link, the view is being called with the id of the element, which can be confirmed by looking at the server shell [06/Apr/2018 17:00:23] "GET /x/x_quantity/1 HTTP/1.1" 200 898.

If I click on the other element, THE VIEW IS NOT BEING CALLED, there is no request going out.

What I intend to do is to display a modal with the quantity of the element clicked.

Is this a confusion on my part regarding how the {% url 'app:app_view' var %} should behave on a href or I'm not supposed to do this and should, instead, use AJAX?

Perhaps this is related with "refreshing" context variables as well?

2 Answers

Answers 1

The explanation for the behavior you are seeing can be found in the Bootstap documentation:

If a remote URL is provided, content will be loaded one time via jQuery's load method and injected into the .modal-content div. If you're using the data-api, you may alternatively use the href attribute to specify the remote source. An example of this is shown below:

If you want to use the same modal to load different content, you have to use Ajax.

A (quite ugly) workaround would be to render a modal for each item in x_list. Just be aware that the value doesn't get updated if you open the same modal twice.

Answers 2

Let me first clarify that before this example I have never used Bootstrap. I found your question interesting so I played a little bit with Bootstrap CDN. Also I do not use a lot of Javascript so everyone feel free to correct any bad practices.

I think what you want is doable using AJAX so here is my solution:

I changed a link to a button because all the modal examples had buttons not links :)

#X_List.html <table>   <thead>     <tr>       <th>Desc</th>       <th>Activate</th>     </tr>   </thead>   <tbody>     {% for x in x_list %}       <tr>         <td>{{ x.id }}</td>         <td><button id="{{ x.id }}" type="button" class="btn btn-info modal-btn">Click me</button></td>       </tr>     {% endfor %}   </tbody> </table>  <!-- Modal --> <div id="myModal" class="modal fade" role="dialog">   <div class="modal-dialog">     <!-- Modal content-->     <div class="modal-content">       <div class="modal-header">         <h4 class="modal-title"></h4>         <button type="button" class="close" data-dismiss="modal">&times;      </button>       </div>       <div class="modal-body"></div>       <div class="modal-footer">         <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>       </div>     </div>   </div> </div> 

Javascript (you will need js-cookie - I used CDN) passes the id to the server side and then shows received quantity at the end in a modal.

$(document).ready(function() {      $(".modal-btn").click(function(event) {         var x_id = $(event.target).attr('id');          $.ajax({             url : "/ajaxquantity/",             type : "POST",             dataType: "json",             data : {                 x_id : x_id,                 csrfmiddlewaretoken: Cookies.get('csrftoken')             },             success : function(json) {                 var quantity = json.quantity;                 $(".modal-title").text('Id: ' + x_id);                 $(".modal-body").text('Quantity: ' + quantity);                 $('#myModal').modal('show');             },             error : function(xhr,errmsg,err) {                 alert(xhr.status + ": " + xhr.responseText);             }         });         return false;     }); }); 

Then you need to add this line into urlpatterns list:

url(r'^ajaxquantity/$', views.ajaxquantity, name='ajaxquantity') 

And finally the server side. I do not know how your model looks like so here I used your query from the question.

# views.py def ajaxquantity(request):     if "x_id" in request.POST:         response_dict = {}         x_id = request.POST.get('x_id')         quantity = X.objects.filter(pk=id).count()         response_dict.update({'quantity': quantity})         return JsonResponse(response_dict)      else:         return render(request, 'yourapp/X_List.html') 

So this worked for me (with a little different QuerySet). It is very important that Jquery is only defined once!!!

Keep in mind that this is a minimal working example.

If You Enjoyed This, Take 5 Seconds To Share It

0 comments:

Post a Comment