GET requests to a POST handling view - django

I have a view intended to deal only with POST requests that starts with
user = User.objects.get(username=request.POST['name'])
Do I need to ensure the view is not invoked with a GET request? Not sure if I'm thinking about good practice/security-type things or being OCD.
I'm using the #require_POST decorator because invoking the view with GET results in "Key 'name' not found in <QueryDict: {}> and a 500 error.
I suppose the only chance of this happening is if a user looked at the HTML of the page and for some reason thought to try the action attribute of the form in the address bar -which seems unlikely.
I've tried this myself with a couple of sites and got a error page, rather than a blank page with 405 error that #require_POST gives me.
Perhaps it's good practice to guard against GET requests in case a template designer mistakenly makes a hyperlink to my view or forgets method="post"? (In which case, I suppose I should use get_object_or_404 above)
I assume adding #require_GET to views that are only designed to deal with GET requests is unnesessary?

It seems like you understand why you would want to use #requirePOST. Another option, if you did not want to cause an error on GET, is to use something along these lines:
def view(request):
if request.method == 'POST':
..code for post..
else:
*redirect, or other code*
As to whether or not you need to use #requireGET, the only way it could hurt is if you need a view to perform both GET and POST. ie a form that causes action on POST, but is simply displayed for the user on GET. But if you are requiring GET then there should not be anything in the view that could be compromised via a POST.

Do I need to ensure the view is not invoked with a GET request? Not
sure if I'm thinking about good practice/security-type things or being
OCD.
Yes. I think you touch on answering your own question. your view requires request.POST a get request errors. If you wnat to create bug free code you will ensure that no get requests access this view. Django provides a convenient, pythonic, decorator to do this. I don't think you are being OCD at all. Also, I don't know how expensive it is to trigger an error in production (emails you, logs it, etc) but that is something to consider.
I suppose the only chance of this happening is if a user looked at the HTML of the page and for some reason thought to try the action
attribute of the form in the address bar -which seems unlikely.
I dont think it matters HOW a user could make a GET request to this, i think it only matters that this view MUST be a post request.
Perhaps it's good practice to guard against GET requests in case a
template designer mistakenly makes a hyperlink to my view or forgets
method="post"? (In which case, I suppose I should use
get_object_or_404 above)
In this case i dont' think thinking about the many ways a get request could be made to this view is important. The important part is it REQUIRES a Post request. You can use the tools at your disposal to ensure that all requests entering the function are post requests.
One thing is, name is not assumed. You could still get a KeyError. Even though you are ensuring that the request is POST you can't ensure that the post request will have a parameter name
that is why get is used so frequently
if not request.POST.get('name'):
# raise some sort of error?
user = User.objects.get(username=request.POST['name'])

Related

Connecting two views in Django

I want to make sure that my visitors (not authenticated users), are unable to visit a particular view without coming directly from a "previous view". I've kind of had to manually create a form preview and confirmation state. It's the step between submission and preview, and preview and confirm I'd like to "secure".
form submission-view -> preview-view -> confirm-view.
Is there some way that I can create a unique hash, POST it, and check if it's correct, or somewhat generate a cookie, session — or anything else that feels clever?
I'm a Django beginner (programming beginner in general) and any snippets' or pointing me in a right direction would be very much appreciated!
Thanks.
There are at least two ways you can accomplish this that I can think of:
One would be to include a hidden field in your form or querystring value that contains your hash/unique that you want to pick up in the next view. If it's not there, or incorrect, redirect.
Another would be to check the referring url from the request.META to see if they've come from the view you want them to come in on first, and save a session value from the form submission to carry through the rest of the views. If it's not there, redirect. If the referring URL isn't what you expect, redirect.
Whether you use a cookie, session, querystring parameter or hidden form post, it's all doing the same thing - validating a value exists. Whatever method works best, is what makes the most sense for you as the developer and most likely maintainer of said app.

Should I use Middleware or write a decorator for this?

I have a situation where a user will be asked to enter their postal code, once they do then they are redirected to the site with content relevant to the postal code they've entered in. There will be categories etc. In a nutshell, the user will see content only relevant to their area.
PLAN --
I want to store their postal code in a cookie and re-use it every time they come back to the site, of course if there is no postal code they should be directed to enter it in a form. The form will be presented before any other content will be.
My questions are should I use a decorator for this and decorate the views with a custom decorator? Or should write middleware? if I write a custom middleware for this should I use process_request process_view, it seems to me process_request gets called on EVERY request, this may pose a problem.
Thanks!
JeffC
If you want to avoid repetition, you'll need to write a middleware. If it's on EVERY page as you say, and the ZIP code is a prerequisite for using the site, then having a middleware call process_request on every request isn't necessarily a bad thing.
On the other hand, is this necessary? Couldn't your URLs just read like: /blah/12345/videos/? Then instead of having to rely on a cookie for a bookmark, your users can just remmber that page. That would negate your having to write a view, as well.
The main question here is how often will you need to use the ZIP code from the cookie. Will it affect the whole site? Or only one part of it?
If the "ZIP-oriented" content will be used only in one part (one or more, but not the whole application), then go for the decorator. It should check for the cookie and if it's not present - redirect to the ZIP selection form. If it's present - continue processing the view in which you will be able to access the ZIP code and use it accordingly.
If the ZIP code is really going to affect the majority of your service and you don't want to decorate every single view - you can go for the middleware. But you are right - it will be called on every request, so be sure it's absolutely necessary.

Django add contrib.messages from custom middleware

I have implemented a custom middleware that check for certain fields in a user's profile. The fields are not required at sign up (in order to make it quick and easy for a user to sign up), however, I would prefer that they fill them out.
My middleware checks if they are set. If not, it notifies the user via a message. I ran into two problems.
Whenever I submit a posted form, because no template displays the messages, the middleware would add the message a second time since the middleware was called when the message was posted and after the redirect it was called again.
I solved this problem by iterating through the messages in my middleware and checking if the message I am about to add is already in there. If yes, it doesn't add it again.
When a user fixes the problem by updating their profile, on the very next page load, the messages are still there. After that though, everything works. At the beginning of my middleware, I actually put a check that returns None if the request was posted (I would have thought this would solve both problems, but it didn't solve either).
Any idea how to solve the 2nd issue? Is there a better way to solve my first one?
Thanks.
Edit:
Is there a way to clear the messages in a view? I've tried iterating through them (without storage.used=False) and they are still there. I would expect that this would solve both my problems.
Yoy can use sticky messages of https://github.com/AliLozano/django-messages-extends that is one storage that only keeps messages in request instead save in session
So, are you using django.contrib.messages to store permanent notices? It's intended for showing one-time notifications, where the user sees the message once and then it goes away. The type of things it's meant for are messages like, "Form edited successfully."
As far as getting rid of messages in a user's message stack are concerned: any time you use a RequestContext (discussed here) to render a template, all messages will be flushed (whether they are actually shown on the page or not).
I'm not totally sure this is the answer you're actually after, and I'm a bit confused by your question. However, I'm somewhat sure you're using messages outside its intended purpose, which is likely why you're running into trouble.
You could use process_reponse() method of Middleware to add the message. By that time, you would know whether to show the message to user or not depending on whether his profile now has the field filled in.
Consider using django.contrib.messages. May be you do not want to show "fill in the XYZ field" message on all requests, but only on few pages, say whenever user logs in or views his profile page.
Just place logic that creates messages to context processor instead of middleware. Modify request and return empty dict.

How to override/update information from POST when creating model

I have a view that handles a POST request and attempts to create a new object. However, I know that some of the POST'd data is invalid... But I want to fix it and go ahead and create the object.
The only way I can figure out to be able to 'fix' data in a ModelForm is to create a 'is_valid()' form. To do this, I can either create the form with the POST data, or I can create it with an already existing instance. Unfortunately, if I use the POST data, because some of it is invalid, the form won't validate and I am thus unable to get to the data in the form to fix it. If I create it with an already existing instance, this works, but when the form is displayed, any remaining errors are for whatever reason ignored (and thus don't show up on the web page.) I've tried a combination of creating the the Model form from the POST data and giving it an instance, but this doesn't seem to help. Additionally, I've tried modifying (a copy of) the POST data, fixing it, and then creating the ModelForm from the 'fixed' POST data. This sort of works, with the exception that I have some ImageFields in my form, and they seem to just be ignored.
Any help would be greatly appreciated. I have looked at every good page that I can find to no avail.
Perhaps there is a better way to do this? The problem I'm trying to solve is that I want to have a model that contains ImageFields. The first time I put up the form, the user needs to 'upload' images for each of the fields. However, if he doesn't update an image for one of the fields, I want the new form to come up with a Image upload button on the fields where images have not been uploaded, and just a text field with the image name for images that have been uploaded.
Edit 9/15/2010:
Ok, I think I can simplify all of the above question into this:
def testing( request ) :
test_form = UserProfileForm()
valid = test_form.is_valid()
return render( 'testing.tmpl', locals(), request )
When the above code is rendered, the 'valid' shows as False (as one might expect), but the 'test_form' renders without any errors. I've read through (if perhaps not understood?) the documentation on Models and ModelForms, and I see that most of the time a ModelForm (in my case: UserProfileForm) is created with a specified 'instance'. However, 1) I don't have an instance yet, 2) I would still expect the non-instance'd Form to display errors. I'm sure there is something I am missing. Please illuminate. :)
One more thing, which perhaps the answer to the above will answer anyway, but as far as I can tell, the is_valid() call is supposed to call the 'clean()' function I defined for the UserProfileForm. However, (not being a python guru) I placed 'raise ValidationError()' at the top of clean(), and when I run the code, no error is shown. Thoughts?
Update: I figured out the problem and the answer is below. Thanks!
You should have a look at how to clean form fields in django. You could either manipulate the data returned from the form there or make any kind of validation!
If your ImageFields are optional then you can still validate them (that they are otherwise correct).
Then it's a matter of adjusting your template to show either the uploaded file name or an file upload field depending on whether they've already uploaded one or not. Actually, it would probably be better to give them both fields in the first case. That's what the automatic admin does (the upload field is labeled "Change").
Well, after figuring out how to use the python debugger (pdb) and the fact that within emacs it kind of 'just works' (wow!?) I was able to find that my (empty) form was not bound. Googling bound forms pointed me to this page:
http://docs.djangoproject.com/en/dev/ref/forms/api/
RTFM'ing I find that I can pass an empty dictionary to my form and then everything starts to behave as I would expect. So, to summarize, there is a big difference between:
test_form = UserProfileForm()
and
test_form = UserProfileForm( {} )
The second version causes the rendering of the form to show all the errors (and to call 'clean()').
With risk of having this deleted by the moderator ;) Thank you to all those who commented and for your patience with a new django developer.

where do functions that don't display go in django

I have some links on an html page like , , currently I handle them as so
<p> rate down
and have a url.py entry:
(r'^cases/(?P<case_id>\d+)/case_rate/(?P<oper>.)$', 'mysite.cases.views.case_rate'),
then I have a view function that handles the logic and hits the DB, then does this:
return HttpResponseRedirect(request.META.get('HTTP_REFERER','/'))
I's there a better way to do this? I can see how this would be OK because it does have to redraw the screen to show the new rating...
The typical way to handle this is with an ajax request.
Instead of a link, you put a javascript handler that calls a view, wich updates the db, and returns a json / xml object with the new rating for the item. Then another javascript handle receives that response and updates the rating number on the screen, without a page reload.
Ideally, you'll keep both versions: plain html (the one you currently have) and the ajax one. The ajax one can be attach to the element after page load, so if javascript is not available, you'll still have a working site.
Then, regarding organization, you can have an "ajax" parameter on your view. The view should update the db accordingly, and if it's an ajax call, return the json / xml response, otherwise, return the new page. That way you can keep the logic (fetching the object, updating the db) on one place.
If you're asking whether case_rate should still go in the views.py given that it returns a redirect rather than providing content, the answer is yes, since case_rate is handling an request and returning a response.
But consider a situation where you had two view functions in views.py that had some duplicate code, and you chose to factor that duplicate code into another function that didn't both take request and return a response. Would that be fair game to leave in views.py? Sure, if moving it elsewhere would make the code harder to read. Or you might choose to put it elsewhere. It's really your call based on your sense of taste.