How to send two variables with html as a JSON in Django? - python

I want to render two different HTML samples and send it back as response to ajax request.
I have something like this in my view:
def getClasses(request):
User = request.user
aircomcode = request.POST.get('aircompany_choice', False)
working_row = Pr_Aircompany.objects.get(user=User, aircomcode=aircomcode)
economy_classes = working_row.economy_class
business_classes = working_row.business_class
economy = render_to_response('dbmanager/classes.html', {"classes": economy_classes}, content_type="text/html")
business = render_to_response('dbmanager/classes.html', {"classes": business_classes}, content_type="text/html")
return JsonResponse({"economy": economy,
"business": business})
With this I get the error:
django.http.response.HttpResponse object at 0x7f501dc56588 is not JSON serializable"
How can I do my task?
In js when I get the response I would like to insert received HTML into corespoding blocks. Like this:
$.ajax({ # ajax-sending user's data to get user's classes
url: url,
type: 'post',
data: {"aircompany_choice": aircompany_choice}, # send selected aircompanies for which to retrieving classes required
headers: {"X-CSRFToken":csrftoken}, # prevent CSRF attack
}).done (result) ->
add_booking_classes.find(".economy-classes").children(":nth-child(2)").html(result["economy"])
add_booking_classes.find(".business-classes").children(":nth-child(2)").html(result["business"])

Try Django's render_to_string :
economy = render_to_string('dbmanager/classes.html', {"classes": economy_classes})
business = render_to_string('dbmanager/classes.html', {"classes": business_classes})
render_to_string() loads a template, renders it and then returns the resulting string. You can then send these resulting strings as JSON.
Your final code now becomes:
from django.template.loader import render_to_string
def getClasses(request):
User = request.user
aircomcode = request.POST.get('aircompany_choice', False)
working_row = Pr_Aircompany.objects.get(user=User, aircomcode=aircomcode)
economy_classes = working_row.economy_class
business_classes = working_row.business_class
economy = render_to_string('dbmanager/classes.html', {"classes": economy_classes})
business = render_to_string('dbmanager/classes.html', {"classes": business_classes})
return JsonResponse({"economy": economy,
"business": business})

render_to_response is, as the name implies, for rendering a response. You don't want to do that; you want to render two templates, and put them into a JSON response. So use render_to_string.

You can send one in your context and one as where you want to render.

Related

Passing data from post form to FileResponde view

I recently started using Django and I managed to create two views, one to submit a form and another to return a FileResponse, separately, they work fine.
Now, I need to integrate both, when the client submit the form, I want to redirect to the another view using the fields submitted at the previous form. How can I do that?
Here is my form view:
def submitForm(request):
if 'report' in request.POST:
date_start = request.POST.get('date_start')
date_end = request.POST.get('date_end')
state = request.POST.get('state')
return render(request, 'comissao.html')
Here is my view that creates a pdf file
def createPdf(request):
date_start = '20220301'
date_end = '20220331'
state = 'G00471'
body = "some html"
options = { 'quiet': '' }
pdfkit.from_string(body, options=options)
file = open('file.pdf', 'rb')
return FileResponse(file)
As you can see, I need the information passed at my first view, to use at second view, I tried something like this, but I think I'm mistaking the concept,
return reverse('pdf', kwargs={'state':state, 'date_start':date_start, 'date_end':date_end})
reverse() only returns the URL, but I think you rather want to do a redirect() to that view.
For passing the parameters you have several options:
GET parameters
Session
URL parameters
Let's use GET parameters, which I would suggest:
from urllib.parse import urlencode
...
def submitForm(request):
...
response = redirect('pdf')
params = { state' : state, 'date_start: date_start, 'date_end': date_end}
response['Location'] += f'?{urlencode(params)}'
return response
Then in your PDF view you need to parse the GET parameters:
def createPdf(request):
date_start = request.GET.get("date_start")
...
Note that you may also need to convert your dates into string and back for the query, which I ignored here.

Dynamic consuming of web API in Django based on user's choice

The program I am trying to write requires that whenever the user changes a value in a form on Django website, that value will be written to the variable and then inserted into the API's url as parameter inside requests.get() function in views.py file.
So basically my Django website is to consume web API.
API returns different data sets ​​depending on the explicit endpoint. It can change dynamically depending on what the user chooses in a form, and then, if submit button is clicked, show the content on a django website immediately.
Here is the Web API which I use to get data sets:
http://api.nbp.pl/en.html
forms.py:
from django import forms
class DateInput(forms.DateInput):
input_type = 'date'
class ExampleForm(forms.Form):
my_date_field = forms.DateField(widget = DateInput)
views.py:
from django.shortcuts import render
import requests
from .forms import ExampleForm
def home(request):
submitbutton = request.POST.get("submit") # I check if submit button is clicked
form = ExampleForm()
date2 = ''
if form.is_valid():
date2 = form.cleaned_data.get("my_date_field") # write date choosen by user to variable
# And now I have a problem. I want to use the value of this variable to specify an endpoint:
response = requests.get(f"http://api.nbp.pl/api/exchangerates/tables/a/2012-01-01/{date2}/")
Api = response.json()
context= {'form': form, 'submitbutton': submitbutton, "Api": Api}
return render(request, 'home.html', context)
The user selects a date in the form and based on that date, the data set is returned.
I have no problem with the HTML template file. I know how to insert form and submit button on a website, and how to view the data set using API, but my goal is to make it flexible - dependent on form value.
Current code returns error: JSONDecodeError. The help would be greatly appreciated.
Yes, URL constructed using the f-string returns data.
I found that if I don't use the function is_valid(), form is invalid but code returns correct reponse (Response [200]) and as a result the data is correctly displayed without error, but this only happens if the value of date2 is constant - this is not what interests me, I want it to be taken from the form!
Please have someone look at my code and say if I am doing something wrong, I am tired of this problem...
from django.shortcuts import render
import requests
from .forms import ExampleForm
def home(request):
submitbutton = request.POST.get("submit")
date2 = '2020-01-17'
if request.method == 'POST':
form = ExampleForm(request.POST)
if form.is_valid():
print("Is Valid")
date2 = form.cleaned_data.get("my_date_field")
date_string = str(date2)
argument = f"http://api.nbp.pl/api/exchangerates/tables/a/2012-01-01/{date_string}/"
response = requests.get(argument)
Api = response.json() # This causes an error, because response is incorrect, I don't know why
return render(request, 'home.html', {'form': form, 'submitbutton': submitbutton, "Api": Api} )
else:
print("Is no valid")
form = ExampleForm()
date2 = '2012-01-10'
response = requests.get(f"http://api.nbp.pl/api/exchangerates/tables/a/2012-01-01/{date2}/")
Api = response.json() # This doesn't cause an error, response is correct - but that way value of variable is not taken from the form...
context= {'form': form, 'submitbutton': submitbutton, "Api": Api}
return render(request, 'home.html', context)

Redirect to the same view while changing one parameter

I have an ajax call that sends a country label to my view function below:
views
...
posts = Post.objects.all()
if request.method == 'POST':
country = request.POST.get('country')
print('COUNTRY:', country) #successfully prints
posts = Post.objects.filter(country=country)
context = {
...
'posts': posts,
}
return render(request, 'boxes.html', context)
I successfully get the ajax data but what do I do after this in order to redirect to the same view with the new posts value?
If you are using Ajax.You have to use window.location.reload(); in success method of Ajax post call.
As i read that you are using Ajax:
The function reload #Himanshu dua said is ok
And i should check the way you use URL and VIEW
# The function reload will work well if you change the DATA
# and it will reload and return again the New value from data
Or you should try to replace the old with the new DATA you got from Server via ajax (just change the value with Jquery)
In your example the view returns a rendered template: boxes.html. For this to work, you would have to either
modify your view to use query parameters (eg /my/url?country=nowhere). This would then work with GET requests instead of posts, and you can easily call it via URL.
or use a html form instead of AJAX requests. A form can easily POST to an endpoint and it will load whatever your webserver returns.
Ajax calls are designed to exchange data with a server, not really for downloading whole webpages. So if you wanted to use ajax, you could make your view return a json/xml/whatever list of objects and then use js inject them into your page:
function successCallback(data) {
var elem = document.getElementById('myelement');
elem.innerHTML = data;
}
It doesn't work that way.
On the HTML page, using Javascript, you should:
(1) Send an AJAX call (GET/POST) to load the view function in the
backend
(5) Receive the output of the view function and do whatever you want with it.
On the Backend, using the view function, you should:
(2) Receive the GET/POST Data from the frontend (HTML)
(3) Do whatever you want with that.
(4) Return the output of the function as JSON using HttpResponse
Note the numbers next to each item. It happens according to that
sequence from 1 to 5.
Here is an example:
On the HTML Page (Javascript):
var posts;
$("button").click(function(){
$.post("/test/", function(data, status){
posts = data;
console.log(data);
});
});
On the Backend (Python):
import json
from django.http import HttpResponse
def test(request):
if request.method == 'POST':
country = request.POST.get('country')
posts = Post.objects.filter(country=country)
return HttpResponse( json.dumps(posts) )
else:
return HttpResponse( "error" )

Django: send json response from view to a specific template

The main requirement is to send a json object from django view to a specific template named output.html (already present in templates directory), as a part of response. Also, the json response contains model and pk attribute, I want to remove them and send only the fields json attribute.
When I try as follows :
def view_personal_details (request):
personal_detail_json = personal_details.objects.all()
personal_detail = serializers.serialize('json', personal_detail_json)
return HttpResponse (serializers.serialize('json', personal_detail_json), content_type='application/json');
I get json in a new page.
And when I try as follows :
def view_personal_details (request):
personal_detail_json = personal_details.objects.all()
personal_detail = serializers.serialize('json', personal_detail_json)
return render (request, "webFiles/output.html", {'personal_detail': personal_detail})
I have to access the data via {{ personal_detail }} in my html, and not from response.
Also, the json response is as follows :
[
{
model: "buglockerApp.personal_details",
pk: "001",
fields: {
name: "Rajiv Gupta",
email: "rajiv#247-inc.com",
doj: "2016-06-22",
dob: "2016-06-22",
address: "Bangalore",
contact: "9909999999"
}
}
]
I don't want the model and pk to be sent as the response. Only fields should be sent as a part of response to webFiles/output.html file.
Thanks in advance!!
you can do the following in python2.7
import json
from django.http import JsonResponse
def view_personal_details (request):
personal_detail = serializers.serialize('json', personal_details.objects.all())
output = [d['fields'] for d in json.loads(personal_detail)]
# return render (request, "webFiles/output.html", {'personal_detail': output})
# for ajax response
return JsonResponse({'personal_detail': output})
or you can read the following for more clarification
https://docs.djangoproject.com/en/1.10/topics/serialization/#serialization-of-natural-keys
https://github.com/django/django/blob/master/django/core/serializers/base.py#L53
The default serializers always add the model and pk so that the data can be deserialized back into objects. Either you can write a custom serializer or can simply remove the unwanted data.
personal_details = [pd['fields'] for pd in personal_details]
This should give you a new list of dicts with personal details

Rendering django cms page as json

I have a django CMS page, I want the rendered html to be made into a json object(dump the CMS html into JSON), is this possible? I'd like it to look something like this:
How would I go about this?
So after some digging , this is what I managed.
CMS has a views.py which has a function "details(request, slug)"
I used this method to render the required page, by passing the slug of the page I need rendered , got the response and put it into a JSON object and returned this.
from cms.views import details
def index(request, topic):
if topic == 'home':
template = details(request, '')
else:
template = details(request, topic)
content = ''
if hasattr(template, 'render'):
# TemplateResponse must call render() before we can get the content
content = template.render().content
else:
# HttpResponse does not have a render() method
content = template.content
# Send JSON response
return JsonResponse({
'createdAt': datetime.datetime.now(),
'content': content
})
Any better way of doing the same?
I think this should be fairly easy. Instead of returning the rendered output from the template, put it in a dictionary. Then just from json import dumps or dump and dump(dictionary) / dumps(dictionary) depending on your purpose. dumps gives you a string. dump gives you something fancier.

Categories