The Django application loads data from a file to a Python dict, process it and sends it as http response. Now say n number of request are received on the web server then this Django app would run n times and load data from a file to a Python dict n times. I was wondering if somehow I can make this data being loaded to the dict only once while n http response could be served.
An example view.py file for the problem situation can be as followed:
from django.http import HttpResponse
from django.http import HttpRequest
def hello(request):
data = open("abc").readlines()
return HttpResponse(data[0])
Binding the dictionary to a global name will make it persist for as long as the Django project runs. Note that each Django process (some WSGI containers, e.g. mod_wsgi, can run multiple processes for an app) will have its own independent copy of the dictionary.
If the data is relevant to the user, you can use djanog's session framework to persist data across requests. If the data needs to be shared between numerous users, you can use the cache.
This is a job for the Django Middleware. Add it to your settings and it will persist across your request. Its a better option then persistence and definitely a lot better than using a global object.
Middleware is a framework of hooks into Django’s request/response processing. It’s a light, low-level “plugin” system for globally altering Django’s input and/or output. Each middleware component is responsible for doing some specific function. For example, Django includes a middleware component, XViewMiddleware, that adds an "X-View" HTTP header to every response to a HEAD request.
Related
I have a Django project that will ultimately consist of three apps. Two of which will be "normal" Django apps, the third is a djangorestframework app. I also plan on creating a desktop client for the project at some point.
I want the rest app to be the only entity communicating with the database. Hence I use requests to communicate with the rest endpoints from the views of the "normal" Django apps and I will do the same for the desktop client. I want all apps to be accessible only for authenticated users, so I'm using Django's authentication backend.
My question is how to pass on the authenticated user/session from the pure Django apps to the rest endpoints when using requests in the views.
I managed to authenticate on the rest API using request's HTTPBasicAuth, but that requires me to have the user's password at hand in plain text. Sure, I could create a technical user to do these requests. But that would also mean that each and every request would need to go through authentication first and that doesn't feel like the best approach.
I have tried to extract the session cookie from the request object that is provided to the views and pass it on through requests.get, but did not manage to put it into the requests.get call the right way.
As of now, using requests and the established sessions looks like my best bet, especially since that will be the way the desktop client will do things, too. So I'm currently looking for the right way to provide requests.get with the session cookie, but I'm certainly open for better solutions.
You should use tokens.
Basically any kind of authentication out of your django project should be managed with secure tokens.
And yes, authentication check should happen everytime you send a request. To make it faster, you can store tokens in memory. (You can use redis or maybe even load your db on memory or ... ) but this is the right and common way to it. Even django does this check everytime using it's builtin functions.
DRF docs recommended some few packages to manage these tokens:
DRF: Third party packages
I used knox for many projects and it's pretty good.
Basically to authenticate your users over all of your projects or microservices, you have to take the token from user, set it as header or ... for your request to the main database or authentication project.
Most of the apps use token in headers which you can simply add to all of your requests calls:
Requests docs: Custom Headers
According to the Flask 0.12 docs:
flask.g
...... Starting with Flask 0.10 this is stored on the application
context and no longer on the request context which means it becomes
available if only the application context is bound and not yet a
request.
As far as I know, when a request comes, a application context will be created, if there isn't one. So shouldn't flask.g be available after a request has come, since the request ensures the existence of an application context?
As a bouns question: why should I store database connections on g instead of request? I know creating a application context is less "expensive" than creating a request context, but when a request comes, a request context will be created anyway.
The wording there is a little awkward. The g object is available during a request as well. A request context is nested inside an application context.
You should store a database connection in the g object because it'll be available *even when there is no request, such as in the flask shell command, and any custom command-line commands. You'll need this when initialising your database, for example.
Next, there are advanced use-cases where you may want to create an 'internal' request, calling another route on your Flask app as if it came from outside. This nested request would re-use the existing app context.
There is never a request context without an application context.
Answering bonus question from Flask documentation:
For instance, the request variable is the request object associated
with the current request, whereas g is a general purpose variable
associated with the current application context.
flask.g is bound to the session of current request. That means that you have different g's for different requests. For example, I store a user in g object for easier access to it (it's not good, but fast to access and easy to use)
I'm developing a microservices architecture with Django in which services communicate each other through RESTful APIs.
A request coming from a client is served by a service, which then requires to make a new (nested) HTTP request to another service as it is shown in the picture below, in order to mantain decoupling between services.
In this scenario, it may happen that two different requests are fired by the client and served simultaneously by the first service. Then, one of the two nested requests to the second service remains unserved until a 503 error (Service Unavailable) occurs.
It seems that concurrency between nested requests is bad handled by the server.
RESTful APIs are implemented with Django REST framework and nested requests are made with the Python requests library. Here is an example:
from rest_framework.views import APIView
import requests
class FirstServiceView(APIView):
def get(self, request, format=None):
# Code...
# The nested requests to the second service
response = requests.get("http://127.0.0.1:8000/second_service/")
# Other code...
It's worth noting that this behaviour happens with both the development server of Django and Apache. Furthermore, no concurrency on the database is involved in this case.
I currently build a web application using flask, sqlalchemy and jinja2.
To get a proper web interface, I build my views as follows:
#app.route('/mydata/', methods=['GET'])
#login_required
def mydata_list():
# build data here...
return render_template('mydata/index.html', data=data))
Now, if I need to build a REST API, I am supposed to terminate with
return jsonify(data)
So, how to handle this to avoid code duplication? Is it a good practice to add a ?api=True to my url, test it in my view, then return appropriate answer?
There is really no right or wrong way to do this, more so with Flask, which is a framework that imposes so few rules on the developer.
If you want my opinion, I think using the same set of view functions for web site and API leads to code that is harder to maintain, because there are a few significant differences between the two, for example:
Authentication: this is typically done in very different ways for web vs. API.
Content: for the API you just return data, but for a web page the view function may need to do more work and obtain extra data that is only needed for rendering the template.
Request methods: APIs use more HTTP request methods than web apps. For example, to delete a resource through an API the client normally sends a DELETE request. A web application running on a web browser needs to do everything with GET and POST requests. Also, the POST request method has different usages in APIs vs. web apps.
My recommendation is that you make your view functions for both APIs and web apps very thin and put the business logic of your application in common classes that both sets of view functions can invoke.
If you want to use the same endpoint for serving a template as well as JSON data, you can test whether this is an AJAX request with request.is_xhr. For example:
#app.route('/numbers/')
def numbers():
data = [1, 2, 3]
if request.is_xhr:
return jsonify(data=data)
return render_template('numbers.html', data=data)
I've been using Django and Django passes in a request object to a view when it's run. It looks like (from first glance) in Flask the application owns the request and it's imported (as if it was a static resource). I don't understand this and I'm just trying to wrap my brain around WSGI and Flask, etc. Any help is appreciated.
In Flask request is a thread-safe global, so you actually do import it:
from flask import request
I'm not sure this feature is related to WSGI as other WSGI micro-frameworks do pass request as a view function argument. "Global" request object is a feature of Flask. Flask also encourages to store user's data which is valid for a single request in a similar object called flask.g:
To share data that is valid for one
request only from one function to
another, a global variable is not good
enough because it would break in
threaded environments. Flask provides
you with a special object that ensures
it is only valid for the active
request and that will return different
values for each request. In a
nutshell: it does the right thing,
like it does for request and session.