django url tag not being called - django

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">×</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?

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.

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">× </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.

Related

Search Box results within Modal

I am trying to build some search functionality within a modal. When a user clicks a button it will open a modal with a search box. I then want the results of the search to be shown within the same modal?
<div class="modal" id="select2modal">
<div class="modal-dialog" role="document">
<div class="modal-content modal-content-demo">
<div class="modal-header">
<h6 class="modal-title">Search for product to add</h6><button aria-label="Close" class="close" data-dismiss="modal" type="button"><span aria-hidden="true">×</span></button>
</div>
<div class="modal-body">
<h6>product Search</h6>
<div class="card-body pb-2">
<form method=POST action="{% url 'searchproduct' %}">
{% csrf_token %}
<div class="input-group mb-2">
<input type="text" class="form-control border-right-0 pl-3" name="search" placeholder="Enter product Name" value="">
<span class="input-group-append">
<button class="btn ripple btn-primary" type="submit"><i class="fa fa-search"></i></button>
</span>
</div>
</form>
</div>
</div>
<div class="modal-footer">
<button class="btn ripple btn-primary" type="button">Add product</button>
<button class="btn ripple btn-secondary" data-dismiss="modal" type="button">Close</button>
</div>
</div>
</div>
</div>
view
def search_product(request):
searched = request.POST['searched']
return render(request, 'index.html',{'searched':searched})
I don't think i should be doing return render(request, 'index.html',{'searched':searched}) think I should just be returning searched
The problem is this relies on the page being refreshed that closes the modal.
So what is the correct way - Do I need to use JavaScript or something.
UPDATE:
I have added jquery now
<script type="text/javascript">
$(document).on('submit','#post-form', function(e){
e.preventDefault();
$.ajax({
type:'POST',
url: '/searchproduct',
data:{
searched:$('#search').val(),
csrfmiddlewaretoken:$('input[name=csrfmiddlewaretoken]').val(),
},
success: function (){
}
});
});
</script>
Which seems is doing a POST and returning 200 but the data returned data isn't being shown in the modal.
def search_product(request):
searched = request.POST['searched']
returned_products = Product.objects.filter(product_name__contains=searched)
return {'searched':searched,'returned_products':returned_products}
and then within my modal i am using:
{% for t in returned_products %}
{{t.product_name}}
{% endfor %}
UPDATE 17/02
I think i have made some progress, but i still not getting the results back within the modal, but my search is returning a 200 rather than a error now.
In my AJAX:
<script type="text/javascript">
$(document).on('submit','#post-form', function(e){
e.preventDefault();
$.ajax({
type:'POST',
url: '/searchproducts',
data:{
searched:$('#search').val(),
csrfmiddlewaretoken:$('input[name=csrfmiddlewaretoken]').val(),
},
success: function (data){
$('jresponse').html(returned_products);
}
});
});
I'm returning returned_products and within my modal I have
<div id="jresponse">
{{ returned_products }}
</div>
```
My view
```
def products(request):
searched = request.POST['searched']
returned_products = Product.objects.filter(product_name__contains=searched).values()
return JsonResponse({"returned_products":list(returned_products)})
```
I think the best way to approach this is to use JavaScript and Ajax calls in your frontend/template and HTTP responses with JSON data in your view/backend. You would not do a form submit but instead POST HTTP calls via Ajax to your view (which most likely would be triggered by the button you already have in place). Your view would then respond with a HTTP response which has to be interpreted and incorporated again by JavaScript in your frontend. A good way to structure your response is using JSON format, which can be easily interpreted using JavaScript. Django Rest Framework can make this easier for bigger projects, but it might be good enough to build the JSON responses more or less manually at small projects.

Showing list of items including item details on same page in Django

In a Django v3.x app I would like to display a list of uploaded file names (e.g. images) in the left hand side of the screen. When a user clicks on one of those, I'd like to display the actual file/image on the right hand side of the screen. I am still new to Django and have used both ListView and DetailView separately, but not in such a combination. I'm not sure how this can be achieved.
Using a little Bootstrap magic, I can create a split screen easily. Hence, my template would look somehow like this:
<div class="row">
<div class="col-md-5 left">
{% for image in images %}
<div class="card">
<h4>{{ image.url }}</h4>
View
</div>
{% endfor %}
</div>
<div class="col-md-5 right">
{# TODO: When the user clicks on the View url above, then I'd
like to load the actual image here on the right hand side of the
screen inside this div-tag. #}
</div>
</div>
Question 1: How can I achieve loading a selected image from a list? Can I still use ListView and DetailView, or do I need to write my own View logic?
Question 2: Ideally, I'd like to NOT re-send the whole page from the server to the client, because the list of images in the lefthand-side could potentially be long and require pagination. So, when the user clicks View, then, ideally, I'd like to load only the document from the server. Is this somehow feasible?
Well I have made a sample code and you can refer to it and get some idea.
<!--Carousel Wrapper-->
<div id="carousel-thumb" class="carousel slide carousel-fade carousel-thumbnails"
data-ride="carousel">
<!--Slides-->
<div class="row">
<div class="col-lg-8">
<div class="carousel-inner" role="listbox">
{% for latest in latest_course %}
<div class="carousel-item {% if forloop.counter0 == 0 %}active{% endif %}">
<img class="d-block w-100" src="{{latest.poster.url}}" alt="First slide">
</div>
{% endfor %}
</div>
</div>
<!--/.Slides-->
<div class="col-lg-4">
<ol class="slider_list">
{% for latest in latest_course %}
<li data-target="#carousel-thumb" data-slide-to="{{forloop.counter0}}"
class="active"> <img class="img-thumbnail" width="100px" height=100px src="
{{latest.poster.url}}"
class="img-fluid"></li>
{% endfor %}
</ol>
</div>
and the output looks like this
Here, you can see the list on the right side and when you select an item the selected item loads in the left side. This way you can style your template the way you want.
basically you want to show the selected item from the list on the other side like a slideshow

unable to retrive data in crud operation

{%for x in read%}
{%if request.user == user%}
<div class="card " >
<h5>
<div class="card-header bg-info">
Dr.{{i.name}}
</div>
</h5>
<div class="card-body">
<h6 class="card-title ">Appointment Date : {{x.appoinment_date}}</h6>
<h6 class="card-title">Age : {{x.age}}</h6>
<h6 class="card-title">Digree : {{x.disease}}</h6>
<h6 class="card-title">Email : {{x.email}}</h6>
</div>
</div>
{%endif%}
{%endfor%}
i am using code above but i am getting data of all users instead of current user
I'm not familiar with your application, but it seems like the if-statement relates to some variable 'user', while in the table everything relates to 'x.something'. If what you're trying to do is filter for rows that are only related to the current user, you may want to check
{%if request.user == x.user%}

Submitting button inside a form selenium + python

I have this form which contains a button with some dynamic value, when I click on it it should add the product to the checkout page.
Here is the html form :
{%for p in product %}
<div class="single-product">
<div class="product-f-image">
<img src="data:image/png;base64,{{p.image_medium}}" alt="">
<div class="">
{% if not user.is_authenticated %}
<form action="/login/">
<button class="add-to-cart-link" type="submit"> Add to cart</button>
</form>
{%else%}
<form id="form-id" action="" method="POST">
{% csrf_token %}
<button class="add-to-cart-link" type="submit" name="product" value="{{p.id}}" >
<input type="hidden" name="product_name" value="{{p.name}}">
<input type="hidden" name="product_price" value="{{p.lst_price}}">
Add to cart</button>
</form>
{%endif%}
<i class="fa fa-link"></i> See details
</div>
</div>
<h2>{{p.id}}</h2>
<div class="product-carousel-price">
<ins>{{p.lst_price}} €</ins>
</div>
</div>
{%endfor%}
And here is my what I am doing with selenium:
bon_commande = self.selenium.find_element_by_xpath("//button[#name='product' and #value='37']/parent::form")
bon_commande.submit()
And thanks for the help !
You don't need to locate Submit button to submit a form - use any element inside form or form element itself:
self.selenium.find_element_by_id("form-id").submit()
self.selenium.find_element_by_class_name("add-to-cart-link").submit()
Update
Try to wait until django variable "{{p.id}}" is replaced with generated value:
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
WebDriverWait(self.selenium, 10).until(EC.presence_of_element_located((By.XPATH, "//button[#name='product' and #value='37']"))).submit()
Change to click the submit button:
// add some sleep to wait the JS files of page
// load completely to register click event to the submit button
// otherwise nothing to response to the click
// (because the `action` of the form is empty.)
self.selenium.sleep(15); // sleep 15 seconds
self.selenium.find_element_by_xpath("//button[#name='product' and #value='37']").click()
To click on the button with text as Add to cart you can use the following line of code :
self.selenium.find_element_by_xpath("//form[#id='form-id']/button[#class='add-to-cart-link' and #name='product']").submit()
#or
self.selenium.find_element_by_xpath("//form[#id='form-id']/button[#class='add-to-cart-link' and #name='product']").click()

double-submit issue in browsers - Bootstrap + Django

I have Bootstrap modal window for updating data everytime I close it, I face the so-called double-submission problem. That is, if I press F5, a message pops up telling me that I'm going to submit the same data for the second time and it inserts records into my table if I press ok. Moreover, if I try to open the modal window for the second time, it is rendered incorrectly ! Does it have anything to do with Django somehow ?
The modal window:
<form class="modal fade" id="openTaskWindow" tabindex="-1" role="dialog" aria-labelledby="exampleModalLabel" method="post">{% csrf_token %}
<div class="modal-dialog modal-lg form-horizontal" role="form">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
<h4 class="modal-title" id="exampleModalLabel">Новая задача</h4>
</div>
<div class="modal-body" style="font-size: smaller">
{{ createTask_form.as_p}}
</div>
<div class="modal-footer">
<input class="btn btn-default btn-sm" type="submit" value="Сохранить"/>
</div>
</div>
</div>
</form>
The button that calls the window:
<div><button type="button" data-toggle="modal" data-target="#openTaskWindow" data-backdrop="static" data-keyboard="false">Launch my modal</button></div>
The view (that is called when submit button of the modal window is pressed):
def createTask(request):
taskTable = Tasks.objects.all()
if request.method == 'POST':
task_form = TaskForm(request.POST)
if task_form.is_valid():
temp_form = task_form.save(commit=False)
temp_form.is_important = 0
temp_form.save()
return render_to_response('task_management/task_list.html',{'createTask_form':temp_form, 'taskTable': taskTable},context_instance=RequestContext(request))
else:
task_form = TaskForm()
return render_to_response('task_management/task_list.html',{'createTask_form':task_form, 'taskTable': taskTable, 'task_id':''},context_instance=RequestContext(request))
After reading discussions of the community, I tried to do this:
$('#openTaskWindow').submit(function() {
location.href = location.href;
});
but it did not help. Any ideas?
Well, this has not much to do with Django. The browser cache the post request for re-submission. The easiest way to prevent this is to return HttpResponseRedirect when for is valid.
So instead
if task_form.is_valid():
temp_form = task_form.save(commit=False)
temp_form.is_important = 0
temp_form.save()
return render_to_response('task_management/task_list.html',{'createTask_form':temp_form, 'taskTable': taskTable},context_instance=RequestContext(request))
Try to do
if task_form.is_valid():
temp_form = task_form.save(commit=False)
temp_form.is_important = 0
temp_form.save()
return HttpResponseRedirect('your_url')
And if you need to pass some extra arguments to the view you can accomplish that through query string or session based cache. And you don't need your Javascript hack.