Django add contrib.messages from custom middleware - django

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.

Related

django form sends empty request on IE - weird error

So I have built a site on my workplace network using django and deploying it with wamp. I don't have a direct connection from my workplace to the internet so I can't show any actual code (not without taking some time to print and rewrite everything).
Now ever since I deployed the site I have been facing one of the worst and weirdes bugs I have ever encountered. It happens only on IE and not even all the time.
what happens is I created a modelform (I added a few lines to make it nicer, but nothing complicated that I couldn't handle on the validation part), and just put it in a template as is. I have added a csrf token and everything seems to be in order.
That is until you click on sending the data. That's when he sends - for some reason, a completely empty request. I don't mean he sends an empty form - he sends a request without any data at all. First I thought it had something to do with the jquery UI I have (just for adding dates), or the csrf going weird but ommiting them didn't change anything (as in, when you omit the csrf token and middlewere it acts as if you sent an empty form, but when it's enabled it acts as if the csrf caught an exeption - because an empty request means no value for the csrf hidden field).
I actually used wireshark and caught the error and ... that's it. I'm no closer to solving it. I tried everything, from changing the page to quirks mode, to rewriting all the html to writing several different template versions just to see what happens.
And It's driving me insane becuase this doesn't even happen all the time. I know I mentioned that already but I just can't make any sense of it. And before you ask - no, it's not an option to use a different webbrowser because all the web-apps my company uses are fit to work with IE and most people here are not technological enough to use multiple browsers.
one more important thing that might help - the bug almost always happens the first time you visit the page (or when you open it in a new tab). If, say, you already went back and forth a few times in the same tab, it usually works fine. we're using IE8, on windows xp computers. Any help would be extremely appreciated, thanks!

GET requests to a POST handling view

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'])

getting the template name and the time it takes to render in a middleware based on a url

I want to write a middleware that would tell me the name of the template being rendered and the time it took, for the database queries for that particular view.
Django Debug Toolbar does the same, but due to custom request and response object written i am not able to get that working.
So i thought of writing a custom middleware that would do the same for me on a url appended with some get request variable.
Say 127.0.0.1/index/polls gives me all the polls.
If i try 127.0.0.1/index/polls/?my_tool it would invoke a url, and i would get the data.
Any suggestions on how to implement it? Is there a working example?
I could infer that you need some debug tool for development, in that case I would suggest django-debug-toolbar, otherwise, if you really need the middleware you always can look at the code of django-debug-toolbar. :)
If I´ve got to write that by myself, I would write a couple of classes (in debug toolbar are called panels) that inherits from template and timer, and override the method process_response for log or print the info that I need.
Even you can look into the middleware of debug-toolbar and picture an idea of how it works

POST without Redirect/GET?

A coworker of mine was working on preventing duplicate form submissions (on a successful submission, we are emailed and a DB entry is created). Submissions are not successful if there are errors on the form.
I was reviewing his code, and I noted that he only used P/R/G on a successful submission. The form submission would still be duplicated on a refresh/revisit if it were not successful. I noted this in my review, but he argued that he didn't see a benefit to redirect every time because the unsuccessful submission is ignored. I noted that if a user refreshes the page or revisits it in history, they will still get a "CONFIRM FORM RESUBMISSION" warning in major browsers.
Is this enough of a reason to redirect after each POST? Whether or not it is, is there any other reason to redirect after a POST even if the submission is idempotent (due to errors in the form)? Is there ever a reason that you should not redirect after a form submission?
The main reason is due to every modern browser's obnoxious dialog box that opens when you hit the "Back" or "Reload" button (and people do - often, whether you want them to or not) after a POST operation, warning you that a POST re-submit is about to take place. I certainly understand why they chose to do this, but it does mean that as programmers we go to great lengths to ensure that a user doesn't have to ever see the message.
So, I disagree with those who say there is no reason to redirect after an unsuccessful post. Theoretically there shouldn't be one, yes, but due to user interface issues with browsers, yes, absolutely you need to.
There is no reason to redirect after an unsuccessful POST. Repeating it won't do any harm and it makes your life easier since you do not need to store all form values in the session for re-filling the form.
Besides that, during development it makes thing much easier especially when using a file upload field since you can just make the form submission always fail and then hit F5 until all your validation code etc works fine.

Django: How to change to success message for update_object?

I'm using the django messages framework for user notifications and update_object to handle saving of forms. When a form is successfully posted the default message is [MyModel] successfully saved or similar.
I want to change this message to a custom one ("Your changes were saved"), either for all form posts or for every use of update_object.
Is this possible?
Thanks!
I am assuming that you are talking about the update_object generic view.
If that is the case then there is no way (hook) to change the success message at present (Django 1.2.3). You can see this for yourself in the source code. Just look for update_object.
One rather flaky way to do this would be to use a custom post_save_redirect and render the message yourself. The post_save_redirect can be a simple view to display the appropriate success message. This will mean losing the redirection to the object's permalink though.
You can also try adding a custom message (using messages.success) and then redirect to the saved object's permalink in the wrapper. I haven't tried this myself so I do not know how this will turn out.