views:

334

answers:

6

I have a class called myClass which defines post() and get() methods.

From index.html, I have a form with an action that calls myClass.post() which grabs some data from the data base, sets a couple variables and sends the user to new.html.

now, new.html has a form which calls myClass.get().

I want the get() method to know the value of the variables I got in post(). That is is main point here.

I figure the submit from new.html creates a separate instance of myClass created by the submit from index.html.

Is there a way to access the "post instance" somehow?

Is there a workaround for this? If I have to, is there an established way to send the value from post to "new.html" and send it back with the get-submit?

more generally, I guess I don't understand the life of my instances when web-programming. In a normal interactive environment, I know when the instance is created and destroyed, but I don't get that when I'm only using the class through calls to its methods. Are those classes even instantiated unless their methods are called?

A: 

I don't know specifically about the google app engine, but normally, here's what happens:

The server would have some kind of thread pool. Every time an http request is sent to the server, a thread is selected from the pool or created.

In that thread an instance of some kind of controller object will be created. This object will decide what to do with the request (like instantiating other classes and preprocessing the http request parameters). Usually, this object is the core of web frameworks. The request parameters are also resent by the browser every time (the server cannot guess what the browser wants).

Web servers usually have state stores for objects in a permanent or a session state. The session is represented by a unique user (usually by a cookie or a GUID in the url), which expires after a certain time.

Now in your case, you would need to take the values you got from your first function, store that in the session store and in the second function, get those values back from the session store.

Another solution would be to send the items back to the page as url parameters in your generated HTML from the first function and then you would get those back "as usual" from your second function.

Loki
Web sessions are usually NOT unique to a user--a single user can have multiple sessions simultaneously, and the web server does not usually know who the user is (the web application handles that).
Rob Williams
User is not the physical being here. It's an abstract concept represented by a special id stored in some way and passed around during communications. The "user" could technically be cloned and used by multiple applications at the same time or one application could have multiple.
Loki
+1  A: 

It is not a problem of how the instances are managed. Because HTTP is stateless, your program is, virtually, stateless too. (For long running processes, like GAE, it is possible to make it otherwise, but I am not sure you would need this complexity here)

You haven't supplied any code, but I am assuming you get a POST and then you redirect to results (which is a GET). So it should be easy to preserve the parameter:

def save_foo(request):
    if request.method == 'POST':
        save(request.POST)
        return HttpRedirect(reverse(
            'Some_Target',
            {'bar': 'baz', 'foo': request.POST['foo']}))
    else:
        # do something else

This view, in case of a POST, casues the client to issue a GET request to whatever URL is aliased Some_Target. And this GET will include foo parameter from the POST.

This solution is for a single view. If you need this behaviour project-wise you can use a middleware for it. And this time caching the variable makes sense.

There are two things that make me a little uncomfortable with this approach:

  1. Mixing GET and POST parameters. GET parameters should be used for instructions with no side effects, like filtering. POST parameter should be used for insructions with side effects, ie modifying the data. Moving a parameter from POST to get should be avoided IMHO.
  2. If we need persistence, using object instances (or function scopes as in my example) is usually not a good idea.
    1. If it is non sensitive information with with lower retention needs cookies are the way to go. They are a mechanism of persistence on the client side, so you can just grab them form the request and unless you change them they are retained (until expiration of course.)
    2. If you need more control over retention you should use local persistence mechanisms. Server cache (of any kind), filesystem, database... Then of course you will need to filter per user manually.

In any case I would avoid caching on instances.

muhuk
+1  A: 

HTTP is stateless, so you have no (built-in) way of knowing if the user that loads one page is the same user that loaded another. Further, even if you do know that, thanks to session cookies, for example, you have no way of telling if the browser window they're loading the subsequent page in is the same one they loaded the prior page in. The user could have multiple tabs accessing your site, and you don't want one page's state change to clobber another's.

With that in mind, your best option is to include query parameters in the link to the page being fetched with GET, encoding the variables you want to send to the 'get' page (make sure they're not sensitive, since the user can modify them!). Then you can access them through self.request.GET in the get request.

Nick Johnson
A: 

Why not just use memcache to temporarily store the variable, and then redirect to the POST URL? That seems like the easiest solution.

jamtoday
+2  A: 

What you're talking about is establishing a "session". That is, a way to remember the user and the state of their transaction.

There are several ways of tackling this, all of which rely on techniques for remembering that you're in a session in the first place.

HTTP provides you no help. You have to find some place to save session state on the server, and some place to record session identification on the client. The two big techniques are

  • Use a cookie to identify the session. Seamless and silent.

  • Use a query string in the URL to identify the session. Obvious because you have a ?sessionid=SomeSessionGUID in your URL's. This exposes a lot and makes bookmarking annoying. After the session is cleaned up, you still have this session id floating around in people's bookmarks.

  • In a limited way, you can also use hidden fields in a form. This only works if you have forms on every page. Not always true.

Here's how it plays out in practice.

  1. GET response. Check for the cookie in the header.

    a. No cookie. First time user. Create a session. Save it somewhere (memory, file, database). Put the unique ID into a cookie. Respond knowing this is their first time.

    b. Cookie. Been here recently. Try to get the cookie.

    • FInd the session object. Respond using information in the cookie.

    • Drat. No session. Old cookie. Create a new one and act like this is their first visit.

  2. POST response. Check for the cookie in the header.

    a. No cookie. WTF? Stupid kids. Get off my lawn! Someone bookmarked a POST or is trying to mess with your head. Respond as if it was a first-time GET.

    b. Cookie. Excellent. Get the cookie.

    • Find the session object. Find the thing you need in the session object. Respond.

    • Drat. No session. Old cookie. Create a new one and respond as if was a first-time GET.

You can do the same thing with a query string instead of a cookie. Or a hidden field on a form.

S.Lott
A: 

OK -- Thanks everyone.

I'll try some of these ideas out, soon, and get back to you all.

It seems I can work around some these things by doing a lot of writing and reading from the datastore*, but I thought there might be an easier way of keeping that instance of the class around (I'm trying to use my known techniques in a web framework that I don't completely get yet).

*For instance, creating a unique record based on the data in the POST, and letting some variables "tag along". Is this a bad practice?

Baltimark
Not enough info to comment on "bad practice"
Rob Williams