How to add information in a page without refreshing the page? - django

I would like to have a page in my django application that has a button that search a product and after selecting quantities gets added to the page (without reloading) in a list where the total get calculated (something like that), I am a beginner in programing and I have a week reading and investigated how to do it but I don't found anything.
Is because you need other programming language? Or could you indicate me some documentation or some example that I can read. Mostly because for my inexperience I don't know how to identify the relevant information in the documentation or even what to look for.

This can be done using Ajax call,
check this example:
forms.py
class sampleForm(forms.Form):
input = forms.CharField()
views.py
from django.http import JsonResponse
def sampleview(request):
input = request.POST.get('input', None)
#perform your logic here
#let us say your data is in variable result
result = {'product1' : 'python' ,'product2' : 'django' , 'product3' : 'ajax' }
return JsonResponse(result)
urls.py
from django.urls import path, include
from . import views
urlpatterns = [
path('sampleview',views.sampleview,name='sampleview'),
]
your HTML
<form method="POST">
{% csrf_token %}
{{form.as_p}}
<button id="sampleform-submit" type="submit">submit</button>
</form>
<div id="results"></div>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script>
<script>
$("#sampleform-submt").click(function(){
e.preventDefault();
var form = $('#id_input').closest("form")
//id_input is id of input tag generated by form and above line selects the form
$.ajax({
url : "{% url 'sampleview' %}",
type: "POST",
data : form.serialize(),
dataType: 'json',
success: function(data){
#data is 'result' you return in sampleview function
$("#results").append('<p> '+ data.product1 +'</p>');
$("#results").append('<p> '+ data.product2 +'</p>');
$("#results").append('<p> '+ data.product3 +'</p>');
}
});
}
</script>
I hope this helps

Related

Add new object to list without refreshing with Django & Ajax

I'm searching for someone who helps me in a Django project with JS, Ajax and jquery.
I'm trying to create something like adding objects on the django-admin page. I used https://www.pluralsight.com/guides/work-with-ajax-django, and almost everything is working fine but...
On my form, I have multiple choice field with authors, when I pressed the button to add a new author, the object is properly saving in DB, but on the form, I can't see a new object. When I reload the page, the new object is on this multiple choice field.
I thought I should refresh the field to see a new object on the list, but I don't know it's the proper way to meet this goal.
[edit]
models.py
class Author(models.Model):
name = models.CharField(max_length=100)
class Book(models.Model):
book_author = models.ManyToManyField(Author,blank=True,)
...
form.py
class AuthorForm(forms.ModelForm):
class Meta:
model = Author
fields = ['name', ]
widgets = {
'name': forms.TextInput(),
}
views.py
I added class SaveAutor
def author_add_view(request):
form = AuthorForm()
return render(request,
"author/custom_create_author.html",
{"form": form})
class SaveAuthor(View):
template_name = "author/custom_create_author.html"
def get(self, request):
author_form = AuthorForm(request)
return render(request,
self.template_name,
{'form': author_form})
def post(self, request):
#assume authorForm has author_name defined
author_form = AuthorForm(data=request.POST)
if author_form.is_valid():
author = Author() #here is class name or form name?
author.name = author_form.cleaned_data['name']
author.save()
return JsonResponse({'author_id': author.id,
'author_name': author.name})
# error response or whatever you want to return
return JsonResponse({'error': 'author form is not valid'})
I had these views registered in urls.py
urls.py
# add an author
path('author/add/', views.author_add_view,
name='author_add'),
# not sure if I should add as_view() at the end
path('author/new-add/', views.SaveAuthor.as_view(),
name='new_author_add'),
When I try check if page with form is displaying properly using the SaveAuthor class based view I get error 'WSGIRequest' object has no attribute 'get', but when I use the author_add_view I got the template.
custom_create_author.html
$("#author-form").submit(function (e) {
// preventing from page reload and default actions
e.preventDefault();
// serialize the data for sending the form data.
var serializedData = $(this).serialize();
// make POST ajax call
$.ajax({
type: 'POST',
url: "{% url '.' %}", //serializer_ajax_mehit_from_vies
data: serializedData,
success: function (response) {
// on successfull creating object
// 1. clear the form.
$("#author-form").trigger('reset');
// 2. focus to nickname input
$("#id_author_name").focus();
},
error: function (response) {
// alert the error if any error occured
alert(response["responseJSON"]["error"]);
}
})
})
{% load static %}
{% load widget_tweaks %}
{% block content %}
<h4>
My author
</h4>
<form id="author-form">
{% csrf_token %}
<p>{{ form.as_p }}</p>
<button class="btn btn-outline-success" type="submit">save</button>
</form>
<br>
{% endblock %}
Here is another page where I'm trying to connect the book with multiple-choice-field author (it's typical form, but I'm enclosing only the button to pop-up the form, where I can add the new author)
add_book.html js code open pop-up windows to create new author
<script type="text/javascript">
$(function () {
$("#create-author").modalForm({
formURL: "{% url 'author_add' %}"
});
})
</script>
<button id="create-author" class="btn btn-primary" type="button" name="button">
<span class="fa fa-plus"/>
</button>
And on this page, I tried to paste your JS code
<script type="text/javascript">
// assume the add author button has an id of add_author_button
$('#create-author').click(function(event){
event.preventDefault();
// assume the text field has an id of author_name
author_name= $('#author_name').val();
create_post(event, author_name);
}
) //<-------- this closing bracket was missing?
function create_post(event, author_name) {
$.ajax({
url: "{% url '.' %}", // the endpoint I'll precise that in comment
type: "POST", // http method
data: {
author_name: author_name,
csrfmiddlewaretoken: $('[name="csrfmiddlewaretoken"]').val()
},
// handle a successful response - data will be a json object returned from your view method
success: function (data) {
if (data.error === null) {
// assume your author multiple choice select has an id of author_sel
// this will append the new author name to the list and will also
// set the value for this author to be the newly created id so you can
// perform other functions on the author like update and/or delete
$('#author_id').append($('<option/>', {
value: data.author_id,
text: data.author_name,
}));
} else {
// display the error on the page
// and/or write it to the console log
console.log(data.error);
}
},
// handle a non-successful http response
error: function (xhr, errmsg, err) {
// display the error on the page
// and/or write it to the console log
console.log(xhr.status + ": " + xhr.responseText); // provide a bit more info about the error to the console
}
});
}
</script>
One closing bracket was missing, so I added in on the JS script.
I had a problem with the endpoint, when I pass the class-based view SaveAuthor(View) (new_author_add by url name) I got the message: the author form is not valid, but when I used author_add_view (author_add by url name) undefined.
The issue is that while you are using AJAX to submit your new author, the author isn't being added to the author's multiple choice field in the current HTML page. Refreshing the page will retrieve the new value but that also does an entire post/refresh loop. Since you are submitting the post using AJAX, you can return the new author's id and name via a JsonResponse and use jQuery to add it to the author's multiple choice field.
views.py
from MyApp.forms import AuthorForm
from MyApp.models import Author
from django.shortcuts import render
from django.views import View
from django.http.response import JsonResponse
class SaveAuthor(View):
template_name = "author/author.html"
def get(self, request):
author_form = AuthorForm()
return render(request,
self.template_name,
{"form": author_form,
"authors":Author.objects.all()})
def post(self, request):
#assume authorForm has author_name defined
author_form = AuthorForm(data=request.POST)
if author_form.is_valid():
author = Author() #here is class name or form name?
author.name = author_form.cleaned_data['name']
author.save()
return JsonResponse({'author_id': author.id,
'author_name': author.name})
# error response or whatever you want to return
return JsonResponse({'error': 'author form is not valid'})Your AJAX
author.html
<!DOCTYPE html>
{% load static %}
<script src="{% static "jquery-3.4.1.min.js" %}"></script>
{% block content %}
<h4>
My author
</h4>
<select id="author_sel" name="author_sel" size="5" class="selectbox">
{% for author in authors %}
<option value="{{author.id}}">{{author.name|capfirst}}</option>
{% endfor %}
</select>
<form id="author-form">
{% csrf_token %}
<p>{{ form.as_p }}</p>
<input type="button" name="button" class="submit_button" id="add_author_button" value="Save">
</form>
<br>
{% endblock %}
<script type="text/javascript">
// assume the add author button has an id of add_author_button
$('#add_author_button').click(function(event){
event.preventDefault();
// assume the text field has an id of author_name
author_name= $('#id_name').val();
create_post(event, author_name);
}) //<-------- this closing bracket was missing?
function create_post(event, author_name) {
$.ajax({
url: ".", // the endpoint I'll precise that in comment
type: "POST", // http method
data: {
name: author_name,
csrfmiddlewaretoken: $('[name="csrfmiddlewaretoken"]').val()
},
// handle a successful response - data will be a json object returned from your view method
success: function (data) {
if (data.error === undefined) {
// assume your author multiple choice select has an id of author_sel
// this will append the new author name to the list and will also
// set the value for this author to be the newly created id so you can
// perform other functions on the author like update and/or delete
$('#author_sel').append($('<option/>', {
value: data.author_id,
text: data.author_name,
}));
} else {
// display the error on the page
// and/or write it to the console log
console.log(data.error);
}
},
// handle a non-successful http response
error: function (xhr, errmsg, err) {
// display the error on the page
// and/or write it to the console log
console.log(xhr.status + ": " + xhr.responseText); // provide a bit more info about the error to the console
}
});
}
</script>
urls.py
from django.urls import path
from . import views
app_name = 'myapp'
urlpatterns = [
# add an author
path('add/', views.SaveAuthor.as_view(), name='author_add'),
]
forms.py
from django import forms
from MyApp.models import Author
class AuthorForm(forms.ModelForm):
class Meta:
model = Author
fields = ['name', ]
widgets = {
'name': forms.TextInput(),
}
models.py
from django.db import models
# Create your models here.
class Author(models.Model):
name = models.CharField(max_length=100)
This is now a complete working example.

Django Render HTML via AJAX - Missing Context Variable Data

In my Django web app, I'm trying to dynamically update only a certain section of my page via AJAX, but doing so by returning/replacing HTML in a child template ({% include 'keywords.html' %}). I understand that I can (and maybe should) return a JsonResponse (and I have done so successfully), but I'd like to try and get the below implementation working (as others seem to have).
The view successfully returns the HTML to the AJAX response, but lacking the data contained in the keywords context variable.
templates/index.html
...
<div id="keywords">
{% include 'keywords.html' %}
</div>
...
templates/keywords.html
<div id="keywords">
{% if keywords %}
{% for keyword in keywords %}
<p>{{keyword.word}}</p>
{% endfor %}
{% endif %}
</div>
views.py
def add_keyword(request):
if request.method == 'POST':
form = KeywordForm(request.POST)
if form.is_valid():
...
keywords = Keywords.objects.values()...
print(keywords) # this works, contains a queryset with data
context = {
keywords: keywords,
}
# i've also tried return HttpResponse(render_to_string(...))
# with same result
return render(request, 'keywords.html', context))
index.js
// i've also tried jquery .load()
$.ajax({
url: data.url,
type: "POST",
data:
{
keyword: keyword,
csrfmiddlewaretoken: data.csrf_token
},
success: function(data) {
$("#keywords").html(data);
}
});
AJAX Response data:
<div id="keywords">
</div>
What might I be missing, or doing wrong?
In your context you are missing quotes, when returning the page you have one extra parentheses. It works on my system.
You can render your template with context data using the loade and context
it will do first templates using jinja context will render in html then return final html text then you can pass using JsonResponse
try following stuff then let me know
#view.py
from django.template import context,loader
...
def render_view(request):
if request.method == 'GET':
form = KeywordForm(request.POST)
if form.is_valid():
keywords = Keywords.objects.values()
print(keywords) # this works, contains a queryse
context = {
keywords: keywords,
}
template = loader.get_template('keywords.html')
html = template.render(context)
print(html)
return JsonResponse({'html':html},status=200,content_type="application/json")
#in ajax call success method you should render
success: function(data) {
$("#keywords").html(data);
//or
//ordocument.getElementById('keywords').innerHTML=data;
}
if works or not let me know?

Pass a rendered view to another app's view in Django

I'm trying display the outputs of 2 apps on a same web page, but am encountering issues when trying to use the solution proposed here.
I have a "main_app" handling the content of most of the page, and would like to add the output of a "sub_app" (i.e. a rendered <div> element) on the same page.
Here's how I collect the output of sub_app in a main_app view:
from sub_app.views import sub_app_view #
def main_app_view(request):
my_sub_app_html = user_tests(request) #supposed to get rendered HTML content from sub_app
context = {
'sub_app_html ': my_sub_app_html,
}
return render(request, 'main_app.html', context)
Then the view in sub_app:
def sub_app_view(request):
context = {
'sub_app_context': "foo",
}
return render(request, 'sub_app/sub_app.html', context)
main_app.html contains:
<p>
{{ sub_app_html }}
</p>
and sub_app.html:
<div id="mydiv">
{{ sub_app_context }}
</div>
But instead of correctly displaying the rendered HTML from sub_app_view, what is shown in main_app.html in the browser is:
<HttpResponse status_code=200, "text/html; charset=utf-8">.
Is there a solution to this, or a better way to achieve linking between apps?
you can do it using
**
javascript and jquery
**
$.ajax({
type: "get",
url: url_app_1,
data: data,
success: here add your html to your div1,
dataType: dataType
});
$.ajax({
type: "get",
url: url_app_2,
data: data,
success: here add your html to your div2,
dataType: dataType
});
and in the success you can append the html to your div
**
Django solution:
**
The render function return an HttpResponse(content, content_type, status)
so to get the template html you need to:
def main_app_view(request):
my_sub_app_html = user_tests(request)
context = {
# you need to get content then decode
'sub_app_html ': my_sub_app_html.content.decode("utf-8"),
}
return render(request, 'main_app.html', context)
Here is the source code of the render

display json dictionary values in templates

I am doing ajax using jquery in django1.3,well its works fine. Am using jquery load method to fill a in a template.
I get a json object asychrosily when user cliks in a button.I pass it to another template(which i loading inside the div of first template ) as a dictionary. But am unaware of how I display it in template.(I tried to pasres json in template page),but its leads to error.
Can any one suggest How can solve the problem?
So I used normal way parse json in view and pass it to template by using the method locals() in render_to_response(). Is it a good approch?
testjqyery.html
$(document).ready(function() {
$('#save').click(function(e)
{
e.preventDefault();
$( '#results' ).html( ' ' ).load( '{% url t %}' );
});
<div id="results"></div>
views.py
def testupdater(request):
// getting json from server
//contents_json = json.loads(...)
json_data = {'json_dict': contents_json}
return render_to_response( 'results.html' ,json_data,context_instance=RequestContext(request))
results.html
{% if json_dict|length %}
{% else %}
{% endif %}
try it this way
from django.utils import simplejson
data = []
data.append({"msg": 'Hi this message'})
json = simplejson.dumps(data)
return HttpResponse(json, mimetype='application/json')

Passing variable from template.html to views.py by URL (using a file input form)

Maybe this is a very silly question but I'm new using django. I have a certain django template with a set of properties that can be chosen. On an uploaded file I have to perform a different treatment depending on the chosen property, so I want to pass the chosen property value from the template to the view. Properies are hard coded in view.py and retrieved in the template by getJSON:
<script type="text/javascript">
$(function() {
$.getJSON('available_properties', function(data) {
var options = [];
for(var i in data.properties)
{
var prop = data.properties[i];
options.push('<option value="'+prop+'">'+prop+'</option>');
}
$("#properties > select").html(options.join(''));
});
});
</script>
Then an uploading file form trigger the action:
<form onsubmit="return checkfile();" prop="return get_prop();" action="calculate/<property_value_goes_here>" enctype="multipart/form-data" method="POST">
{% csrf_token %}
<input type="file" id="uploadfile" name="uploadfile" size="30">
<input type="submit" id="calculate" value="Calculate!">
</form>
How can I pass the property value directly in the URL path that must be called on the submit form?
Actually you have two ways to solve that problem. One is parsing the url, the other one is passing the properities as request parameters.
The first one can be implemented like this:
urlpatterns = patterns('',
(r'^/(?P<property>\*)/$', 'appname.viewname'),
)
in your url, and:
def your_view(request,property):
#your view stuff here
in views.py of your app. This is documented in Part 3 of the django tutorial, as you can find it here: http://docs.djangoproject.com/en/1.2/intro/tutorial03/
But for your problem the second solution is probably the better on. You can create a standard url-querystring (as your post suggests you know how to use js to do that) like this:
/upload/?property=value&someotherproperty=othervalue
and get the passed values like this:
def your_view(request):
property = request.POST.get('property',None)
someotherproperty = request.POST.get('someotherproperty',None)
where the get works as:
request.POST.get(property_name,fallback_value)
To put the querystring into request.POST, you have to configure your urls.py like this:
urlpatters = patterns('',
(r'^upload/$','appname.viewname'),
)
That way everything after /upload/ will be passed to request.POST