I am terribly confused about the routing and url set up when using backbone.js and django together with the Django-restframework.
Where does the the template fit in when using a REST framework?
For example, i have a class based view defined for one of my urls where i want to use backbone.js to just update the div displaying students:
url(r'^home/students/$', views.StudentList.as_view()),
class StudentList(APIView):
"""
List all students
"""
def get(self, request, format=None):
students = Person.objects.filter(person_type = Person.STUDENT)
serializer = PersonSerializer(students)
return Response(serializer.data, "core/teachers/teacher_teaching.html")
def pre_save(self, obj):
obj.owner = self.request.user
How does Backbone routes fit in with the url routing of django. I have in a file router.js, something like this:
function($,jqueryui, _, Backbone, HomeView, StudentsView) {
var AppRouter = Backbone.Router.extend({
routes: {
// Define some URL routes
':home': 'showStudents',
'users': 'showContributors',
// Default
'*actions': 'defaultAction'
}
});
var initialize = function(){
var app_router = new AppRouter;
app_router.on('route:showStudents', function(){
// Call render on the module we loaded in via the dependency array
var studentsView = new StudentsView();
studentsView.render();
});
Yet the routes never actually get to my views?
Where does the the template fit in when using a REST framework?
It doesn't; Django templates are for normal Django HTML pages, not REST framework APIs. REST framework API responses are programmatically-generated documents (typically JSON or XML), so they don't need templates.
How does Backbone routes fit in with the url routing of django
They are 100% completely separate. Let's say you have a URL like:
www.example.com/foo/bar#baz
Django will handle this much of that URL:
www.example.com/foo/bar
while Backbone will handle the remaining:
#baz
Of course, that assumes that Django returns a webpage that uses Backbone; if it doesn't, the #baz will never even come in to play.
As a quick summary, when you visit a URL like the above, your browser will ask www.example.com/ for /foo/bar. This is when your urls.py in Django comes in; it has:
url(r'^foo/bar/?$', views.FooBar.as_view()),
so your webserver knows to send back whatever views.FooBar.as_view() gives it (whether that is REST framework-produced JSON document or an old school Django HTML document).
Once that document comes back to the server, it renders it, and this is where client-side code like Backbone and its router take their turn. The Backbone Router (whenever you call Backbone.history.start()) looks at the URL (ie. window.location) and looks for the anchor or "hash" part of the URL (eg. #baz). It then compares that part of the URL to its route list (similar to how your webserver compared the earlier part to urls.py) and if it finds a match, it "sends you to a page".
It's key to understand though, it doesn't really send you anywhere at all; all its really doing is changing the hash part of the URL and then running some Javascript which manipulates the DOM. Therefore, it is impossible for the Backbone Router to ever send you to a Django URL; if you want to hit a server route, you need to either use AJAX or window.location =.
Related
I am quite new to the web development world and have just built a Todo app using Django. I have used Django ModelForm for adding tasks to my TaskModel.
Now my problem is that each time I add a task, the whole page refreshes as the added task goes to the database. It is not a very good user experience, as it is refreshing the page on each task addition and also it is taking time for reloading the page. What should I do to stop page refresh but still add the task to the database?
my views.py looks something like this:
def index(request):
if request.method == 'POST':
form = TaskForm(request.POST or None)
if form.is_valid():
form.save()
all_tasks = TaskModel.objects.all()
return HttpResponseRedirect(reverse("index"))
else:
all_tasks = TaskModel.objects.all()
return render(request, "todo_list/index.html", {"all_tasks": all_tasks})
Note: I have used authentication in my todo app so that the tasks can be accessed from any device, so I don't think storing my task merely in the browser cache will work. But I am open to any suggestions.
Back-end
Use django-rest-framework so that you can handle the server traffic manually.
Front-end
You can use a DOM API called XMLHttpRequest, but also you can use more easy to use APIs such as fetch.
When the form event is emitted we have to e.preventDefault().
form.addEventListener("submit", (e)=>{
e.preventDefault();
// use the same URL in form's action <form action="{{url}}"></form>
fetch(url, {
method: "POST",
data: new FormData(form),
})
.then((response)=>{
return response.json()
})
.then((json)=>{
return console.log(json);
})
.catch((err)=>{
console.err(err); // an error occured
});
});
The Django server can respond with a different type of data, plain/text or application/json are suitable in this situation.
BTW, fetch is a function that returns a Promise, so you can use async and await to make you code look better. You can use axios, or JQuery.ajax to make XMLHttpRequest more easy to handle.
Use django-restframework to create the API and then use frontend frameworks like react, vue and etc, to send post request to your Django server, So this way it wouldn't have to reload the page everytime
I am using a DefaultRouter and have a custom method in it. Right now I am passing values as POST but I want to pass as GET with the pattern like example.com/wallets/balance/<customerID>/. I am using ViewSet.
My current urls.py looks like:
router = routers.DefaultRouter()
router.register('wallets', views.WalletView, basename='WalletModel')
router.register('wallets/balance/1/', views.custom_balance,basename='CustomBalanceModel') # This crashes
and models.py
def custom_balance(id):
return Response({'status': 'OK', 'data': 'success'}, status=status.HTTP_200_OK)
class WalletView(viewsets.ModelViewSet):
.....
When I did this I used a .js file to do the get and post
Something like this to get all data. Then I passed it to the template using AngularJS.
You could do this in an AJAX .get call in the tag inside the template as well if you're not using AngularJS or VueJS for example.
function HeatTreatController($scope, $http) {
$scope.Foodata =[];
var q
$http.get('/wallets/balance/').then(function(response){
$scope.Foodata = response.data;
$scope.Fooworkorder = response.data.workOrder;
});
}
Foodata would then be everything sent by your serializer through the viewset.
workorder is just the workOrder value (models.py workOrder field) accessed by the dot operator. Just like when you have a QuerySet and you want to get sub fields of your model.
wallets/balance has to be an accesible API URL.
In your Django app you should be able to go to this URL and see the data.
Now if you want to get 1 specific piece of data from a GET
function FooController($scope, $http) {
$scope.Foodata =[];
var q
$http.get('/wallets/balance/'+customer.id +'/').then(function(response){
$scope.Foodata = response.data;
$scope.workorder = response.data.workOrder;
});
}
If I am understanding your question correctly it would not be strictly necessary to separate URL like router.register('wallets/balance/1/', views.custom_balance,basename='CustomBalanceModel').
You can GET and POST through router.register('wallets', views.WalletView, basename='WalletModel')
Here is some more Django documentation on ViewSets
So in this cast if you're already doing a POST request somehow in your code you can instead do a GET request in the same fashion.
If you have the time to learn, I learned all this from Pluralsight:
https://www.pluralsight.com/courses/django-angularjs-web-development
If you have a day or two you can learn it all.
I also recommend this Max Goodridge video. They're all pretty good
This is my basic view using DjangoRestFramework:
class user_list(APIView):
"""
List all users, or create a new user.
"""
def get(self, request):
users = User.objects.all()
serializer = UserSerializer(users, many=True)
return Response(serializer.data)
def post(self, request):
serializer = UserSerializer(data=request.DATA)
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status=status.HTTP_201_CREATED)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
When I go to the URL which calls this view (localhost:8000/CMS/users), DjangoRestFramework already has a frontend which says:
GET /CMS/users
HTTP 200 OK
Vary: Accept
Allow: GET, POST, HEAD, OPTIONS
Content-Type: application/json
[
{
"username": "t",
}
]
How do I customize this? I want to use AngularJS on the frontend. I know that without DjangoRestFramework, I would return an html template which would be located in my Django App directory in a folder called "Templates". I've been told that DjangoRestFramework is useful becauase I can create a RESTful API which returns JSON objects. I tried adding the following to my settings.py file:
REST_FRAMEWORK = {
'DEFAULT_RENDERER_CLASSES': (
'rest_framework.renderers.JSONRenderer',
'rest_framework.renderers.BrowsableAPIRenderer',
)
}
but I still can't seem to figure out how I can customize the frontend of my Django application. I know that there is:
renderer_classes = (TemplateHTMLRenderer,)
in which I can return an html page in my view, like so:
return Response({'user': self.object}, template_name='user_detail.html')
but doesn't returning actual HTML pages defeat the purpose of DjangoRestFramework's ability to return JSON objects and create a RESTful API?
First off, there are some things to make Django Rest Framework play better with angular. Until I decided to try out ember, I was working through this utorial. To try to provide a useful example for your question:
Typically you want to put your DjangoRestFramework REST Api in something like /api.
If you're doing the seemingly ubiquitiious single page application, you can then have index.html get served up as a template (i.e. just have your default home view be a TemplateView with index.html as the template)
You would then have your angular html templates and your angular/jquery/etc. javsascripts and your css files as normal static files. NB that you generally don't want to have django templates generate angular code. First off, it makes things much more of a pain to debug, and secondly, the default angular and django template syntax use the same <% characters meaning you have to be careful to make sure one doesn't try to interpret the others templating code.
When you load http://yourserver/, this will bring up the index.html page which then pulls down angular stuff, which then starts making RESTful calls to your REST api to generate the data. Note that you can start mixing in stuff to use Django forms etc., but I'd recommend keeping it simple and then reading the linked article (or another) once you have the basics going.
All is in my title. I would like to get the current user information because i need it in my view to display action (delete/edit) depending of the user's rights.
I use the basic authentification make by Django (/login /logout), i didn't change anything. Is there a way to listen to this login/logout action and retrieve this information in the Angular context?
Pretty new in angular, i'm searching some informations that would help me to go in one or other direction.
Actually i don't have a REST API for authenticated my users.
I find some interesting article Best place/way to store 'global' data such as 'current logged in user' / How do I store a current user context in Angular? but for now as i said i don't have AuthService just the basic login/logout from Django.
I used Django Rest framework for some action on my project (like post/delete/read/update for some of my models) and it works fine with angularjs. But i'm happy with the basic authentification provided by Django, so i don't want to rewrite it. But i don't know how to listen on it and if it's possible.
I know that is a broad question and for now i dont't have code to show because afters hours of research i don't know where i need to begin.
If it's to broad i will remove it.
Thanks,
OK, you can do something like that
Example (someUrl is url to your function in view.py):
In angular controller add $http
$http({method: 'POST', url: '/someUrl'}).
success(function(data){
//process aswer
});
In djnago view.py:
from django.shortcuts import HttpResponse
import json
def check_login(request):
if request.user.is_authenticated():
return HttpResponse(json.dumps({'result': {'logged': True}, 'user': request.user.username}),
content_type="application/json")
else:
return HttpResponse(json.dumps({'result': {'logged': False}}),
content_type="application/json")
I have a web application which will return a user id based on the first segment of the url, much like Twitter:
http://www.myapplication.com/user-name-goes-here/
It can go deeper too, like so:
http://www.myapplication.com/user-name-goes-here/news/article_1/
In order to break the site down, I am using the following URL routing technique:
(r'^(?P<slug>\w+)/', include('myapp.sites.urls')),
This will then further route the user to the correct page, but as it stands I am having to query the database in every view in order to obtain the user_id based on the first url segment. I was hoping to somehow automate this so I don't have to bloat my views with the same code each time... my solution was to create some middleware which checks the url segment and returns a 404 if its not found:
from django.http import Http404
class DomainMiddleware(object):
def process_request(self, request):
from myapp.sites.models import Sites
dname = request.path.split('/')[1]
if not dname:
return
try:
d = Sites.objects.get(domain__exact=dname)
except Sites.DoesNotExist:
raise Http404
return
This works, but it's trying to parse EVERY request, even those to images, favicons etc.
My question is thus; Is there a way to run this query on every page load without clogging up my views with extra code? If middleware is the solution, how can I modify my code so that it doesn't include EVERY request, only those to successfully routed URLs?
Hope someone can help!
The Django server shouldn't be processing requests for static content URLs - certainly not in production anyway, where you'd have a different web server running to handle that, so this shouldn't be an issue there.
But if you say you'd like this to run for only sucessfully routed URLs, maybe you'd be better of using process_view rather than process_request in your middleware? http://docs.djangoproject.com/en/dev/topics/http/middleware/#process-view
process_view works at view level rather than request level, and provides a view_func argument which you can check so that your code doesn't run when it's the django.views.static.serve view used for serving static media during development.
Whatever happens you should defs be caching that database call if it's going to be used on every view.