Rendering django cms page as json - python

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.

Related

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 REST API with multiple representations/formats

I'm new in web dev and I'm trying for a project to develop a Restful web api and a website. I'm using Django framework and following tutos, I always see html files as static and the different views rendering an html template. This way of doing seems to me as backend and frontend are not much separated. Is it possible to have backend only developed in Django ?
edit:
I have actually a problem more specific. I having this app (records) with a view having "patient_list" using Response class from REST framework that renders some data and an html template like this:
def patient_list(request):
"""
List all records, or create a new .
"""
if request.method == 'GET':
#data = Patient.objects.all()
data= Patient.objects.all()
#serializer = PatientSerializer(data, many=True)
#return JSONResponse(serializer.data)
return Response({'patients': data}, template_name='records.html')
in my urls.py I have:
url(r'^records/$', views.patient_list),
and here I'm a little confused. Suppose one called this /records, so patient_list is called and will response with an html page. From what I understood (maybe wrong), a restful API should renders data in a standard view so that it can be used from any "frontend" (html pages or mobile app). Is this statement correct ? am I doing it wrong using Response with an html template ?
With Vanilla Django
Of course it's possible, and without any additional libraries to Django.
E.g. You can define a Django view that returns JSON data instead of rendering it into a HTML template server-side. Effectively making an API instead of a "website".
Here's an example with a class-based view that accepts GET requests and returns some JSON data with JsonResponse
from django.views.generic import View
from django.http import JsonResponse
class MyView(View):
def get(self, request):
my_data = {'something': 'some value'}
return JsonResponse(my_data, mimetype='application/json')
As you can see, you don't have to use the HTML rendering facilities in Django, they're there only if you want to use them.
With REST libraries
And of course there is a host of libraries to build RESTful APIs with Django, like Django REST Framework and Tastypie
Multiple representations and content negotiation
Content negotiation is the process of selecting one of multiple possible representations to return to a client, based on client or server preferences.
You can support more than one format in your REST API. E.g. you can support both HTML and JSON formats. There are various ways to do this:
You may use a GET param ?format=JSON (and have it default to HTML e.g.)
You may use Accept headers
You may have two URLs /records.html and /records.json (the format suffix method)
More on this topic in DRF's documentation
E.g. if you were to implement the first method with the GET params you could modify your code this way:
if request.method == 'GET':
data = Patient.objects.all()
format = request.GET.get('format', None)
if format == 'JSON':
serializer = PatientSerializer(data, many=True)
return JSONResponse(serializer.data)
else:
# Return HTML format by default
return Response({'patients': data}, template_name='records.html')

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

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.

Update Jinja2 template variables

I am using appengine with Python and jinja2 template.
I encountered an issue during the process: I render a list of games with this code
self.templateValues = {}
self.templateValues['title'] = 'GalaStore'
self.templateValues['values'] = kw
gamesQuery = Game.all()
values = {'games' : gamesQuery.run()}
self.templateValues['gl'] = values
template = JINJA_ENVIRONMENT.get_template(template)
self.response.out.write(template.render(self.templateValues))
then I have some button-filters in my html, and everyone calls a different js function. The problem is: once I hit the filter "sort by alpha" and I call a python function "sortByAlpha" via js (via ajax), how can I update the template variables in runtime withouth calling the template.render() function again? That would cause the reloading of the entire page and I would like to avoid it.
Thank you very much!
Your AJAX request would either need to return the games object list in JSON form, so the JavaScript could update the list in the browser, or you would have a template rendering just that part of the page, and have JavaScript swap out that piece with the HTML loaded from your server.
The latter can be made reusable; have both your main view and your AJAX handler use the same template, rendering just the list of games (no the whole page):
def rendered_games_list(self, sort_by=None):
games_query = Game.all()
if sort_by:
# I winged this bit, you didn't specify the ORM used
games_query = games_query.order_by(sort_by)
template = JINJA_ENVIRONMENT.get_template(games_list_template)
return template.render(gl=games_query.run())
then use this part in your main view:
template_values = {
'title': 'GalaStore',
'values': kw,
'games_list': self.rendered_games_list()
}
template = JINJA_ENVIRONMENT.get_template(template)
self.response.out.write(template.render(self.templateValues))
and in your main template insert the rendered games list HTML as:
{{ games_list|safe }}
So your main template doesn't render the games list itself, it merely includes it.
Your AJAX handler can return the rendered_games_list() directly:
sort_order = self.request.get('sort_order', None)
self.response.out.write(self.rendered_games_list(sort_order))

implementation difficulties in some part of views.py file in django cms

My views.py code:
from django.template import Context, loader, RequestContext
from django.http import HttpResponse
from skey import find_root_tags, count, sorting_list
from search.models import Keywords
def front_page(request):
if request.method == 'get' :
str1 = request.getvalue['word']
fo = open("xml.txt","r")
for i in range(count.__len__()):
file = fo.readline()
file = file.rstrip('\n')
find_root_tags(file,str1,i)
list.append((file,count[i]))
sorting_list(list)
for name, count in list:
s = Keywords(file_name=name,frequency_count=count)
s.save()
fo.close()
return HttpResponseRedirect('/results/')
else :
str1 = ''
list = []
template = loader.get_template('search/front_page.html')
c = RequestContext(request)
response = template.render(c)
return HttpResponse(response)
def results(request):
list1 = Keywords.objects.all()
t = loader.get_template('search/results.html')
c = Context({'list1':list1,
})
return HttpResponse(t.render(c))
#this for everyone.
the flow is this:
1) I run my app on the server .
2)It shows me the search page due to the else part of the view "def front_page(request)", now I want to execute the if part of the view "def front_page(request)" because I want to execute my python code written there and the redirected to the view "def results(request)", how can I do that ?
3) what should I mention in "action" of the front_page.html and in urls.py so that I can get back to the same view again. because I could'nt get back to the same view that I want it is repetitively showing me the same search page.Please help.
To enlarge upon the answer posted by #Barnaby....by using action='#' your form will be posted to the same url as the url used in the get request for the form.
Then in your view code, you have logic that says - if the request for this url is a GET request then do the work to configure the form, otherwise, you assume it is a POST and then you can handle the response.
Additionally I would advise that the your view explicitly checks that the request is a POST and if not make the assumption that it is a GET, rather than the other way around (as you have it), this is safer, as GET and POST are not the only request types, and you definitely need to know that you are dealing with a POST request if you want to deal with variables submitted in the POST request.
Hope that helps
Short answer: action="#". This is a HTML trick to post back to the current URL.
The general answer to how to reference a view in a template is to use the url tag. You may also want to consider using Django's forms functionality.

Categories