I have a similar problem to those listed in
Django produces blank pages when POST data is sent and Models are accessed
and
Nginx connection reset, response from uWsgi lost
Here is one of the views in question:
#transaction.commit_on_success
#occ_update
#checks_status
def hold(request):
if not request.user.has_perm('orders.hold'):
return error_response_rollback(NO_PERMISSION_MSG % "hold orders")
order = Order.objects.get(pk=request.POST.get('pk'))
occ_revision = int(request.POST.get('occ_revision'))
agent = Agent.get_agent(request.user)
action = Action(agent=agent, type='hold_order',
comments=request.POST.get('comments'))
action.save()
order.hold(action, occ_revision)
return ok_response_commit("Order held successfully.")
error_response_rollback rolls back the transaction and returns an HttpResponse with JSON as its contents.
I am adding permission checking to many of my views in my application and when the user does not have the correct permission, a blank response is returned.
However like the questions referenced above, if you put a
print request
or
request.POST
statement BEFORE the permission check, the NO_PERMISSION_MSG JSON string is returned to the browser correctly every time (error_response_rollback returns an HttpResponse object with JSON in it.)
You get blank responses when you check permissions before the "print request" and they do not have the correct permissions.
You do NOT get blank responses when:
the user has the correct permissions
a "print request" statement is before any permission check
you use Firefox at any point.
The #occ_update and #checks_status decorators just catch exceptions. These problems occur with and without them present.
I'm developing in Chrome and none of this is an issue in Firefox.
One page I found suggested overloading the WSGIRequest object to read the request before it is passed to the view but this seems icky to me and I'd rather find out the real solution.
Does anyone know of any fixes/settings to the runserver command to help this issue without hacking on the request? My users are primarily using Chrome so I'd prefer to keep using it... we'll see. Currently developing in Windows using Django 1.3.1
One option I have considered is making another manage.py command to handle this but that, too, seems icky.
Thanks
Update:
I have been able to re-organize my code so that any permission checks happen after some bit of data is read from the POST. This seems to have eliminated any symptoms of this problem. It's still not ideal but it is a good alternative to inserting middleware to read the post. and won't always be possible in all applications.
Please comment if you have a similar situation and just can't figure it out.
As saying in the second link in your post, especially http://forum.nginx.org/read.php?2,196581 : when you works w/ Nginx and uWSGI and get a non-empty POST, always read the request.POST before return an HttpResponse. The reason is described in the link.
You don't have to override an handler, just put the request.POST line before the return code, or inside some decorator or middleware.
I encountered this issue for production site half a year ago and put the line in a middleware to solve it.
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.
I am in the midst of writing a web app in CherryPy. I have set it up so that it uses OpenID auth, and can successfully get user's ID/email address.
I would like to have it set so that whenever a page loads, it checks to see if the user is logged in, and if so displays some information about their login.
As I see it, the basic workflow should be like this:
Is there a userid stored in the current session? If so, we're golden.
If not, does the user have cookies with a userid and login token? If so, process them, invalidate the current token and assign a new one, and add the user information to the session. Once again, we're good.
If neither condition holds, display a "Login" link directing to my OpenID form.
Obviously, I could just include code (or a decorator) in every public page that would handle this. But that seems very... irritating.
I could also set up a default index method in each class, which would do this and then use a (page-by-page) helper method to display the rest of the content. But this seems like a nightmare when it comes to the occasional exposed method other than index.
So, my hope is this: is there a way in CherryPy to set some code to be run whenever a request is received? If so, I could use this to have it set up so that the current session always includes all the information I need.
Alternatively, is it safe to create a wrapper around the cherrypy.expose decorator, so that every exposed page also runs this code?
Or, failing either of those: I'm also open to suggestions of a different workflow. I haven't written this kind of system before, and am always open to advice.
Edit: I have included an answer below on how to accomplish what I want. However, if anybody has any workflow change suggestions, I would love the advice! Thanks all.
Nevermind, folks. Turns out that this isn't so bad to do; it is simply a matter of doing the following:
Write a function that does what I want.
Make the function in to a custom CherryPy Tool, set to the before_handler hook.
Enable that tool globally in my config.
Problem
UPDATE: This issue, it turns out, has little to do with the #login_required decorator!
I am getting finicky behavior when I try to test views that are decorated with #login_required.
I have one test that is actually able to go to a view decorated with #login_required (a password change view). A different test, however, always gets redirected to login. No matter which way I've tried to re-write it, it won't let my test user through, even though I am logging the user in and asserting that user.is_authenticated() beforehand.
Here's the relevant snippet of the test that's having issues:
# Log user in
self.client.login(username=user.username, password=user.password)
self.assertTrue(user.is_authenticated())
# Go to account_edit view
url = reverse('account_edit')
response = self.client.get(url)
self.assertEqual(response.status_code, 200)
self.assertTemplateUsed(response, 'users/account_edit_form.html')
This inevitably redirects to the login view, as if the user were not logged in.
I can confirm that this behavior is not reflected in the "normal" functioning of the app; the decorator works exactly as expected when I actually run the server and then navigate to this view (i.e. it allows access when logged in, and redirects to login view).
Using Django 1.3.1. I am using the testrunner from django-nose, but I can confirm that this issue happens regardless of which testrunner I use.
Also, I found several previous questions, but the solutions suggested were either particular to older versions of Django, or not helpful in this case (see here for example).
Solution (combining two good answers)
I received two very good answers to this question, both of which highlighted important oversights in the snippet I posted. The issue had nothing to do with #login_required's behavior, and everything to do with (a) signing the user in wrong and (b) checking the user authentication wrong.
I was having a hard time picking which answer to accept, but after a little thought, I've decided to accept Konrad Hałas's answer, since it pinpoints the crucial oversight on my part, that was the root of unexpected behavior.
Nonetheless, I would have figured this out much sooner if I had not been using the faulty test line self.assertTrue(user.is_authenticated()). So to emphasize that the solution was actually two parts, here are the two steps to fixing the problematic code:
# Log user in *NOTE: Password needs to be raw (from Konrad's answer)
self.client.login(username=user.username, password="pass")
self.assertTrue(user.is_authenticated()) # <-- still not correct
The assertion line is still faulty because a valid user always satisfies user.is_authenticated(). See Alasdair's info for an explanation of this gotcha. So step two of fixing this code is:
# Log user in *NOTE: Password needs to be raw (from Konrad's answer)
login_successful = self.client.login(username=user.username, password="pass")
self.assertTrue(login_successful) # Much better! (see Alasdair's answer)
Finally, should you need to test that your user was logged in without using client.login (i.e. testing a login form), this should work:
self.assertTrue(response.context['user'].is_authenticated())
user.password is password hash. You can't log in with it. You need to use original password:
self.client.login(username=user.username, password='<user password>')
The gotcha here is that the is_authenticated method always returns True for a User instance.
In the template or view it can be useful - if request.user.is_authenticated() is True, then you have a real user, not an AnonymousUser, and can proceed accordingly. However, if you start off with a User object, as you have done, then is_authenticated() can be confusing!
You can check the return value of the test client's login() method to test whether it was successful.
login_successful = c.login(username='fred', password='secret')
self.assertTrue(login_successful)
I want to show various messages to registered users only once in my django application. I found django-announcements which seemed to do what I want - but I found in testing it marks messages as read by using a session variable, which disappears if the user logs out. This means a message is shown again to a user if they dismiss it when logged in, log out, and then log in again.
I wondered if anyone know of an application that I might be able to use here without re-inventing the wheel.
Have a look at django-notification. It is used by pinax, there it seems to work like what you are searching for. At least it saves the status in the db.
edit
Response to the comment
from the docs:
notification.send([to_user], "friends_invite", {"from_user": from_user})
so this should work:
notification.send(Users.objects.all(), "friends_invite", {"from_user": from_user})
and if a queryset isnt right:
notification.send([u for u in Users.objects.all()], "friends_invite", {"from_user": from_user})
Have you looked at the Messages Framework in Django 1.3? In Django <=1.2 it was a simple model so you could do:
for user in User.objects.all():
user.message_set.create(message="some text")
and this would be rendered in the template, and dismissed as soon as the next page is loaded (it's what Django admin uses). It has changed a bit in 1.3, but it might be handy, but not 'dismissable' in the way that maybe you want.
Does anyone have any simple code samples for Django + SWFUpload? I have it working perfectly in my PHP application but Django is giving me headaches.
Unfortunately I can't give you any very detailed code samples, but I have quite a bit of experience with working with SWFUpload + Django (for a photo sharing site I work on). Anyway, here are a few pointers that will hopefully help you on your quest for DjSWF happiness :)
You'll want to use the cookies plugin (if of course you are using some sort of session-based authentication [like django.contrib.auth, and care who uploaded what).
The cookies plugin sends the data from cookies as POST, so you'll have to find some way of getting this back into request.COOKIES (process_request middleware that looks for a settings.SESSION_COOKIE_NAME in request.POST on specific URLs and dumps it into request.COOKIES works nicely for this :)
Also, remember that you must return something in the response body for SWFUpload to recognize it as a successful upload attempt. I believe this has changed in the latest beta of SWFUpload, but anyway it's advisable just to stick something in there like 'ok'. For failures, make use of something like HttpResponseBadRequest or the like.
Lastly, in case you're having trouble finding them, the uploaded file is in request.FILES :)
If you have anything perplexing I haven't covered, feel free to post something more detailed and I'll be happy to help.
Django version of the samples for SWFUpload:
http://github.com/naltimari/django-swfupload-samples/tree/master
So long uploadify. Great idea but it is just buggy, especially on Windows.
The following is my Django-specific implementation for fixing this issue (i.e. my uploads were failing in Firefox with a 302 Redirect).
In my initial view that generates the page with the uploader on it, I looked at the cookies and found sessionid
ipdb> self.request.COOKIES
{'csrftoken': '43535f552b7c94563ada784f4d469acf', 'sessionid': 'rii380947wteuevuus0i5nbvpc6qq7i1'}
When I looked at what was being posted in the SWFUploadMiddleware (when using Firefox), I found that the sessionid was not being set.
In my intial view that generates the page that contains the upload handler, I added the sessionid to the context.
context['sessionid'] = self.request.session.session_key
In my swfuploader settings, I added sessionid to the post-params option as follows:
post_params: {... "sessionid": "{{ sessionid }}" ...},
Now, when I looked in the SWFUploadMiddleware, I could see the sessionid being posted, and my uploads started working if Firefox.
ipdb> request.POST
<QueryDict: {... u'session_id': [u'rii380947wteuevuus0i5nbvpc6qq7i1'],...}>
For completeness, my SWFUploadMiddleware looks like this...
from django.conf import settings
from django.core.urlresolvers import reverse
class SWFUploadMiddleware(object):
def process_request(self, request):
if (request.method == 'POST') and (request.path == reverse('upload_handler')) and request.POST.has_key(settings.SESSION_COOKIE_NAME):
request.COOKIES[settings.SESSION_COOKIE_NAME] = request.POST[settings.SESSION_COOKIE_NAME]
# http://stackoverflow.com/questions/6634666/403-forbidden-error-on-swfupload-and-django
# Fix for problem uploading images (403 error) in Firefox 20 and others
if request.POST.has_key('csrftoken'):
request.COOKIES['csrftoken'] = request.POST['csrftoken']