Flask: how to use g [duplicate] - flask

I found this code that times each response, but I'm not sure where g is supposed to come from. What is g?
#app.before_request
def before_request():
g.start = time.time()
#app.teardown_request
def teardown_request(exception=None):
diff = time.time() - g.start
print diff

g is an object provided by Flask. It is a global namespace for holding any data you want during a single app context. For example, a before_request handler could set g.user, which will be accessible to the route and other functions.
from flask import g
#app.before_request
def load_user():
user = User.query.get(request.session.get("user_id"))
g.user = user
#app.route("/admin")
def admin():
if g.user is None or not g.user.is_admin:
return redirect(url_for("index"))
An app context lasts for one request / response cycle, g is not appropriate for storing data across requests. Use a database, redis, the session, or another external data source for persisting data.
Note that the dev server and any web server will output timing information in the logs already. If you really want to profile your code, you can use the Werkzeug application profiler.

Related

Flask with SQLAlchemy working outside of application context

I have a Flask app and I use SQLAlachemy(without Flask extension cause I need to create my own class based SQLAlchemy and so on).
My app has a connection to its database over engine and it works fine but now I need to make my engine dynamically and get db_name from Flask.g
Engine is declared in models.py
models.py
engine = create_engine(f"postgresql://postgres:postgres#localhost:5434/{g['tenant']}", convert_unicode=True)
db_session = scoped_session(sessionmaker(autocommit=False,
autoflush=False,
bind=engine))
Base = declarative_base()
Base.query = db_session.query_property()
For the start app I use wsgi.py:
from app import app
if __name__ == "__main__":
app.run(port=5002)
when I type python wsgi.py I receive an error.
RuntimeError: Working outside of application context.
This typically means that you attempted to use functionality that needed
to interface with the current application object in some way. To solve
this, set up an application context with app.app_context(). See the
documentation for more information.
In general I understand that I use an engine which is outside the context. The issue is - I cannot figure out how to pass my engine variable to context.
I try to make create app func:
def create_app():
app = Flask(__name__)
with app.app_context():
engine = create_engine(f"postgresql://postgres:postgres#localhost:5434/{g['tenant']}", convert_unicode=True)
return app
Also I tried app.app_context().push(engine)
But it doesn't work. How I can solve this issue?
The problem is that the flask object g only ever exists when a request is currently in progress on flask. (Without a request, there is no flask g, because g is specifically a global for individual requests)
what you'd have to do is to create that engine after the request starts, which slows down the route a bit. The #app.before_request decorator might help you here:
#app.before_request
def create_engine_for_request():
engine = create_engine(f"postgresql://postgres:postgres#localhost:5434/{g['tenant']}", convert_unicode=True)
("before_request" is already "during a request" - its just the first thing that flask does "when a request starts")

How does interacting with the django rest api through the url work?

I get that the Django rest framework is for interacting with the Django server programmatically but one thing I still don't understand is how.what i want to do is have my client app (mobile app) send data (somehow) to the Django server in order to create/retrieve data based on variables and obviously this has to be done through the URL since there will be no direct GUI interaction with the API. (unless I'm mistaken, which I probably am) I have gone through the official documentation and followed the tutorial to the end and still don't understand how this is supposed to work.all I ask for is a quick and simple explanation because I have searched everywhere and haven't found a simple enough explanation to grasp the core concept of how this is all supposed to work.
I think what you're looking for is JSONResponse and related objects:
This will allow you to send JSON in response to a request.
from django.http import JsonResponse
def my_view_json(request):
response = JsonResponse({'foo': 'bar'})
return response
If your templates or webpages need to make a request to a view and specify different parameters, they can do so by adding POST variables (examples). These can be parsed in the view like so:
def myView(request):
my_post_var = request.POST.get('variable_name', 'default_value')
my_get_var = request.GET.get('variable_name', 'default_value')
You can then parse what was sent any way you like and decide what you want to do with it.
Basically,
You define the URLS upon which you perform Get/POST/PUT Requests and You can Send Data to that.
Eg:
urls.py
from django.conf.urls import url,include
from app import views
urlpatterns = [
url(r'^(?i)customertype/$',views.CustomerViewSet.as_view()),
url(r'^(?i)profile/$', views.Save_Customer_Profile.as_view()),
url(r'^(?i)customer_image/$', views.Save_Customer_Image.as_view()),
]
Now Whenever User would send a Request to:
example.com/profile ==> This would be received in the Save_Customer_Profile View based on the Method Type, Save_Customer_Profile is as follows:
class Save_Customer_Profile(APIView):
"""Saves and Updates User Profile!"""
def get(self, request, format=None):
return AllImports.Response({"Request":"Method Type is GET Request"})
def post(self, request, format=None):
return AllImports.Response({"Request":"Method Type is Post Request"})
def put(self,request, format=None):
return AllImports.Response({"Request":"Method Type is Put Request"})
I think the OP was referring to how to do GET/POST request programmatically. In that case, it is enough to do (values are dummy):
GET:
import requests
r = requests.get('http://localhost:8000/snippets/')
print(r.json())
print(r.status_code, r.reason)
POST:
data = {'code': 'print(" HELLO !!!")', 'language': 'java','owner': 'testuser'}
r = requests.post('http://localhost:8000/snippets/', data=data, auth=('testuser', 'test'))

Flask Blueprint : how to run each apps in different port?

I got a flask application with different apps inside, using BluePrint.
To simplify, I got an API that manages token web authentification (and a lot of other data functions) and a website that should call the API to get the valid token, using a basic auth to start with
The issue is that when the website requests the API, it never gets any feedback from the API.
Requesting the API via POSTMAN works like a charm, but this call below, done from a website route is waiting, waiting, waiting and never ends.
So my assumption is that using the same port for both website and api is the issue
I could of course divides the flask into 2 flask apps with 2 servers, but there are many objects and tools both API and website are sharing, so I dont want to double the job
Thanks.
call from the website
from requests.auth import HTTPBasicAuth
import requests
mod = Blueprint('site', __name__, template_folder='templates/login')
def load_user(username, password):
data = requests.get('http://127.0.0.1:5000/api/login',
auth=HTTPBasicAuth('username', 'password'))
return data
#mod.route('/')
def index():
username = 'jeje'
password = 'jeje'
data = load_user(username, password)
return '<h1>load user<h1>'
the api function
#mod.route('/login')
def login():
resu = True
auth = request.authorization
if not auth or not auth.username or not auth.password:
resu = False
user = USER.query.filter_by(username = auth.username).first()
if not user:
resu = False
if validehash(user.password, auth.password):
period_in_mn = 120
payload = {
'public_id':user.public_id,
'exp' : datetime.datetime.utcnow() + datetime.timedelta(minutes = period_in_mn)
}
token = createtoken(payload, current_app.config['SECRET_KEY'])
if resu:
return jsonify({'token' : token })
else:
return jsonify({'token' : 'unknown'})
I guess your using flask 0.12 instead of 1.0. So whats happening here is that you're requesting a route from within another route.
Your browser requests /, and in your index function, you request /login. But the flask process is still working on the / request from the browser, and can't take any other requests, because flask 0.12 is working on a single core only.
Requesting like this is bad design. You could make a helper function, which returns the same data in different requests (either api or main site), or you could make the browser send another request using AJAX.
Flask 1.0 has multicore support, so I think this might work over there, but I really think you should change your design. This has absolutely nothing to do with blueprints by the way.
from flask import Flask, redirect
import requests
app = Flask(__name__)
#app.route('/')
def index():
result = requests.get('http://127.0.0.1:5000/api/login')
return 'this is the index<br>' + result.text
#app.route('/api/login')
def login():
return 'you are logged in'
Using flask 0.12, times out when visiting http://127.0.0.1:5000/.
Using flask 1.0, returns this is the index
you are logged in when visiting http://127.0.0.1:5000/.

How to share object between blueprint in Flask

I have two blueprints, such as auth and sprints, the structure is as follows:
auth
__init__.py
views.py
forms.py
sprints
__init__.py
views.py
forms.py
I want to share api object after login successfully
#auth.route('/login', methods=['GET', 'POST'])
def login():
form = LoginForm()
if form.validate_on_submit():
try:
jira_url = app.config["JIRA_URL"]
app_id = app.config["JIRA_APPID"]
api = GreenHopper(options={"server": jira_url, "appid": 37},
basic_auth=(form.username.data, form.password.data))
g.api = api
except JIRAError:
api = None
...
...
return redirect(request.args.get('next') or url_for('scrumworks.index'))
return render_template('auth/login.html', form=form)
On the sprints blueprint, I want to get the api object like codes below:
#scrumworks.route("/sprints")
#login_required
def show_sprints():
if current_user.admin:
sprints = g.api.sprints(37)
return render_template("scrumworks/sprints.html")
else:
flash("Only admin users can access this page")
return redirect(url_for(".index"))
When the codes run, it will complain AttributeError: '_AppCtxGlobals' object has no attribute 'api'.
It seems the life cycle of g is per request, not global, so I can't store api in g
Another choice is session, but the api object cannot be serializable, so it can't be stored in session, what should I do next?
Any ideas? Thanks :-)
The g object is only available between requests.
The quick and dirty way to solve this, is to add your api object into the global space where the Flask app is defined and then importing the api object from there.
Keep in mind that with multiple servers and concurrency, this object can get out of sync fairly quickly and should remain stateless.
See this project on github for an example
The preferred solution for this is to use a database that fits the needs of your object. Redis, MongoDB and PostgreSQL are some of the more common ones.

Huge Django Session table, normal behaviour or bug?

Perhaps this is completely normal behaviour, but I feel like the django_session table is much larger than it should have to be.
First of all, I run the following cleanup command daily so the size is not caused by expired sessions:
DELETE FROM %s WHERE expire_date < NOW()
The numbers:
We've got about 5000 unique visitors (bots excluded) every day.
The SESSION_COOKIE_AGE is set to the default, 2 weeks
The table has a little over 1,000,000 rows
So, I'm guessing that Django also generates session keys for all bots that visits the site and that the bots don't store the cookies so it continuously generates new cookies.
But... is this normal behaviour? Is there a setting so Django won't generate sessions for anonymous users, or atleast... no sessions for users that aren't using sessions?
After a bit of debugging I've managed to trace cause of the problem.
One of my middlewares (and most of my views) have a request.user.is_authenticated() in them.
The django.contrib.auth middleware sets request.user to LazyUser()
Source: http://code.djangoproject.com/browser/django/trunk/django/contrib/auth/middleware.py?rev=14919#L13 (I don't see why there is a return None there, but ok...)
class AuthenticationMiddleware(object):
def process_request(self, request):
assert hasattr(request, 'session'), "The Django authentication middleware requires session middleware to be installed. Edit your MIDDLEWARE_CLASSES setting to insert 'django.contrib.sessions.middleware.SessionMiddleware'."
request.__class__.user = LazyUser()
return None
The LazyUser calls get_user(request) to get the user:
Source: http://code.djangoproject.com/browser/django/trunk/django/contrib/auth/middleware.py?rev=14919#L5
class LazyUser(object):
def __get__(self, request, obj_type=None):
if not hasattr(request, '_cached_user'):
from django.contrib.auth import get_user
request._cached_user = get_user(request)
return request._cached_user
The get_user(request) method does a user_id = request.session[SESSION_KEY]
Source: http://code.djangoproject.com/browser/django/trunk/django/contrib/auth/init.py?rev=14919#L100
def get_user(request):
from django.contrib.auth.models import AnonymousUser
try:
user_id = request.session[SESSION_KEY]
backend_path = request.session[BACKEND_SESSION_KEY]
backend = load_backend(backend_path)
user = backend.get_user(user_id) or AnonymousUser()
except KeyError:
user = AnonymousUser()
return user
Upon accessing the session sets accessed to true:
Source: http://code.djangoproject.com/browser/django/trunk/django/contrib/sessions/backends/base.py?rev=14919#L183
def _get_session(self, no_load=False):
"""
Lazily loads session from storage (unless "no_load" is True, when only
an empty dict is stored) and stores it in the current instance.
"""
self.accessed = True
try:
return self._session_cache
except AttributeError:
if self._session_key is None or no_load:
self._session_cache = {}
else:
self._session_cache = self.load()
return self._session_cache
And that causes the session to initialize. The bug was caused by a faulty session backend that also generates a session when accessed is set to true...
Is it possible for robots to access any page where you set anything in a user session (even for anonymous users), or any page where you use session.set_test_cookie() (for example Django's default login view in calls this method)? In both of these cases a new session object is created. Excluding such URLs in robots.txt should help.
For my case, I wrongly set SESSION_SAVE_EVERY_REQUEST = True in settings.py without understanding the exact meaning.
Then every request to my django service would generate a session entry, especially the heartbeat test request from upstream load balancers. After several days' running, django_session table turned to a huge one.
Django offers a management command to cleanup these expired sessions!