integrating Django with Angular js - python

This will going to be a very basic question that how to integrate Django with angularjs.I have developed a web application using Django.In views.py, i want to use json to dump my data from database but i don't have any idea or you can say i can't get started with the process.I have a very basic level knowledge about Angularjs.If you give some examples , then it will help me to get start in Angularjs using Django.For better convenience,here is a sample view that i have produced..
def userphoto(request):
user_photo = Photo.objects.get(user = request.user)
context = RequestContext(request)
ctx_dict = {'user_photo': user_photo}
return render_to_response('userena/profile_detail.html',ctx_dict,context)
here the ctx_dict directly rendering into a html file,but i want to render them using Angularjs probably using json and http get request to implement the data using Angularjs http service.How can i do this?in mention i am a novice in angularjs.

You can use django-angular, of cause, but I find this package too WIP.
You should think about AJAX instead of just rendering. It depends on a problem.
I'd suggest to use plain django or adding tastypie or django-rest-framework. I, currently, use plain django views.
Yes, to send models data back to angular, you should provide JSON of your data, you should serialize your model. But! There is a lot problems and catches. First of, you don't need everything from the model. Because user could access to some strange fields. Because you will send too many data you don't use on client side.
So, you should serialize your items data into JSON with fields you want. Here is example how I do it:
#ajax_request
#login_required
def mydata_ajax(request):
qs = MyData.objects.all()
#add possible filters
if request.GET.get('search'):
s = request.GET.get('search')
qs = qs.filter(
Q(name__icontains=s) |
Q(email__icontains=s) |
Q(address__icontains=s) |
)
qs = qs.order_by('task_time', 'name')
#setup pagination so angular will retrieve data page by page
pages = Paginator(qs, 20)
try:
current_page = int(request.GET.get('page', 1))
except ValueError:
current_page = 1
if current_page > pages.num_pages:
current_page = 1
#get reguested page
page = pages.page(current_page)
#create response
return {
'total': pages.count,
'num_pages': pages.num_pages,
'page': current_page,
'data': [{
'id': o.id,
'name': o.name,
'email': o.email,
'address': o.address,
} for o in page.object_list]
}
First of, I use ajax_request decorator, from django-annoying package, for my view, which expects view to return list, dictionary or any other simple data so it will automatically serialize(convert) it to JSON.
There is some handy things for you, like example of filters and pagination, btw.

have a look at
django-angular integration
django-angular-model-forms
django-angular

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 filtering queryset

Here is my simple view:
def transaction_list(request):
current_user = request.user
month = datetime.date.today().month
try:
page = request.GET.get('page', 1)
except PageNotAnInteger:
page = 1
objects = Transaction.objects.filter(user=current_user, date__month=month)
p = Paginator(objects, 10, request=request)
transactions = p.page(page)
return render(request, 'transaction/list.html',
{'transactions': transactions})
It shows a list of transactions which occured in the current month.
I want to add an option to change the month of the transactions being displayed but I have no clue how to tackle this and make it work. Should it be done in a view? maybe template? I would appreciate any ideas
Take some time to read some Django docs as they may prove really valuable (not to mention they are very clean and well written for every version available). I would focus on Working With Forms
In short, you'll pass the month from your django template (maybe via ajax or a simple HTML form POST), to your view, and use your view function to get the POST data and use that in your queryset.
It is hard to provide a good, thorough answer because there are different ways to do this. Do you want AJAX? Simple form with page reload, etc? 
Okay, here, in detail, is how I usually handle a POST request. This isn't tested code, it's just psuedo code, but should work as far as I can tell, aside from a few minor typos probably. BUT, it should give you an idea of how to handle ajax requests in Django.
This is pretty 101 and taking some time to read the docs and run through some of the early projects covers a these concepts much I, so my going into more depth isn't really valuable to SO readers.
views.py
class change_date_form(forms.Form):
new_date = forms.DateField()
def change_transaction_date(request):
#Do some checks to make sure user is authorized to do this
current_user = ...
customer_data = []
if request.method == 'POST':
form = change_date_form(request.POST, request.FILES)
if form.is_valid():
change_date = form.cleaned_data.get('new_date')
objects = Transaction.objects.filter(user=current_user, date__month=change_date)
for i in objects:
customer_data.append(objects.name)
response_data = json.dumps(customer_data)
return HttpResponse(response_data, content_type='application/json')
urls.py
...
url(r'^change_date_view/', 'module.views.change_transaction_date'),
Jquery:
$('button_handler').on('click', function() {
var new_date_value = $(date_field_selector).val()
$.ajax({
url: "/change_date_view/",
type: "POST",
data: {
new_date: button_handler,
},
success:function(data) {
//build your html via javascript with response data
}
})
})

django-rest-framework: Rendering both HTML and JSON with the same ModelViewSet

I'm using Django==1.10.5 and djangorestframework==3.5.3.
I have a few ModelViewSets that handle JSON API requests properly. Now, I'd like to use TemplateRenderer to add HTML rendering to those same ModelViewSets. I started with the list endpoint, and created a simple template that lists the available objects. I implemented the get_template_names to return the template I created.
Accessing that endpoint through the browser works fine when there are no objects to list, so everything related to setting up HTML renderers alongside APIs seems to work.However, when tere are objects to return the same endpoint fails with the following error:
ValueError: dictionary update sequence element #0 has length XX; 2 is required
Where XX is the number of attributes the object has.
This documentation section suggests the view function should act slightly differently when returning an HTML Response object, but I assume this is done by DRF's builtin views when necessary, so I don't think that's the issue.
This stackoverflow Q/A also looks relevant but I'm not quite sure it's the right solution to my problem.
How can I make my ModelViewSets work with both HTML and JSON renderers?
Thanks!
DRF has a brief explanation of how to do this in their documentation.
I think you'd do something like this...
On the client side, tell your endpoint what type of response you want:
fetch(yourAPIUrl, {
headers: {
'Accept': 'application/json'
// or 'Accept': 'text/html'
}
})
In your view, just check that and act accordingly:
class FlexibleAPIView(APIView):
"""
API view that can render either JSON or HTML.
"""
renderer_classes = [TemplateHTMLRenderer, JSONRenderer]
def get(self, request, *args, **kwargs):
queryset = Things.objects.all()
# If client wants HTML, give them HTML.
if request.accepted_renderer.format == 'html':
return Response({'things': queryset}, template_name='example.html')
# Otherwise, the client likely wants JSON so serialize the data.
serializer = ThingSerializer(instance=queryset)
data = serializer.data
return Response(data)

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')

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))

Categories