I need to be able to access an object from one route in other routes. If I only need textual data, using session variables work just fine, but what if I want to be able to access an "unjasonyfyble" object?
I managed to do it with GLOBAL VARIABLES, I just don't know if this is a good practice...
Below is the code snippet where I got it working, but please, I'd like a general case opinion.
The route:
#main.route('/start', methods=['GET', 'POST'])
def start():
global my_form
my_form = Form()
The form class
class Form(FlaskForm):
data = IntegerField('Data', validators=[DataRequired()])
submit = SubmitField('Next')
and then, on any other function, I just access my_form.data.data
I'd really like to do this the right way.
Related
i'm trying to do a basic blog to display what i'm working on.
I was currently making a invisible route to make post directly onto it so i don't need to update my blog everytime i finish a new project, and created a ghost "post" page.
Still, somebody could find the link and i'd like to put some kind of password prompt to validate the post method, is there a way to do that without making a whole login/user system ? (Like using #login_required and all)
Thanks !
You'll want to use Flask BasicAuth. You won't need a database as you will only add one user right where you config the app, like so:
from flask_basicauth import BasicAuth
app = Flask(__name__)
app.config['BASIC_AUTH_USERNAME'] = 'john'
app.config['BASIC_AUTH_PASSWORD'] = 'matrix'
basic_auth = BasicAuth(app)
#app.route('/secret')
#basic_auth.required
def secret_view():
return render_template('secret.html')
Then you would simply add the "#basic_auth.required" decorator to your "post" route. Alternatively, you could simply name the route something that cannot be guessed, like a random string of characters.
more BasicAuth info here
I have an HTML form (in a very basic Flask site, adjusted to be inside a class), which takes in some values and will upload them to a database. What I'd like is to send the user some kind of a message on the same page after they click the 'submit' input button. That is - not to serve up a different HTML file, but to change, say one of the divs in my home.html file, or add a new div. At the moment I've thought of two possiblities:
A JS script, with onclick() to change the InnerHTML of one of the divs;
Serving up a new, almost identical HTML file, with one line changed to say something like "information received".
However, I have a feeling that there's a simpler way to do this, within the same file (home.html) using a method of Flask. I've spent a while searching through the docs and SO, without success.
class UI:
def __init__(self):
app = Flask(__name__)
#app.route('/')
def home():
return render_template("home.html")
#app.route('/', methods=['POST', 'GET'])
def update_info():
foo = request.form['foo']
bar = request.form['bar']
if request.method == 'POST':
return render_template("new_home.html")
app.debug = True
app.run()
A JS script, with onclick() to change the InnerHTML of one of the divs;
This would be the best option in my opinion. Create a div to contain the message above the form--or anywhere else you'd want it. I would suggest using jQuery for this as it's ajax method is very nice for this type of thing. Return either a success or failure response from your app(setting the status code, so jQuery knows what happened), and use the done promise to display success or the fail promise to display errors.
I'm new to Flask and templating; I am trying to pass an object and display its data on my HTML pages.
I have a detachment class like
class Detachment:
def __init__(self, name, ...):
self.name = name
self.... = ... # lots of data, mostly lists that I'd like to index
I tried doing something like this:
import Detachment as dt
from flask import Flask, request, redirect, url_for
#app.route('/')
def go():
# stuff
testDetachment = dt.Detachment('name')
return redirect(url_for('cooliofunction', detachment=testDetachment)
#app.route('/templates')
def cooliofunction():
return render_template('data.html', obj=request.args.get('detachment'))
with my data.html attempting:
{{obj}} <br />
{{obj.name}} <br />
While {{obj}} will display the object address, I can't access the variables set in my detachment - it shows up blank. Am I approaching the whole problem wrong, or is there a simple way to access objects' properties?
EDIT: I was using redirect because the creation of testDetachment actually depends on a file upload, but I omitted it to focus on the object properties.
EDIT2: So I had been using the redirect because I was following a file upload tutorial that displayed what had been uploaded, but I don't need to do that. Rendering the template directly, I could access the object's attributes directly. Thanks, everyone!
If url_for gets arguments that are not part of the rule it's building, it will append them as the query string by converting the values to strings. The string representation of an object is its address, not the object itself. When you retrieve it in the other view, you're retrieving the string representation of the object, not the actual object.
As written, you should just omit the redirect and render the template directly in the go view.
If your actual code has a specific reason for that redirect, then you should send a unique identifier for the object, and re-load it in the other view. For example, if you're using a database, commit the object to the database, pass the id in the url, and load it by id in the other view.
By the time your route gets obj it is only a string because of how you're passing it. redirect(url_for('cooliofunction', detachment=testDetachment) is likely actually passing str(testDetachment) implicitly as a query string.
Even though name is not a valid attribute for a string, Jinja simply ignores this:
from flask import Flask, render_template_string
app = Flask(__name__)
#app.route("/")
def test():
obj = "Foo"
return render_template_string("{{ obj }} {{ obj.name }}", obj=obj)
#Foo
If you want to pass arbitrary Python objects, use session, or some other form of storage, like a DB, that will persist from one request to the next.
That's not what url_for is for. Or redirects, for that matter.
Redirects are either for:
When a page doesn't exist or they can't access it
You've finished doing something (e.g. logging them in) and now they can carry on their way and you want them to go to a new page.
So typically you'll do something like this:
#app.route('/login')
def login():
if request.method == 'POST' and request.form['username'] == 'the_user' \
and request.form['password'] == 'super secret!':
... # log the user in here
return redirect(url_for('main'))
Or if you really did need to pass on some information you could do it with url_for like this:
return redirect(url_for('page', extra='values', go='here', and_='will be added', to_the='query string', like='http://foo.bar?extra=values&go=here'))
But, don't do that.
I have a problem getting data from a form using it in a route
forms.py
class Calculator(Form):
amount = IntegerField('Amount')
weight = IntegerField('Weight')
class Program(Form):
cycles = IntegerField('Cycles')
volume = FormField(Calculator)
app.py
#app.route('/', methods=('GET', 'POST'))
def index():
form = forms.Program()
if form.validate_on_submit():
values = models.Progression(
cycles=form.cycles.data,
amount=form.amount.data,
weight=form.weight.data
)
return render_template('index.html', form=form, values=values)
The data for cycles comes through just fine but I am unsure of the syntax for how to access the encapsulated form within my route. The docs say FormField will return the data dict of the enclosed form but I can't seem to figure out how to grab that and put it in a variable.
I was able to grab the data I needed using
amount=form.volume.amount.data,
weight=form.volume.weight.data
The real issue came from the fact that the form was not validating when I was using FormField. A rookie error I should have checked earlier.
I had to enable CSRF protection by importing it from flask_wtf and using CsrfProtect(app)
The problem is that the form data does not come through as the attributes of the Calculator class. The data is sent as a dictionary from the volume attribute.
Test it out with: print form.volume.data
(I suggest commenting out your values object and just use print statements)
The output should be: {'amount': foo, 'weight': bar}
Thanks for teaching me something! I never knew of FormField.
I am making a stock application, where, after a user types in a stock such as MSFT, they are redirected to .../stock?s=MSFT I have successfully made this part, but now I need Python to grab this current, unique URL so that I can parse the quote (in this case, the MSFT) out if it and save it as a new variable.
The easiest way I can think of is just to get the current URL, although I cannot seem to find a way to do this; using self.request... but this returned the error:
NameError: global name 'self' is not defined
The other ideas I came across was to use a form of urllib as it contains a specific .request_qs() method, although this requires me to pass the URL as a parameter, which should be unique every time because of the change in stock.
Here is the Python I currently have:
#app.route('/', methods=['GET', 'POST'])
def home_search():
if request.method == 'POST':
st = request.form['s']
return redirect(url_for('stock')+'?s='+st)
return render_template('stk.html')
#app.route('/stock', methods=['GET', 'POST'])
def stock():
#here I need to save the variable 'name' as the current URL. I can parse it later.
url="http://finance.yahoo.com/d/quotes.csv?s="+name"&f=snl1"
text=urllib2.urlopen(url).read()
return render_template('stock.html')
Many thanks in advance.
It's request (imported from the flask package), not self.request
The Flask docs have, as always, thorough documentation about variables in the URL: http://flask.pocoo.org/docs/quickstart/#variable-rules
#app.route('/user/<username>')
def show_user_profile(username):
# show the user profile for that user
return 'User %s' % username
On that occasion, you should read the whole Quickstart from the Flask docs: http://flask.pocoo.org/docs/quickstart/
You haven't posted any info on where the error occurs :) And I can't see where you're trying to access self.requests.
Looking at other Flask apps, it seems you should just access request instead.
Take a look at these examples: https://github.com/mitsuhiko/flask/tree/master/examples