Example from Django documentation:
def index(request):
return HttpResponse('<h1>hellworld!</h1>')
def detail(request, question_id):
return HttpResponse("Question: %s" % question_id)
Since the request argument is never used, why should I include it in each function signature?
The purpose of a web server is to reply to HTTP requests (In simple terms). Django being a web framework generates responses depending on the request that it receives.
The business logic of handling the requests is done by Django Views, it is their purpose. This is why Django supplies the request to the view function, so the code can access the request data and choose what actions it should take and which response it should send back (even though that specific view doesn't make use of it).
The decision of requiring the view to receive the request as an argument is an implementation decision made by Django developers, making it part of the interface the view has with the rest of the "system". Other frameworks might choose making it available globally and not suplying it to the views/controllers directly, but the merits of one or another approach is other discussion.
Many of the examples in Django's documentation (and any documentation, really) are necessarily contrived. They're simple because the complexity of a real example would take away from the point that's being made.
In real use cases, you'll frequently want access to the request object. You may want to know which User is attached to the request (request.user) or whether the request is a GET or a POST (request.method).
You can also inspect the headers (request.headers), decode the JSON object sent with a POST request (json.loads(request.body)), etc.
Those are just examples. In real world a programmer would want to find request GET arguments, decode JSON POST body, inspect headers, get user or session data, etc.
Related
"Accessing request.POST inside middleware before the view runs or in process_view() will prevent any view running after the middleware from being able to modify the upload handlers for the request, and should normally be avoided."
This is from the django documentation. First of all, if I just read the POST, without changing that, how does it even know and how does it prevent the view from doing it's business and second, how is a CsrfViewMiddleware different in that sense?
The warning comes from this ticket and this.
Django currently parses the POST data lazily, but middlware might try to access POST on a request and trigger parsing, even though the function itself never touches POST.
That would put high load on the machine if the POST data is rather large ...
It means that the view will be unable to set any custom upload handlers, perform custom parsing of the request body, or enforce permission checks prior to file uploads being accepted.
And the difference about CsrfViewMiddleware is stated clearly right below the said warning in the docs:
The CsrfViewMiddleware ... provides the csrf_exempt() and
csrf_protect() decorators which allow views to explicitly control at what point the CSRF validation should
occur.
Short version: On a django site, I can grab values from request.GET but not request.POST in response to a request from Twilio. I suspect it has something to do with csrf, but I'm not really sure how to debug the problem. Details below.
Long version:
I am helping a friend with a project where we are running a medical survey over SMS using the Twilio REST API. I had a domain and a very bare-bones django-built site on that domain, which I had built really just to better familiarize myself with django, so we're using that.
We're collecting SMS responses to our survey and as part of the Twilio API, it sends any response to our number to a url specified under the account, so we have the response targeting something like the following:
...mydomain.com/some_page/another_page/
The Twilio request then looks something like the following:
...mydomain.com/some_page/another_page/?AccountSid=###SOME_LONG_ACCOUNT_SIDE&From=%2BPHONE_NUMBER&Body=bla+BLA+bla+BLA&SmsSid=##MESSAGE_ID_KEY&SmsMessageSid=##MESSAGE_ID_KEY&FromCity=Santa+Cruz&FromState=California...
Working Code
I am testing that the incoming request has our AccountSid inside it (compared with the value in the database) and in my views.py for the app, I have something that looks like the following (and this works):
from our_app import TwilioAccount
our_account = TwilioAccount.objects.get(id=1)
def twilio_response(request):
assert request.GET.get('AccountSid', None) == our_account.account_sid
## log the incoming request to the database under survey responses...
Non-Working Code
If I log-in to our Twilio account and switch the request method to POST, and then I switch all of my data collecting to request.POST, the above assert statement fails. Further debugging reveals that my QueryDict is empty under POST, POST: {}, so there is no key value grabbed.
I thought this maybe was because POST under django requires a csrf_token, but I figured checking for the AccountSid was fairly good, so I imported csrf_exempt and wrapped the above function with that:
#csrf_exempt
def twilio_response(request):
assert request.POST.get('AccountSid', None) == our_account.account_sid
## log the incoming request to the database under survey responses...
AssertionError: ...
This does not work with the exact same request: the QueryDict is empty.
Questions:
1) Is there something else I need to do to make my #csrf_exempt work? Alternate question: is this a terrible and dumb way to do this? How do people usually satisfy this requirement when working with other company's APIs and not actual, logged-in users?
1a) Instead of making it csrf_exempt, I could just keep it as a GET request, knowing that it's still checking all incoming requests against our account_sid. Should I do that or is that a really naive way to do it?
2) I am eager to learn the best way to do this: should I build a django form and then route the request to my form and test validity and clean the data that way? If so, can anyone give me a loose outline on what the view/form would look like (complete with csrf_token) when there's not going to be a template for the form?
Matt from the Twilio Developer Evangelist team here.
1) Wrapping your twilio_response function with #csrf_exempt to remove the Django CSRF token check is the right way to go here. Twilio does not generate a Django CSRF token. Instead, there are other ways to validate POSTs are coming from Twilio, such as signature validation with the X-Twilio-Signature header. See the Twilio security docs for details.
1a) Using the GET request is convenient for testing and debugging, but POST should be used in production. GET requests do not have a body according to the HTTP spec, so the results are passed in the query string. If the parameters are too large, for example with a text message that has a maximum length of 1600 characters, the query string in the URL could exceed the maximum length of a URL and potentially cause issues when you handle the string.
2) Django forms are a good way to go for this use case, particularly a ModelForm that leverages your existing Model used to save the response. For example, your ModelForm could
look something like the following if you are saving your data to a TwilioMessage model:
from django.forms import ModelForm
from .models import TwilioMessage
class MessageForm(ModelForm):
pass
class Meta:
model = ReactionEvent
# include all fields you're saving from the form here
fields = ['body', 'to', 'from_', 'signature',]
In my option,Have you open DEBUG(= True) in settings.py?
And in the DEBUG mode, you can raise An Exception(raise Exception('')),And then you can see the Environment Varialbe like url, GET,POST.etc....in you page
OR return HttpResponse(request.POST.dict())
to see the post variable.
use crsf_exempt is a right way when post
Recently I've started converting some of the view functions to Generic Views.
Converting the function which was expected to handle POST request (via AJAX form) results in "405 Method not allowed" HTTP exception.
I'm sure is not about CSRF: Ajax sends valid token, changing the generic view back to view function (in the test case, they're essentially the same) fixes the problem, and - lastly - for testing purposes, I've disabled CSRF middleware.
Did anyone experienced similar problems?
I suppose you are using class-based views. If so then you need to define post method in your view or use mixin which does it (django.views.generic.edit.ProcessFormView for example). If you want to fully understand why this is necessary then look at dispatch method of django.views.generic.base.View.
I'm using python to develop a web app.
I defined both "get" and "post" method in the same request handler to serve different purpose. That is, I use "get" method to present a form to user, and "post" method to handle the submitted form.
It works fine, but is this approach appropriate? Or should I better define get and post separately in different request handler? Thanks!
Your approach is appropriate. According to the newest documentation you can even define post and get as functions outside request handler and just as other functions in your module and that's a way I would choose since it eliminates problems that can happen when instanciating request handlers.
If starting a new app from scratch I probably would try to put my get and post function outside of request handler with the new python 2.7 runtime that according to docs supports that.
The behavior I propose:
A user loads up my "search" page, www.site.com/search, types their query into a form, clicks submit, and then ends up at www.site.com/search/the+query instead of www.site.com/search?q=the+query. I've gone through a lot of the Pylons documentation already and just finished reading the Routes documentation and am wondering if this can/should happen at the Routes layer. I have already set up my application to perform a search when given www.site.com/search/the+query, but can not figure out how to send a form to this destination.
Or is this something that should happen inside a controller with a redirect_to()?
Or somewhere else?
Followup:
This is less an actual "set in stone" desire right now and more a curiosity for brainstorming future features. I'm designing an application which uses a Wikipedia dump and have observed that when a user performs a search on Wikipedia and the search isn't too ambiguous it redirects directly to an article link: en.wikipedia.org/wiki/Apple. It is actually performing an in-between HTTP 302 redirect step, and I am just curious if there's a more elegant/cute way of doing this in Pylons.
You can send whatever content you want for any URL, but if you want a particular URL to appear in the browser's address bar, you have to use a redirect. This is independent of whether you use Pylons, Django or Rails on the server side.
In the handling for /search (whether POST or GET), one would normally run the query in the back end, and if there was only one search result (or one overwhelmingly relevant result) you would redirect to that result, otherwise to a page showing links to the top N results. That's just normal practice, AFAIK.
HTML forms are designed to go to a specific URL with a query string (?q=) or an equivalent body in a POST -- either you write clever and subtle Javascript to intercept the form submission and rewrite it in your preferred weird way, or use redirect_to (and the latter will take some doing).
But why do you need such weird behavior rather than just following the standard?! Please explain your use case in terms of application-level needs...!