Python separating Ajax requests from normal page views - python

I'm wondering what are some strategies that you've come up when dealing with this. I'm new to the python/django framework and would like to separate the serving of view from the handling of ajax requests (xhr).
I'm thinking of having a separate file xhrHandler.py and route specific POST/GET requests to /xhr/methodname and then delegate the views.py methods to return the view passing along the httprequest for view processing.
Thoughts?

Check request.is_ajax() and delegate wherever you need. Sample handler:
def view_something(request):
if request.is_ajax():
# ajax
else
# not
You can now call different functions (in different files) for the two cases.
If you want to be fancier, use a decorator for the handler that will dispatch ajaxy requests elsewhere:
def reroute_ajaxy(ajax_handler):
def wrap(f):
def decorate(*args, **kwargs):
if args[0].is_ajax():
return ajax_handler(args)
else:
return f(*args, **kwargs)
return decorate
return wrap
def score_ajax_handler(request):
print "score ajax handler"
#reroute_ajaxy(score_ajax_handler)
def score_handler(request):
print "score handler"
And some mock testing to exercise it:
class ReqMock:
def __init__(self, ajax=False):
self.ajax = ajax
def is_ajax(self):
return self.ajax
score_handler(ReqMock(True))
score_handler(ReqMock(False))
Produces:
score ajax handler
score handler

Related

django-csrf protection on ajax post

I am working on django 1.7 and python 2.7. To prevent csrf attack on ajax post request i have added csrf token in ajax header before send.
In views i have added csrf_protect decorator to check the token. Everything is working fine in this scenario. But In my project this function in views.py is being called internally in other views where i haven't implemented csrf token, this causing 403 error.So what i want to do is only when there is ajax post call have to check csrf_protect decorator. Every other calls can neglect.
def check_token(func):
def wrapper(request, *args, **kwargs):
if request.is_ajax():
return csrf_protect(func(request,*args, **kwargs))
return func(request,*args, **kwargs )
return wrapper
#check_token
def myViews(request,mob,id):
"""function starts here"""
Your decorator is equivalent to
myViews = check_token(myViews)
You could apply it manually to a new name:
def unprotected_view(request,mob,id):
"""function starts here"""
...
protected_view = check_token(unprotected_view)
Now you have a decorated and a non-decorated name for it.
Calling views from within other views is not really what Django views are supposed to do. If you have some generic functionality to craft a response, make that a separate function. Then let your protected view call that function and your other views call it as well:
#csrf_protect
def my_view(request, mob, id):
return craft_generic_response(request, mob, id)
def craft_generic_response(request, mob, id)
# do stuff to create response
return response
def another_view(request, mob, id):
# do stuff
response = craft_generic_response(**kwargs)
# do more stuff

twisted render_GET redirect to function

I can't seem to find any documentation on how to use twisted.web.util.Redirect to redirect to another function.
For more information see below.
I have the following code:
class Login(Resource):
isLeaf = True
def getChild(self, name, request):
if name == '':
return self
return Resource.getChild(self, name, request)
def render_GET(self, request):
saml = SamlRequest(request)
print('redirecting to sso')
return Redirect(saml.sso())
class SamlRequest(object):
self.auth = OneLogin_Saml2_Auth(self.request, custom_base_path=settings_path)
def sso(self):
return self.auth.login()
I need to redirect to page login to the login function inside OneLogin_Saml2_Auth.
When I try to redirect as-is I receive the error
raise TypeError("Unicode object not allowed as URL")
Is there a way to accomplish this?
twisted.web.util.Redirect is a kind of Resource, not something you return from a render method. It's most suitable if you have a "static" redirect that exists in your URL structure and redirects to a fixed location.
If you want to write a custom resource that redirects to a dynamic URL, use twisted.web.util.redirectTo(url, request), which you can call from your render_GET method just like you tried to do with Redirect.

What is dispatch used for in django?

I have been trying to wrap my head around the dispatch method, particularly in Django. However, I cannot seem to figure out exactly what it does. I tried to gain an understanding from the Django docs but didn't find them to informative on this topic. Per my understanding it is a listener that listens to all events happening on a page but I am not sure if this is the case?
class OrderDetail(DetailView):
model = Order
def **dispatch**(self, request, *args, **kwargs):
try:
user_check_id = self.request.session.get("user_checkout_id")
user_checkout = UserCheckout.objects.get(id=user_check_id)
except UserCheckout.DoesNotExist:
user_checkout = UserCheckout.objects.get(user=request.user)
except:
user_checkout = None
obj = self.get_object()
if obj.user == user_checkout and user_checkout is not None:
return super(OrderDetail, self).dispatch(request, *args, **kwargs)
else:
raise Http404
The dispatch method takes in the request and ultimately returns the response. Normally, it returns a response by calling (ie, dispatching to) another method like get. Think of it as a middleman between requests and responses.
Normally, it simply decides what method in the class (e.g. get(),post(), etc) should be used (ie, dispatched) based on the HTTP method that was used in the request. Something like
def dispatch(self, request, *args, **kwargs):
if request.method == 'GET':
return self.get(*args, **kwargs)
elif request.method == 'POST':
return self.post(*args, **kwargs)
elif #... and so on
You can use your own dispatch method to change this behavior to call whatever methods you want that should return the HTTP response or even 'intercept' and modify the arguments that ultimately reach those methods. For example, you might use this to block/filter certain kinds of requests or even inject arguments...
def dispatch(self, request, *args, **kwargs):
"""Updates the keyword args to always have 'foo' with the value 'bar'"""
if 'foo' in kwargs:
# Block requests that attempt to provide their own foo value
return HttpResponse(status_code=400)
kwargs.update({'foo': 'bar'}) # inject the foo value
# now process dispatch as it otherwise normally would
return super().dispatch(request, *args, **kwargs)
But the key concept is that it's the entry point for requests and ultimately responsible for returning the response.
When a request url matches a url in your urls.py file, django passes that request to the view you specified. The request can only be passed to callable functions. This is why when using class-based views, you use the as_view() method. The as_view() method returns a function that can be called.
This function then creates an instance of the view class and calls it's dispatch() method. The dispatch method then looks at the request and decides whether the GET or POST method of the view class should handle the request.

Render Django view class to either string or response

I have a template that I want to be able to both serve directly and embed in arbitrary other templates in my Django application. I tried to create a view class for it that looks like this:
class TemplateView(View):
def get(self, request):
context = self._create_context(request)
return render_to_response('template.html', context)
def get_string(self, request):
context = self._create_context(request)
return render_to_string('template.html', context)
def _create_context(self, request):
context = {}
# Complex context initialization logic...
return context
I've wired get to my Django URLs. However, I haven't been able to figure out how to instantiate TemplateView so that I can call get_string from other views.
There must be a better way to go about doing this. Ideas?
Update: I've seen some folks talking about making a request internally and using response.content, which would save me from having to write the get_string method. So, perhaps a better question is: How do I make a request to TemplateView from another view?
I'd follow in django's CBV pattern: it determines via dispatch what method to return. By default based on request.method. Why not based on any other argument passed to dispatch()?
So subclass dispatch and give it a way to determine whether or not to return get_string.
def dispatch(self, request, *args, **kwargs):
if 'as_string' in kwargs:
return self.get_string(request)
return super(TemplateView, self).dispatch(request, *args, **kwargs)
response = TemplateView.as_view()(request, as_string=True)

Why don't Django and CherryPy support HTTP verb-based dispatch natively?

It's not the same to POST to an URL than to GET it, DELETE it or PUT it. These actions are fundamentally different. However, Django seems to ignore them in its dispatch mechanism. Basically, one is forced to either ignore HTTP verbs completely or do this on every view:
def my_view(request, arg1, arg2):
if request.method == 'GET':
return get_view(request, arg1, arg2)
if request.method == 'POST':
return post_view(request, arg1, arg2)
return http.HttpResponseNotAllowed(['GET', 'POST'])
The few solutions I have found for this in the web (this snippet for verb-based dispatch, or this decorator for verb requirement) are not very elegant as they are clearly just workarounds.
The situation with CherryPy seems to be the same. The only frameworks I know of that get this right are web.py and Google App Engine's.
I see this as a serious design flaw for a web framework. Does anyone agree? Or is it a deliberate decision based on reasons/requirements I ignore?
I can't speak for Django, but in CherryPy, you can have one function per HTTP verb with a single config entry:
request.dispatch = cherrypy.dispatch.MethodDispatcher()
However, I have seen some situations where that's not desirable.
One example would be a hard redirect regardless of verb.
Another case is when the majority of your handlers only handle GET. It's especially annoying in that case to have a thousand page handlers all named 'GET'. It's prettier to express that in a decorator than in a function name:
def allow(*methods):
methods = list(methods)
if not methods:
methods = ['GET', 'HEAD']
elif 'GET' in methods and 'HEAD' not in methods:
methods.append('HEAD')
def wrap(f):
def inner(*args, **kwargs):
cherrypy.response.headers['Allow'] = ', '.join(methods)
if cherrypy.request.method not in methods:
raise cherrypy.HTTPError(405)
return f(*args, **kwargs):
inner.exposed = True
return inner
return wrap
class Root:
#allow()
def index(self):
return "Hello"
cowboy_greeting = "Howdy"
#allow()
def cowboy(self):
return self.cowboy_greeting
#allow('PUT')
def cowboyup(self, new_greeting=None):
self.cowboy_greeting = new_greeting
Another common one I see is looking up data corresponding to the resource in a database, which should happen regardless of verb:
def default(self, id, **kwargs):
# 404 if no such beast
thing = Things.get(id=id)
if thing is None:
raise cherrypy.NotFound()
# ...and now switch on method
if cherrypy.request.method == 'GET': ...
CherryPy tries to not make the decision for you, yet makes it easy (a one-liner) if that's what you want.
Came across this from Google, and thought of updating.
Django
Just FYI, This is now supported in Django as class based views. You can extend the generic class View and add methods like get(), post(), put() etc. E.g. -
from django.http import HttpResponse
from django.views.generic import View
class MyView(View):
def get(self, request, *args, **kwargs):
return HttpResponse('Hello, World!')
The dispatch() part handles this-
dispatch(request, *args, **kwargs)
The view part of the view – the
method that accepts a request argument plus arguments, and returns a
HTTP response.
The default implementation will inspect the HTTP method and attempt to
delegate to a method that matches the HTTP method; a GET will be
delegated to get(), a POST to post(), and so on.
By default, a HEAD request will be delegated to get(). If you need to
handle HEAD requests in a different way than GET, you can override the
head() method. See Supporting other HTTP methods for an example.
The default implementation also sets request, args and kwargs as
instance variables, so any method on the view can know the full
details of the request that was made to invoke the view.
Then you can use it in urls.py -
from django.conf.urls import patterns, url
from myapp.views import MyView
urlpatterns = patterns('',
url(r'^mine/$', MyView.as_view(), name='my-view'),
)
More details.
CherryPy
CherryPy now also supports this. They have a full page on this.
I believe the decision for django was made because usually just GET and POST is enough, and that keeps the framework simpler for its requirements. It is very convenient to just "not care" about which verb was used.
However, there are plenty other frameworks that can do dispatch based on verb. I like werkzeug, it makes easy to define your own dispatch code, so you can dispatch based on whatever you want, to whatever you want.
Because this is not hard to DIY. Just have a dictionary of accepted verbs to functions in each class.
def dispatcher(someObject, request):
try:
return someObject.acceptedVerbs[request.method]()
except:
return http.HttpResponseNotAllowed(someObject.acceptedVerbs.keys())

Categories