Django block request - django

I have a problem with my website. there it is :
No problem in this case :
User A do a request.
Django server update data...
Object 1 is updated.
Object 2 is updated.
Object 3 is updated.
Django render the result.
User A do a request.
Problem apear in this case :
User A do a request.
Django server update data...
Object 1 is updated.
Object 2 is updated.
User A do another request !
User A do another request !
Django render the result.
the problem is that if the user makes a request while the server has not finished working, the server stop the process and data are no longer good.
I think i have to block client side (by displaying a loading message for exemple) but i want to be sur the user cant make a request on the server if another treatemment still working.
thanks for your time.

This sounds like you have a long running process, and the user gets tired of waiting, clicks on "stop" in the browser; the other scenario is - user opens another tab and sends the same request again.
A few ways to solve this problem.
Use the transaction middleware to prevent your db objects from being corrupted if the request is interrupted.
Use a task queue like celery. At the first request, offload your task to the queue/broker. Send the user a message that their request has been accepted for processing. Now the user is free to send a duplicate request. If they do, you can check what is the status of the queue and reject the duplicate requests.

Related

Django close sessions if users moves another site or after browser close

How can I close sessions in Django if a user moves from my site to another or if he close the browser.
From both the question and comments, seems you would like to "close" session when user exits your site without any aid from JS. The answer is it depends how you define "close".
Root of the problem is that HTTP is stateless. Each request coming into the server is completely independent request without any relation to any other requests which means there cannot be any state. Since state is very useful we hack HTTP to add state by using sessions. The idea is that browser sends some identifier to some state stored on the server which allows the server to retrieve that state hence give some context to the request. The key there is that the browser is sending that data. In other words, if the browser at some point will stop sending requests, (e.g. user closes the tab), the server will never know that. Therefore if you define "close" session as removing session from the server, no that cannot be possible without some JS help.
If however all you are trying to achieve is log the user out when they exit your site, that can partially be done in Django with the use of SESSION_EXPIRE_AT_BROWSER_CLOSE setting. Here are additional docs about that. The idea here is that when Django sends the session cookie back to the browser, it will indicate to it that the session cookie should expire when the browser is closed. In that case when the browser is closed, the browser itself will invalidate the session hence the user will be forced to create new session on next visit. This is partial solution since the session will still be stored on the server and I believe only works when browser is completely closed (I dont think closing tabs works but not certain). To mitigate the issue of the server accumulating old sessions, Django provides a management command clearsessions which you should run on regular basis.

Run method on session expire Django

I'm using session to store an object id and its description, this instance should be blocked to all other users while it is beign used in someone's session, and I would like to release the user object once he closes the browser, now I'm aware there is a configuration to expire sessions on browser close, I was just wandering if there is any entry point where I could add some custom code
What I'm trying to achieve is something like
def OnSessionExpire(???):
#release my objects
I've searched around but found no answer, can someone lay a help here? I'm using the backend session mode
Thank you !
Django doesn't do anything at all when the browser closes. Django doesn't even know - how can it: the only time Django knows anything about what you do in the browser is when you make a request to the server, but closing the browser is the opposite of making a request.
Session expiry on browser close is an attribute of the session cookie, not anything that Django does. It just means that the cookie is set with a flag that tells the browser not to persist it when it closes. The actual session data remains in Django's session store, and will do until you explicitly clear it, but is not accessible because the cookie has been removed.
So, the upshot of that is that there is no way to tell explicitly when a session ends. The only thing you can do is to send regular keepalive signals - eg via Ajax - while the session is open, and taken an action if you haven't seen any for a while.

Deal with timeouts when posting data -no ajax

The use case:
User makes order his payment gets accepted and his details are getting post to a django's view. Using these details django's view creates user and everything that is necessary (Username and password is provided by me). Then before returning it sends email to clients email with his data (Username and password for now).
But sometimes I get a gateway timeout error from apache(app is deployed on openshift). Because the user is created I assume that the timeout comes from the email sending part. How can I make sure everything went ok and inform the user? How can I make sure that if the email isn't sent I can resend it? What is the best practice at that?
If you have timeouts with an API or Service, you should fire your POST / sendmail request with AJAX...
Serialize the whole form (like jQuery's serialize())
Send that data via AJAX (with jQuery's ajax())
Inform the User of success or error (alert() or jQuery UI dialog)
You can find a lot of examples on this website.
Another "dirty" approach would be to add the attribute target="_blank" to your form tag what opens your lazy request in a new tab / window.

implementing stackoverflow's notification system with django

I've seen questions like Notify panel similar to stackoverflow's. It talks about the client side of the implementation.
I'm looking for the information about the server part and the networking part (how client get notified real time)
A user scenario might look like this:
something happens for user-a
server creates a message for user-a in DB (for persistance) : I'm using django-activity-stream for this
server sends (new or last 10) messages to user-a's browser (when user-a logs in or when event happens)
browser displays the message (Notify panel similar to stackoverflow's part)
if user acknowledges the message(clicking the inbox in SO), all the unseen messages are marked as read and recorded in server
I have questions on the following steps.
(3) Not sure but https://github.com/stephenmcd/django-socketio could be used.
(4) The answer to the question says client has the json data received from server.
Does server send messages to user for every request?
Does client check local storage(I'm new-to-web, what's a good local storage for this purpose?) and request the json data if he doesn't have them in the local storage?
(5) How should I implement this seen and unseen? django-activity-stream doesn't have notion of them.
This can easily be implemented by using django-channels.Because you need websockets to have a two way client server communication.
Showing notifications is a two way communication. Server notifies the client that a new notification available. The client shows this notification to the user, and then when a user interacts with the notification, the client notifies the server that notification was read, so the next time user loads a page, only unread notifications are shown.
There are some steps involved.
Your server needs to be able to support websocket communication. django-channel converts the application to ASGI.
Create a websocket consumer that can send and receive messages to a websocket.
When user opens the application, the client creates a websocket connection channel to the server.
Whenever a new notification needs to be sent, the server will send the message to the channel.
On receiving the message, the client renders the notification on the webpage using Javascript. Like showing the new message icon, appending the new message to the list of messages, etc.
Now, one part is done. Your user has been notified. Coming to the second part.
User sees the bell icon or whatever, and click on it, he sees the notification details (this was rendered by the js, when client received a message).
User clicks on the notification/bell icon. At this time, the client will send a notification back to the server, so that server can update what all notifications were read.
I created an app that updates the client when a new message is to be shown. Github link.
You can also refer to a similar question: https://stackoverflow.com/a/55656848/4186008

Does Django process requests as queue?

I am building a voting mechanism for a site. A similar one seen on Stackoverflow.
For instance, if user clicked up-arrow, vote = True. If he clicks again on it, vote = None. The app is working fine except if we submit votes very fastly.
We tried to click arrows very very fastly and see how voting is happening by logging the data. Unfortunately, we are seeing some misbehavior. By fast, I mean, clicking the arrow continuously without stopping for some seconds!
The expected log data should be like
vote=True
vote=None
vote=True
vote=None
..
But I observed it like
vote=True
vote=True
vote=None
vote=None
The observed log data mentioned as second case, seems to be a bit unordered..
This could mean that the requests received by django are not handled as a queue! Which in our case is a bit dangerous. Or database is taking some time to store and during that period another requests are handled which is causing the error.
I hope you are understanding my issue. So, I am wondering if you can let me know what's going on here and how to control it.
You cannot make assumptions about the order in which a browser sends (asynchronous) requests, the order in which they arrive at the server and the order in which they are handled by a single or multi-instance (threaded, worker) Django application.
So what you describe above is what you actually might expect. Doing synchronous requests may help a bit. The best option is probably to (asynchronously) wait for the server's response before allowing further clicks.
You must be having a flow similar to this:
-> User clicks button
-> check if user has already voted up
-> if no:
-> vote up request goes
-> vote up after validation
-> response is sent back to browser
-> else:
-> vote none request goes
-> remove the vote after validation
-> response is sent back to browser
If you don't disable the button for the time when a request has already been sent and its response is awaited, then you will get into such situations.
Say, request1 was considered a vote up and request was sent.
Before request1's response came and user clicked again, then this request will also be considered as a vote up, which is not what you expect.
You should either disable the button, just before making the ajax call and enable it again when the response is received.
Or whenever user clicks, you should flip the button type i.e. make it vote-none for vote-up request and vice versa, even before making the ajax call. And when the ajax response is received, validate the previous action again. It will vary only in cases, when any validation fails on server side, like the user might not have permission to vote up.
You can see this happening in SO if you try to vote-up your own post. It first changes to vote-none mode and then later when the response is received from server, it changes back and also gives an error message.
PS: I tried to vote-up my own posts for educational purposes only ;)