how to send a model id while using javascript in django - python

I'm trying to delete a model instance when clicked on a button but before that i want to show a confirm box using JS, if the confirm box results true then i want to head over to the view to delete the instance also passing the instance id.
Here Django is showing an Error
NoReverseMatch at /profile/myprojects
Reverse for 'project_delete' with arguments '('',)' not found.
This is my button
<button onclick="delFunction()" class="btn btn-danger btn-sm">Delete
Project</button>
This is the JS code
function delFunction() {
var txt;
if (confirm("Are you sure you want to delete the project?")) {
window.location.href = "{% url 'project_delete' project.id %}";
}
}

Related

Django with ajax Request

I have below code
function OpenModal()
{
var fname="Quartz";
var mname="Rohit";
var lname="Patel";
var url="{% url 'display_modal' %}"+fname +"/"+mname+"/"+lname;
alert(url);
xmlhttp = new XMLHttpRequest();
xmlhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
document.getElementById('divcontent').innerHTML=this.responseText;
}
};
xmlhttp.open("GET",url,true);
xmlhttp.send();
}
How to execute the above code on click of a button in django templating language.
url is like
path('member/search/',
views.displayModalView, name="display_modal"),
What ajax does it will prevent a page from reload, this is the magic of ajax. So if you are providing path, this can be use for page reload.
Html:
<script>
function OpenModal(){
var fname="Quartz";
var mname="Rohit";
var lname="Patel";
$.ajax({
type:'POST',
url: "{% url 'display_modal' %}",
data: { csrfmiddlewaretoken: '{{ csrf_token }}'},
success: function(param123){
dict1 = JSON.parse(param123);
let data1 = dict1.test;
alert("Successful call do what ever you want");
alert(data1);
},
error: function(){
alert("sorry");
}
});
}
</script>
urls.py:
what url does it will match the regex with your mentioned url.
the name='display_modal' parameter and the url: "{% url 'display_modal' %}" that you are mentioning in ajax call would be same.
from django.conf.urls import url
urlpatterns = [
url(r'^display_modal', views.displayModalView, name='display_modal')
]
views.py:
import json
from django.http import HttpResponse
def displayModalView(request):
#do what ever you want but at the end return Httpresponse with dictionary if you want
to use dictionary in your ajax call.
param123 = {'test': "Hello_world"}
return HttpResponse(json.dumps(param123))
I think you can use a jQuery Ajax request inside a normal click() method, like descripted here: W3C Documentation
In this case, however, I think you have to declare the url as TemplateAsView, so you can tell Django to immediatly return a template instead of execute a Django view, as described in doc. In the template you can execute the function, as you wish, for example in the template you can insert a call to your function on document ready, and execute when the DOM is loaded, as described here.
To do this you have to change the url, because a view.someView in made to search, inside your view.py, the someView function declaration, but your function is a Javascript so, I presume, you put it inside the template code.
I see that your code is a Javascript function, so I try to figure why you have to call a function like this with Django template system, as a template call, and you can't call the function directly. I think that doing as you want you force a DOM reload everytime and, I think, there are several method to open a modal without a page refresh.
You can add onclick to your button and the value of that should equal to your function
like this
<button onclick='show()' something else ... ></button>
------------------------------ javascript--------------------------------------------------
function show(){
something else ...
}
you can also see jquery documentation

How to load Django ListView via Ajax

Basically code works as I expected, but my ListView is not refreshing. Everything works fine, but template does not load itself, I must push reload button (all data are loaded correctly then).
I done simple form/input for testing and there is no problem with views. My project requires calendar widget for picking months, and simplest way to do this I found on the internet was Ajax approach.
Ajax function:
$(document).ready(function () {
$(function () {
$("#datetimepicker1").datetimepicker({
viewMode: 'months',
format: 'MM/YYYY',
}).on('dp.change', function (e) {
var url = "/booking/update_months/{{hotel_id}}";
$.ajax({
type: 'GET',
url: url,
dataType: 'json',
data: {
month: e.date.month(),
},
success: function (data) {
},
error: function (data) {
}
});
})
});
});
Url "/booking/update_months/{{hotel_id}}" refers to first View function I'm using for this functionality:
#csrf_exempt
def update_months(request, hotel_id):
if request.GET.get('month'):
month = request.GET.get('month')
request.session['month'] = int(month) + 1
return HttpResponseRedirect(reverse('booking:hotel_statistics', args=(hotel_id,)))
else:
return render_to_response(request, 'booking/hotel_statistics.html')
Then in HotelStatistics ListView I'm doing some stuff in get_context_data function, nothing special here. Just by some "prints" I've tested that the code is being executed until the end of the class.
class HotelStatistics(ListView):
model = Reservation
context_object_name = 'reservations'
template_name = 'booking/hotel_statistics.html'
def get_context_data(self, **kwargs):
.
.
.
return context
I'm pretty sure that I'm missing something with Ajax functionality, It's my first approach to this language. Thanks in advance for your help.
Why are you using AJAX here? Unless I am missing something, you should just have the date picker inside an HTTP GET form that is submitted.
template.html
<!-- The action attribute hardcoded URL value should be replaced with a Django url templatetag. This will allow the url to be resolved based on the router configuration. i.e. {% url "booking:update_months" hotel_id %} -->
<form action="/booking/update_months/{{ hotel_id }}" method="GET">
<input id="date" name="date">
<button type="submit">Update</button>
</form>
<script>
$(document).ready(function() {
$("#date").datetimepicker({
viewMode: 'months',
format: 'yyyy-mm-dd',
});
});
</script>
view.py
#csrf_exempt
def update_months(request, hotel_id):
date = request.GET.get("date")
if date:
request.session["month"] = datetime.strptime(date, "%Y-%m-%d").month
return redirect("booking:hotel_statistics", False, hotel_id)
return render(request, "booking/hotel_statistics.html")
The code above submits an HTTP GET form, resulting in a server side 301 and therefore a "refresh" of your statistics page with the update session data.
Notice, we are sending up the full date information. I am not sure if you are doing this separately, but if you are allowing users to update each date part independent, you could now bring that together into a single update_date function.

Create a Flask Search Bar that Inserts URI Variable with url_for()

I have a Flask site that has a 'search bar' where you type in the location ID of a particular location and then click Submit to be taken to the page for that location, if it exists. Here's the current form action:
<form id="locationinfo" action="{{ url_for('location') }}">
When you click Submit you are taken to /location?info=SITEID and that works just fine. What I want to do is change this behavior slightly so that when a user clicks Submit they are taken to /location/SITEID/ instead. I have the decorator set up in my main Flask routes file, but I'm struggling to put the pieces together to get this simple form together.
#app.route("/location/<locationid>/")
def locations(locationid):
...
return locationid
Any direction would be greatly appreciated!
[Edit with current full form code]
#app.route("/location")
def location():
location_id = request.args.get("info")
<form id="info" action="{{ url_for('location') }}">
<input type="text" name="info" id="locationfield">
<button type="submit">Go!</button>
</form>
You can't change how HTML forms submit their fields, they will always be in the query string or body (POST). One option is to use JavaScript to override the submit event to perform your own submit and re-render with the results.
A simpler solution is to redirect to the nice url after submit. This keeps the "search" action separate from the "show" action (even if they are handled by the same view).
#app.route('/location/')
#app.route('/location/<int:id>/')
def location(id=None):
# redirect to the second form if the id wasn't in the path
# raises 400 error if id wasn't in the query
if id is None:
return redirect(url_for('location', id=request.args['info']))
# id is in the path, continue
...
You can expand this later if you want to search by something besides id. Perform the search then redirect to the found id.

How can Ajax work with a dynamic Django dropdown list?

I'm making this little web app that takes 2 addresses, calculates the distance using google maps, and calculates the gas cost based on the vehicles mpg rating. Everything is complete except for this last part that I believe would work best with AJAX.
I have 3 lists (year, make, model), and I need the list of car models to be restricted based on the year and make of the car. After selecting, I have a button that once clicked, will verify if it is a valid vehicle in the database and pull the vehicle's mpg rating to do some basic math on it.
The problem is I don't really know how to approach this problem. I've searched some inquiries the past few hours and I'm getting a lot of things related to model forms and Django choice fields which I don't want to get into if I don't have to. My idea is to just change the innerText/value, and check it against my django database.
I also came across this answer from SO:
How do I integrate Ajax with Django applications?
and am a bit confused by it. If I understand correctly, the AJAX GET request will extract data in javascript objects the same as if I visited that url as a user. Does this mean I could just create another html template and post every vehicle in the database onto that page from which I can extract info and create my dynamic lists from?
Looking for the most straightforward way to dynamically generate my lists with ajax and verify the year, make, and model with my database which will then return the car's mpg.
models.py:
class Car(models.Model):
year = models.IntegerField(default=0)
make = models.CharField(max_length=60)
model = models.CharField(max_length=60)
mpg = models.IntegerField(default=0)
def __str__(self):
return ("{0} {1} {2}".format(self.year, self.make, self.model))
views.py: (right now, it just lists every vehicle and has no way to verify the vehicle on the spot)
def index(request):
context_dic = {}
car_list = Car.objects.order_by('make')
car_list_model = Car.objects.order_by('model')
context_dic['car_list'] = car_list
context_dic['years'] = []
context_dic['makes'] = []
context_dic['models'] = []
for year in range(1995, 2016):
context_dic['years'].append(year)
for make in car_list:
if make.make not in context_dic['makes']:
context_dic['makes'].append(make.make)
else:
continue
for model in car_list_model:
if model.model not in context_dic['models']:
context_dic['models'].append(model.model)
else:
continue
return render(request, 'ConverterApp/index.html', context_dic)
html: (x3 for the make and model)
<div id="specifics">
<div class="dropdown" id="year-dropdown">
<button class="btn btn-default dropdown-toggle" type="button"
id="dropdownMenu1" data-toggle="dropdown" aria-haspopup="true" aria-expanded="true">
Year
<span class="caret"></span>
</button>
<ul class="dropdown-menu" aria-labelledby="dropdownMenu1">
{% for year in years %}
<li>{{ year }}</li>
{% endfor %}
</ul>
</div>
javascript: (just shows the value right now, but can't verify with the database)
$('#calculate').on('click', function ()
{
$(this).siblings()[0].textContent = (
document.getElementById("dropdownMenu1").textContent
+ " " + document.getElementById("dropdownMenu2").textContent
+ " " + document.getElementById("dropdownMenu3").textContent
+ " " + document.getElementById("specifics-gas").value
)
});
});
//this part changes the year, make, model to what the user selects //from the list
$('li').on('click', function () {
$(this).parent().siblings()[0].innerHTML = this.innerHTML
//console.log(this.textContent)
});
Suppose you have to populate a static list of all the brand names in a drop-down and the second dropdown is supposed to be populated based on the selection in first.
Assuming two simple Django models defining Brands and Showrooms.
Views.py
class YourView(TemplateView):
template_name = 'template.html'
def get_context_data(self, **kwargs):
brands = Brands.objects.all()
context = super(YourView, self).get_context_data(**kwargs)
context.update({'brands': brands})
return context
def get_showrooms(request, **kwargs):
brand = Brands.objects.get(id=kwargs['brand_id'])
showroom_list = list(brand.showrooms.values('id', 'name'))
return HttpResponse(simplejson.dumps(showroom_list), content_type="application/json"
HTML
<label>Select Brand</label>
<select id="brands" name="brands" class="form-control">
<option value="">Select Brand</option>
{% for brand in brands %}
<option id="{{ brand.id }}" value="{{ brand.id }}">
{{ brand.name }}
</option>
{% endfor %}
</select>
<label>Select Showrroom</label>
<div id="showroom_list">
<select name="showrooms" class="form-control">
</select>
</div
Ajax
$('select[name=brands]').change(function(){
brand_id = $(this).val();
request_url = '/sales/get_showrooms/' + brand_id + '/';
$.ajax({
url: request_url,
success: function(data){
$.each(data, function(index, text){
$('select[name=showrooms]').append(
$('<option></option>').val(index).html(text)
);
};
});
You can make the RESTful calls in request_url.
You can further populate the third dropdown based on the selection in second and so on. Also, you can access the selected option and perform the further stuff.
The chosen plugin can help you in optimizing your dropdowns.
I would go for a REST service, like Django Rest Framework, and then use jquery to autopopulate the dropdowns.
If installing a REST service is a hassle, you could write a couple of views to get the data in json format...
For instance, if you have a REST service in /myapp/api, you could populate the Cars like this:
$.ajax({
url: "/myapp/api/cars?format=json",
dataType: "json",
success: function( data ) {
var makes=[];
for (var i in data) {
car = data[i];
if (makes.indexOf(car.make) < 0){ // avoid duplicate brands
makes.push(car.make);
$('#makeselect').append($('<option>', {
value: car.id,
text: car.make
}));
}
}
}
});
Then, attach a handler when the "make" selector has changed, and populate the model and year accordingly using another REST call, like /myapp/api/cars?make=Ford
I'm not sure what you're confused about. Why would you put every car into a page? When you build a normal non-Ajax page, you pass some data - eg the slug or ID of a database object - via the URL, you query the database for that specific object, and return its data via an HTML template.
The exact same logic applies for Ajax, except that you probably don't want an HTML template; you can just return JSON, which is easy for JS to understand.

Selenium Testing Django with React and Ajax

I have a Django app that uses React to create a Newsfeed component. When the React Newsfeed component mounts, it makes an ajax call to the Django API to get the current user, and sets the author of a new post to the current user. Below is the code for the new post form React component:
var NewPost = React.createClass({
getInitialState: function() {
return {
author: 'Default Author'
}
},
getUser: function() {
$.ajax({
url: this.props.url + "user/",
dataType: 'json',
method: 'GET',
success: function(data){
this.setState({author: data.fields.first_name});
}.bind(this),
error: function(xhr, status, err) {
console.error("Error with API", status, err.toString());
}.bind(this)
})
},
componentDidMount: function(){
this.getUser();
},
handleSubmit: function(event) {
event.preventDefault();
var author = this.state.author;
var content = React.findDOMNode(this.refs.content).value.trim();
if (!content) {
return;
}
this.props.onPostSubmit({author: author, content: content});
React.findDOMNode(this.refs.content).value = '';
return;
},
render: function() {
return (
<div className="panel panel-default">
<div className="panel-body">
<form onSubmit={this.handleSubmit}>
<div className="form-group">
<textarea className="form-control" ref="content" placeholder="Whats Up" rows="3" id="newpost-input" />
<br/>
<input type="submit" className="btn btn-primary" id='newpost-submit' value="Submit" />
</div>
</form>
</div>
</div>
)
}
});
When I test this code manually everything works the way it should. I login, make a post, and my name is displayed as the author of the post. But when I test this using Selenium, the author is 'Default Author'; it is not getting changed. In my Selenium test I login to my app with my login credentials, and everything works as it should, except that the author of the post is not being changed from 'Default Author' to my name.
At first I thought that Selenium was doing its work before the ajax call had time to finish. So I added some wait times to my Selenium tests but the author name never gets changed. Any ideas why the ajax call seems to not be working?
UPDATE
Here is the relevant Selenium code:
class FunctionalTest(LiveServerTestCase):
def login(self):
self.browser.find_element_by_id('username').send_keys(LOGIN['USERNAME'])
self.browser.find_element_by_id('password').send_keys(LOGIN['PASSWORD'] + '\n')
def create_post(self, content=""):
self.browser.find_element_by_id('newpost-input').send_keys(content)
self.browser.find_element_by_id('newpost-submit').click()
def test_correct_author_name_is_displayed(self):
self.login()
self.create_post('A Post')
self.assertIn("Jonathan", self.browser.find_element_by_id('newsfeed').text)
I know the login with my credentials is successful because I added {{user}} to my django template, and added a print statement to the selenium test to print the text of the body and {{user}} is correctly displayed as my username.
Another test I did was to see if the react function componentDidMount was being called. In the componentDidMount function I did this:
componentDidMount: function() {
console.log("component mounting");
this.getUser();
console.log("component mounted");
},
In addition to that I also added console.logs to the success and error functions of the getUser ajax call. The console.logs from the componentDidMount function work, but the console.logs inside the ajax call do not.

Categories

Resources