This question already has answers here:
How do I use flask.url_for() with flask-restful?
(3 answers)
Closed 7 years ago.
I had my Flask routes defined like this:
#api_app.route('/api/1.0/infrastructure/', methods=['POST'])
def create_infrastructure():
return (jsonify({'job': job_instance.reference}), 202,
{'Location': url_for('get_job', ref=job_instance.reference, _external=True)})
get_job function:
#api_app.route('/api/1.0/job/<string:ref>', methods=['GET'])
def get_job(ref):
job = Model.Job.query.filter_by(reference=ref).first()
if not job:
abort(400)
return jsonify({'job': job.reference})
I migrated to a flask.ext.restful environment and now looks like this:
from flask.ext.restful import Resource
class Job(Resource):
def get(self, ref):
job = Model.Job.query.filter(Model.Job.reference == ref).first()
if job:
return jsonify(job.serialize())
resp = Response(status=404, mimetype='application/json')
return resp
In this class based API using flask.ext.restful
How to define the url_for parameters in this class based environment?
In my main app file:
api.add_resource(Job, '/api/1.0/job/<string:ref>')
imbue_api.add_resource(Infrastructures, '/api/1.0/infrastructure')
The easiest way is to just use flask-restful's Api.url_for.
So instead of writing
url_for('get_job', ...)
You would have to
from flask_restful import Api
Api.url_for(Job, ...)
Note:
It is important to make sure you don't create circular imports by importing classes into each other. My personal preferred way to organize this is to import all involved resouces in the __init__.py and then if you want to link to them you import .Job, that way you enforce a clean import order.
Thanks I used the following:
from flask import current_app
api = restful.Api
In my Infrastructure class:
response.headers['Location'] = api.url_for(api(current_app),
Job,
ref=job_instance.reference,
_external=True)
And works fine now
Related
This question already has answers here:
Serve static files from a CDN rather than Flask in production
(3 answers)
Closed 1 year ago.
I'm using a web server on PythonAnywhere to run a Flask application. All I'm looking to do is randomly output a gif from a list of URLs. I'm looking to utilize the requests library, and I suspect I need the render_template in order to actually pass the image over. I have been dealing with either view function TypeErrors or outputs of plain text to a URL. I've also incorporated PIL and shutil once or twice but to no functional success.
from flask import Flask, render_template
import random
import requests
app = Flask(__name__)
WELCOME_LIST = [
'https://cdn.discordapp.com/attachments/891856529928622080/891865614870806568/rgb.gif'
'https://cdn.discordapp.com/attachments/891856529928622080/891865655542964224/racing.gif',
'https://cdn.discordapp.com/attachments/891856529928622080/891897881550802954/comet.gif',
'https://cdn.discordapp.com/attachments/891856529928622080/891897942678581278/harujion.gif',
'https://cdn.discordapp.com/attachments/891856529928622080/891898027126698045/letter.gif',
'https://cdn.discordapp.com/attachments/891856529928622080/891898085909864479/encore.gif',
'https://cdn.discordapp.com/attachments/891856529928622080/891898143627677786/gunjou.gif',
'https://cdn.discordapp.com/attachments/891856529928622080/891898187240050718/haruka.gif',
'https://cdn.discordapp.com/attachments/891856529928622080/891898241900236830/monster.gif',
'https://cdn.discordapp.com/attachments/891856529928622080/891898276339646474/probably.gif',
'https://cdn.discordapp.com/attachments/891856529928622080/891898352617259028/taisho.gif',
'https://cdn.discordapp.com/attachments/891856529928622080/891898425342316624/tracing.gif',
]
#app.route('/')
def obtainGif():
gif = random.choice(WELCOME_LIST)
response = requests.get(gif)
return response.raw
#app.route('/join')
def output():
finalize = obtainGif
return render_template('home.html', finalize=finalize)
if __name__ == '__main__':
app.run(host='0.0.0.0')
Use the send_file method.
from flask import Flask, render_template, send_file
def obtainGif():
gif = random.choice(WELCOME_LIST)
response = requests.get(gif, stream=True)
return send_file(response.raw, mimetype='image/gif')
You can use {{ variable }} anywhere in your template, not just in the HTML part.
def output():
gif = random.choice(WELCOME_LIST)
return render_template('home.html', gif=gif)
in the home.html file add a script tag in which you are capturing this passed data
<script>
let gif= {{gif|safe}};
</script>
At this point you have the GIF URL inside your java-script code from where you can edit the HTML part of your code to add this GIF inside the <img> tags
I am trying to call a get method from my main.py from another python file and I am using flask and blueprints.
I have 2 files: main.py and product.py.
Based on the documentation, I thought after we have done an import, we can then call the method.
In my product.py
import os
from flask import Blueprint, Flask, render_template, request, jsonify
import stripe
import json
import ast
product = Blueprint('product',__name__)
#product.route('/getallproducts', methods=['GET'])
def get_products ():
myList = ["price_1GqLlRFswqvdSoNHi27H2wLV","price_1GqLiAFswqvdSoNHjv4R6scY","price_1GqY8eFswqvdSoNHVSRzEQdn","price_1GqYAcFswqvdSoNH1uReU4kN"]
result =[]
for i in myList:
priceobj = stripe.Price.retrieve(i)
product= stripe.Product.retrieve(priceobj.product)
data = product
data["price"] = priceobj.unit_amount/100
data["priceid"] =i
result.append(data)
return result
In my main.py i have
import os
from flask import Blueprint, Flask, render_template, request, jsonify
import stripe
import json
import ast
from product import product
stripe.api_key = stripe_keys['secret_key']
app=Flask(__name__,template_folder='../client', static_url_path='', static_folder='../client')
app.register_blueprint(product)
#app.route('/', methods=['GET'])
def main():
result =product.get_products()
return render_template('index.html', data=result)
I tried to do product.get_products() but it complained that no such methods exist.
Is there something which I am missing out on as I thought this was the way we can use blueprints?
You're likely getting the invalid method because you're not importing the function get_products() but a variable from your file that uses it. Try changing the import line in your main.py to from product import product, get_products.
Ideally get_products should be a separate method somewhere instead of calling the Flask route method, in this case, you could start off with product.py itself.
def get_all_products():
myList = ["price_1GqLlRFswqvdSoNHi27H2wLV","price_1GqLiAFswqvdSoNHjv4R6scY","price_1GqY8eFswqvdSoNHVSRzEQdn","price_1GqYAcFswqvdSoNH1uReU4kN"]
result =[]
for i in myList:
priceobj = stripe.Price.retrieve(i)
product= stripe.Product.retrieve(priceobj.product)
data = product
data["price"] = priceobj.unit_amount/100
data["priceid"] =i
result.append(data)
and you could simply refer to this method from wherever you need to get all the products.
P.S: Leandro's answer works perfectly if you don't want to follow this method
I have a Flask project where the entry point is application.py and then I have several other modules like, e.g. variant.py, etc.
The project structure is:
>my_app_dir/
application.py
views/
__init__.py
users.py
variant.py
...
For variant.py, it's a function like:
import ...
from views import *
def variant(variant_id, subset='all', language='en'):
...
if subset == 'all':
return json.dumps(x)
return json.dumps([{subset: y[subset]} for y in x])
The point is I want to use variant.py like an API, so I am testing via iPython, something like, but it's returning an error:
from views import variant as v
aa = v.variant('22-38212762-A-G')
...
RuntimeError: Working outside of request context.
This typically means that you attempted to use functionality that needed
an active HTTP request. Consult the documentation on testing for
information about how to avoid this problem.
I've tried googling but couldn't find any similar case, yet I experimented several things for no avail.
In the end, I found out a way to get what I was looking for:
from views import application, autocomplete
from views.variant import variant
ctx = application.test_request_context(path='/login',method='POST', data={'user':'demo','password':'demo123'})
ctx.push()
variant('22-38212762-A-G')[:50]
autocomplete.autocomplete('ttll','gene').json
So, essentially, the trick bit is:
ctx = application.test_request_context(path='/login',method='POST', data={'user':'demo','password':'demo123'})
ctx.push()
I'm currently working through the Flask Mega-Tutorial (Part XVI) and have gotten stuck implementing elasticsearch. Specifically, I get this error when running the following from my flask shell command line:
from app.search import add_to_index, remove_from_index, query_index
>>> for post in Post.query.all():
... add_to_index('posts', post)
AttributeError: module 'flask.app' has no attribute 'elasticsearch'
I should mention that I did not implement the app restructuring from the previous lesson to use blueprints. Here's what my files look like:
__init__.py:
#
from elasticsearch import Elasticsearch
app.elasticsearch = Elasticsearch([app.config['ELASTICSEARCH_URL']]) \
if app.config['ELASTICSEARCH_URL'] else None
config.py:
class Config(object):
#
ELASTICSEARCH_URL = 'http://localhost:9200'
search.py:
from flask import app
def add_to_index(index, model):
if not app.elasticsearch:
return
payload = {}
for field in model.__searchable__:
payload[field] = getattr(model, field)
app.elasticsearch.index(index=index, id=model.id, body=payload)
def remove_from_index(index, model):
if not app.elasticsearch:
return
app.elasticsearch.delete(index=index, id=model.id)
def query_index(index, query, page, per_page):
if not app.elasticsearch:
return [], 0
search = app.elasticsearch.search(
index=index,
body={'query': {'multi_match': {'query': query, 'fields': ['*']}},
'from': (page - 1) * per_page, 'size': per_page})
ids = [int(hit['_id']) for hit in search['hits']['hits']]
return ids, search['hits']['total']['value']
I think I'm not importing elasticsearch correctly into search.py but I'm not sure how to represent it given that I didn't do the restructuring in the last lesson. Any ideas?
The correct way to write it in the search.py file should be from flask import current_app
Not sure if you got this working, but the way I implemented it was by still using app.elasticsearch but instead within search.py do:
from app import app
first off, a disclaimer: I'm not well versed in python or flask, so bear with me.
I'm trying to put together a minimal API using flask, i was planning to dynamically generate routes and their associated procs from the contents of a subdirectory.
The code looks something like this:
from flask import Flask
import os
app = Flask(__name__)
configs = os.getcwd() + "/configs"
for i in os.listdir(configs):
if i.endswith(".json"):
call = "/" + os.path.splitext(i)[0]
#app.route(call, methods=['POST'])
def call():
return jsonify({"status": call + "Success"}), 200
The plan being to iterate over a bunch of config files and use their naes to define the routes. Now, this works for a single config file, but wont work for multiple files as I end up trying to overwrite the function call that is used by each route.
I can factor out most of the code to a separate function as long as i can pass in the call name. However it seems that however i go about this i need to dynamically name the function generated and mapped to the route.
So, my question is: how can use the contents of a variable, such as 'call' to be the function name?
i.e. something like
call = "getinfo"
def call(): # Effectively being evaled as def getinfo():
Everything i've tried hasn't worked, and i'm not confident enough in my python syntax to know if it's because i'm just doing something silly.
Alternatively is there another way to do what i'm trying to achieve?
Thanks for all and any feedback!
Thanks for the help. I've moved to one route and one handler and building up the file list, and handling of the request paths, etc separately.
This is a sanitized version of the model i now have:
from flask import Flask
import os
calls = []
cfgs = {}
app = Flask(__name__)
configs = os.getcwd() + "/configs"
for i in os.listdir(configs):
if i.endswith(".json"):
cfgs[call] = os.path.splitext(i)[0]
calls.extend([call])
#app.route('/<call>', methods=['POST'])
def do(call):
if call not in calls:
abort(400, "invalid call")
# Do stuff
return jsonify({"status": call + "Success"}), 200
if __name__ == '__main__':
app.run(debug=True)
So, thanks to the above comments this is doing what i'm after. Still curious to know if there is any way to use variables in function names?