PYTHON: Updating local variable in .TPL file

Hi,
In a Python function, I have a local variable: TestLocal.
I pass it to the bottle.template() function.

    TestLocal = "TEST"
    TempReturn = bottle.template("entry_template", dict(post=post, username=username, errors="", comment=comment, TestLocal=TestLocal))
    print "After return from bottle.template: TestLocal =",TestLocal

Open in new window


In ENTRY_TEMPLATE.TPL, I have the following. (The other is a field in a blog comment)

Name (required)
<input type="text" name="commentName" size="60" value="{{comment['name']}}">
Enter TestGlobal:
<input type="text" name="testlocal" size="20" value="{{TestLocal}}">
<input type="submit" value="Submit">

Open in new window


The form appears as follows, with TestLocal seeded to "TEST".
Python-TPL-fields.JPG
I do the following:
1. Enter the name (e.g. "STEVE").
2. For TestLocal, I change "TEST" to "ABCDE".
3. I click submit.

The results:
1. The comment is added including "STEVE" for the name.
2. For TestLocal, "ABCDE" reverts to "TEST" ,as soon as I return from the .TPL routine per this debugging code. (Reproducing code snippet here for clarity.)

    TestLocal = "TEST"
    TempReturn = bottle.template("entry_template", dict(post=post, username=username, errors="", comment=comment, TestLocal=TestLocal))
    print "After return from bottle.template: TestLocal =",TestLocal

Open in new window


After return from bottle.template: TestLocal = TEST

So, one field is updated, the other is not. Any ideas on what I'm missing?

Thanks,
Steve
LVL 4
Stephen KairysTechnical Writer - ConsultantAsked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

gelonidaCommented:
not sure if this is the problem, but be aware that if a function wants to modify a module's variable it can only do so by declaring it as global.
Otherwise a local variable will be created, but the module's one won't be changed.
Just run following code snippet and You'll see


A=1

def set_a(value):
    A = value

def really_set_a(value):
    global A
    A = value

print(A)
set_a(2)
print(A)
really_set_a(3)
print(A)

Open in new window


The output will show, that the first function will not change A (not declared as global), whereas the second will.
The output is:
1
1
3

Open in new window

0

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
Stephen KairysTechnical Writer - ConsultantAuthor Commented:
Gelonida,

Thanks! I'll try it later...I'm presently in the midst of prepping for an interview.

Steve
0
gelonidaCommented:
good luck
0
Ultimate Tool Kit for Technology Solution Provider

Broken down into practical pointers and step-by-step instructions, the IT Service Excellence Tool Kit delivers expert advice for technology solution providers. Get your free copy now.

Stephen KairysTechnical Writer - ConsultantAuthor Commented:
Gelonida,
Thanks!  Finally had a chance to try your snippet and I see your point.  I am so used to the world of C where if you have the below, the assignment statement in foo() refers to the global. in Python, if I understand you correctly, the A=2 creates a local version of A.

Int A=1;

void foo()
{   
   A = 2; // Refers to the global A.
}

void main()
{
   printf("%d\n", A);
   foo();
   printf("%d\n", A);
}

Open in new window


I still need to try the above per my TPL file, but having an unrelated issue with my Port 8082, which my program uses. Will post again once i resolve.

Thank you again!
Steve
0
gelonidaCommented:
Exactly.

All variables in python functions are by default local.
however the confusing thing is, that you can read global variables and if you try to modify them you will create a local version, which will mask the global from that point on (except you declare it at the beginning of the function as global)
0
Stephen KairysTechnical Writer - ConsultantAuthor Commented:
Gelondia,

OK. I now have TestGlobal "Globalized" (for lack of a better word) in the function that invokes the TPL file. But...when I change the seeded value of TestGlobal from (for example) "Seed" to "Abcde", it is not updated when the web page refreshes.

I have attached the relevant .PY and .TPL files. Thanks. I renamed the .TPL file to have a .TXT extension b/c I was not allowed to attach a file with .TPL extension.

Thanks again!
Steve
blog.py
entry_template_tpl.txt
0
gelonidaCommented:
I'm not a big specialist of bottle, I never used it.
However I expect it to work similiar than other web frameworks.

If I understand well:

Now you have a global variable named TestGlobal,
this variable is passed to a template, which is rendered into a web form and sent to your web browser
on your browser you submit the form with a modified value for TestGlobal

now you have to:
-  go to the function, that is called whenever the form is submitted
- fetch the value TestGlobal from your form (probably something like bottle.request.forms.get('TestGlobal')
- assign it to your global python variable

this should allow you to change the global variable of the currently active python process.

But note, that this might not necessarily be the best idea depending how your web server / web framework is configured.
It will probably run for a standalone web server, but might fail if you run multiple instances behind apache / nginx

If your webserver creates for example multiple processes, then you would only change the global variable of one process. (each process having its own variables)

If you restart the web server it would also loose the value of TestGlobal.

That's why most web frameworks store persistent variables in a database or in a file storage.
It all depends on your context.

Please don't hesitate to ask for clarifications in case I didn't explain well enough.
0
Stephen KairysTechnical Writer - ConsultantAuthor Commented:
Thanks for your detailed reply. To respond:

1.  All I need is for it to run on a standalone web server. I don't need to support multiple processes, or concern myself with restarting the server. Nevertheless, your points are well-taken.

2.  Doesn't this line:
 TempReturn = bottle.template("entry_template", dict(post=post, username=username, errors="", comment=comment, TestGlobal=TestGlobal))

Open in new window

accomplish what you suggested:

>>
- fetch the value TestGlobal from your form (probably something like bottle.request.forms.get('TestGlobal')
- assign it to your global python variable

<<

Thanks!
0
gelonidaCommented:
I think, that this line just creates HTML code, that will be sent to your web browser.
You tell it, that the variable in your template, that is named TestGlobal should have the value of your python variable TestGlobal.
In other words you assign the python global to the template variable and fill therefore it's value into the html template and thus in the rendered HTML.

If I understand well, you change the value in the web browser, press submit and want its value to be received by your bottle code and then assigned to your global variable.

Could you please check on your web browser (view source code), whether your web form has "POST" or "GET" as submit method?

Could you also tell me, which action url your form has?

This will allow me to understand which function will be called when you pressed the submit function.

To see how to extract values from a web request you can look for example look at the function
post_new_comment()
this one fetches variables from a submitted web form with lines like.
name = bottle.request.forms.get("commentName")

Open in new window


You would need something  like
global TestGlobal
TestGlobal = bottle.request.forms.get("TestGlobal")

Open in new window

to extract a value from a request and assign it to a python variable.

You just have to place it in the function, that handles your form submit
0
Stephen KairysTechnical Writer - ConsultantAuthor Commented:
To give context, this is a Blog application that was given to me as part of a course I took. It dealt with fields in the Blog database. I need to learn how to deal with global variables in a standalone app I'm writing. So, I figured I'd leverage this existing application - I randomly chose the post-comment mechanism - as a framework.

Let's consider the following.

1. In this function call:
TempReturn = bottle.template("entry_template", dict(post=post, username=username, errors="", comment=comment, TestGlobal=TestGlobal))

Open in new window

it already handled blog fields (post, username, comment). This function assigns local variables to these fields. (e.g. username=username). In this case, the instance on the right is the local variable, and I think the instance on the left is the variable in the .TPL file.

2. Per the submit method, do you mean something like this (for the LIKE button):
<form action="/like" method="POST">

Open in new window


3. Please clarify your comment:
>>Could you also tell me, which action url your form has? <<

Thanks!
0
gelonidaCommented:
What I meant with action was the string:
action="/like"

Open in new window


int he line:
<form action="/like" method="POST">

Open in new window


So this means, that the function handling the post request to "/like" will be called whenever you press the submit button.
In this function you should be able to retrieve the web forms value and store it in your global.


So try to add the lines
global TestGlobal
TestGlobal = bottle.request.forms.get("TestGlobal")

Open in new window


to the function post_comment_like()
0
Stephen KairysTechnical Writer - ConsultantAuthor Commented:
OK...
Two comments:

1. The "/like" refers to the LIKE button. Not the SUBMIT button. I should have been clearer.

2.  I tried this:
 TestGlobal = "Tomato"
    TempReturn = bottle.template("entry_template", dict(post=post, username=username, errors="", comment=comment, TestGlobal=TestGlobal))
    print "After return from bottle.template: TestGlobal =",TestGlobal
    TestGlobal = bottle.request.forms.get("TestGlobal")
    print "After return from bottle.request.forms.get: TestGlobal =",TestGlobal

Open in new window


but it did not work. Here's my debugging code:

BLOG.PY:show_post() about to query on permalink =  New_York_City_Marathon
After return from bottle.template: TestGlobal = Tomato
After return from bottle.request.forms.get: TestGlobal = None

Open in new window


Anyhow, won't be able to respond 'til late Friday (or Saturday)...heading out of town for the Thanksgiving holiday. Thanks for all your help...we'll figure it out! :)

Steve
0
gelonidaCommented:
Wish you happy thanksgiving.

I'll try to explain, why what you tried cannot work
1.) TestGlobal  is assigned a value in your python script
2.) you render a template with the current value of TestGlobal
in fact the
TempReturn = bottle.template(...)

Open in new window

just renders a template, but it sends nothing at all to the web browser
only whe you do the
 return TempReturn

Open in new window

at the end of your function bottle will send the rendered
template to your browser
3.) The rendered HTML with a form is sent to your web browser.
4.) Now you change the value in your web browser and you submit the form.
To understand how the submit is handled you have to look at the form in which the submit button is contained.

What you tried to do in your recent attempt cannot work, as all the code you added is in 2.) in the function that renders and creates the form that will be sent to the web browser. The call to this function is finished before anything was sent to your web browser. It can therefore not retrieve the value that you entered into your web browser

if the <form>tag in the HTML code were
 <form action="/like" method="POST">

Open in new window

then you had to adapt the code, that treats the "POST" request for the url "/like"

The submit button will perform a request to the action of the form it is located in and do this request with the method specified in the form it is located in.

5.) The code treating the form submission (let's assume it were a POST to "/like" is the code, that has to retrieve the variable value from the posted form data and to update the global variable.

Not sure I have time in the next days. If, then I'll try to download bottle and make a small example that works without any other dependencies like the mongo database.
0
Stephen KairysTechnical Writer - ConsultantAuthor Commented:
Hi, Gelonia. I Just saw this reply. Thank you for the holiday wishes!
I'll review after the weekend. I really appreciate all your patient attention to this issue.

Steve
0
Stephen KairysTechnical Writer - ConsultantAuthor Commented:
Gelonia,

OK, let's take it step-by-step.
You are saying the data I enter for TestGlobal will not get updated. Why then will my COMMENT be processed properly and the local data not?

Blog and Local Data on Same Form
Thanks,
Steve
0
gelonidaCommented:
I think the main issue is, that your example is too complicated to be able to focus on understanding some specifics about how web frameworks are functioning.

Please look at the example that I attached.

it just contains three views
- main page to show all blogs
- edit form to change them
- handle the post request.

In order to have to post only one file, I added the template strings into the python code.
As I don't know bottle very well (I never used it so far) I didn't know how to render from strings, so the first part of the code, just creates the three template files, which you will find in the local directorty after running the secript)

Please try out the example and tell me whether things are easier to understand.

I intentionally added a delay of three seconds in the code.
if you look at your browser window and the python console at the same time, you might better understand, when things are processed by the python code and when they are displayed at the browser.

As already said before.
you have to change your global variable in the code section, that handles your web request and NOT in the one, that renders the template showing the form.

In my opinion, this is the main issue with the code, that you tried out.
microblog.py
0
Stephen KairysTechnical Writer - ConsultantAuthor Commented:
Yeah, I was starting to think that I should simply create a small app to handle just one field, rather than try to add a field to a complex app. Will look at your remarks in detail later. Thanks.
0
gelonidaCommented:
minor update. there were some small mistakes in the example code.

Addintionally the server restarts now automatically any time you change the source code
microblog.py
0
Stephen KairysTechnical Writer - ConsultantAuthor Commented:
Gelonida,

Nice!  It seems that if I enter a new value for the global, it is modified.

I will play around with it some more. Thank you so much!

Steve
0
Stephen KairysTechnical Writer - ConsultantAuthor Commented:
Well, this is interesting.

After invoking the .PY program, I found some TPL files in the same folder. Is the below expected behavior?  Thanks.

12/07/2015  12:47 PM             3,472 MicroBlogTest.py
12/07/2015  12:47 PM    <DIR>          ..
12/07/2015  12:47 PM    <DIR>          .
12/07/2015  12:49 PM               451 show_post_edit.tpl
12/07/2015  12:49 PM               251 main.tpl
12/07/2015  12:49 PM               359 modify_post.tpl

Open in new window

0
gelonidaCommented:
Hi Stephen,

yes this is expected behavior jus reread my comment of the previous post:
In order to have to post only one file, I added the template strings into the python code.
As I don't know bottle very well (I never used it so far) I didn't know how to render from strings, so the first part of the code, just creates the three template files, which you will find in the local directorty after running the secript)

I don't know bottle very well and didn't know how to use strings as templates.
Hope this clarifies
0
Stephen KairysTechnical Writer - ConsultantAuthor Commented:
Thanks. Sorry for the delayed reply, some other things came up. Will try to get back to this issue soon.
0
Stephen KairysTechnical Writer - ConsultantAuthor Commented:
Apologies for the late response, Gelondia. Don't have time to go through all comments but I wanted to give you credit for explaining the global/local thing... :)

Thanks!
0
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
Python

From novice to tech pro — start learning today.

Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.