Django 2: how to run code once on app initialization? - django

Using Django 2.2, how can I run code once after the code has been loaded but before any request is handled? (Similar to code executed in Rails initializers).
The use case is the following:
I'd like to create a pool of connections to a database and assign it to a global variable in a module but preferably not during module import.
(Initially following: https://stackoverflow.com/a/1117692/3837660, I was doing it at module import. But this is not optimal. Partly because I am facing a double import issue which I haven't solved yet and partly because I'd like to avoid creating a pool of connections at module import time.)
It should be done exactly once (no matter if that module happens to be imported twice) but at the application start (not on the first request).
=============================
EDIT:
Apparently running
python manage.py runserver localhost:8000
will call manage.py main twice. As a consequence, everything is imported twice and the ready function is also called twice.

I think you can take advantage of the django AppConfig, docs here -> https://docs.djangoproject.com/en/2.2/ref/applications/#django.apps.AppConfig
from django.apps import AppConfig
from django.utils.translation import ugettext_lazy as _
class YOURAPPNAMEConfig(AppConfig):
name = 'YOURAPPNAME'
verbose_name = _('VERBOSE APP NAME')
def ready(self):
CODE YOU WANT TO RUN ON APP READY
Let us know if this helps you.

Related

Exchanging data between django apps in the same project

I would like to exchange data between two django apps that are coming from a single big app that due to the increasing size and functionalities we decided to split.
Specifically I need to retrive only a string in one app from the other. Litterally a 10 character string.
The only thing that I found at the moment that satisfies me, since I would like to avoid import stuff from the other app (to me it seems not a clean way to do it, in the other case please change my mind), is making an http request from one app to the other.
Anyway I found it overkill.
Is there a clean way to achive this without using http request or imports?
If you mean constant app configuration data, that lives in the project settings.py adnd doesn't change except at a server re-start
from django.conf import settings
more
It's possible to make an import fail soft, if you just want to handle the case where the other app is not installed. For example
try:
from other_app.models import Foo
except ModuleNotFoundError:
from .models import Foo_Stub as Foo
(obviously you can get as sophisticated as you want with your stub models and other methods that aren't available from the other app).

Import Django models from outside the project

I'm working on an app which uses two tables from different databases.I manage to make the connection and make the tables structures in models.py, but now one I change the models.py file, I copy one of the tables in another python script, and I put the file elsewhere for other people to use it.My question it is possible in Django to import a model from outside the project? or the package?
The App is called banner_manager and in views.py I want to import a model called user from another project called django_models
when I try to import like this:
from ....models_django import models.py(in models.py it's the class "user" defined) it says: ValueError: Attempted relative import beyond top-level package
You can add this directory to PYTHONPATH for example:
export PYTHONPATH=$PYTHONPATH:/var/python/your-libs
And then just import package as normal:
import models_django

Flask: accessing application config in other files (anywhere and not just while serving requests)

I didn't get it clearly from Flask docs. Also, I can see similar stackoverflow questions but I still didn't get my answer, hence asking.
I have a flask application served using gunicorn+gevent. Gunicorn worker process, on start, creates a Flask application. Then it imports some files that setup a few global things, like a udp connection to a statsd server, etc. The setup needs to be done only once i.e. on worker process start and not with every client request. The setup code in the imported files needs access to config variables.
I know that while serving a request I can use the current_app proxy, but not outside a request.
One way can be: put Flask app creation code in a separate file and include it wherever you need access to config.
Ex:
file: mywsgi.py
from flask import Flask
application = Flask(__name__)
application.config.from_pyfile('myconfig.cfg')
file: mygunicornapp.py
from mywsgi import application
import file1
import file2
# import more files
file: file1.py
from mywsgi import application
# use the application config to setup something
file: file2.py
from mywsgi import application
# use the application config to setup something
Is this the preferred way?
Flask doc says I can create application context explicitly.
Can I push application context, just after creating my flask app, and never pop it. So that the application context is always there as long as my process runs and the current_app proxy will be available application wide even when no request being served?
Ex:
from flask import Flask
application = Flask(__name__)
application.config.from_pyfile('myconfig.cfg')
application.app_context().push()
Now I should be able to use the current_app proxy anywhere in my code. Thoughts, please!
== Update ==
The files file1.py, file2.py etc are imported for adding routes to the application. They provide the functions that handle my api requests. So the file mygunicornapp.py looks more like:
file: mygunicornapp.py
from mywsgi import application
from file1 import API1
#application.route("/api1")
def handle_api1():
return API1.handler()
from file2 import API2
#application.route("/api2")
def handle_api2():
return API2.handler()
# many more routes
Now file1 imports many other files and they, in turn, import many more files. Any of these imported files may need access to a config parameter that I have set on the application object. The question is: How do I make the application object available to all these files? Do you suggest that I pass the application object to each file?
Is it possible to just delay adding routes? I mean set routes after current_app context local is available. That means the files will be imported after current_app is available. I tried adding routes to the current_app context local in 'before_first_request' callback. The problem with that is, the very first request returns 404. Subsequent returns give a correct response.
Why don't you make functions in file1 and file2, and pass the argument app into them? Then you can call these functions in your setup code in mywsgi.py, using as an argument the app object you just created.
This should work much better than some of the other things you suggested. The different files importing each other is close to a circular import. Pushing an app context is also something that leaves you likely to end up with difficult to understand bugs.
If you create the object app in one file and import it from that file everywhere, you basically have a global variable (using a namespace). This is going to cause problem when you want to test your app setup code, or create more than one version of your app for another reason. There is also the issue that you won't be able to import any of file1, file2 without creating an app object. While testing these, or possibly re-using some of that code outside of Flask, this will be a pain.
It's much better to create the app object once and pass it around. Having a function which returns the newly created app, which can be imported and called from anywhere, is a common way of organizing a flask app. This file is often called factory.py. It makes it easier to create zero, one or more copies of the app, rather than making it more difficult.

Trouble importing function from one views.py to another app in django

I have two apps login and someother
I am trying to import a function like
From login.views import save
In someother.views.py
But getting ImportError: No module named views
I found the answer to my question.
Here it is.
My app name was "login" and have feature.py in the same.
when i tried to import feature using
from login import feature
IDE was not showing any issues. intellisense was working fine.
but when i tried to runserver it thrown ImportError: No module named feature.
and as soon as i changed login to extended_login it worked.
So i think some Keywords are not acceptable as app names or there is already a (system) app named with that keywords which actually do not have a module you trying to import.

Django unittests - ImproperlyConfigured error

Im trying to write tests for my module. When i run:
python manage.py test my_module
Im getting message:
django.core.exceptions.ImproperlyConfigured: Please fill out the database NAME in the settings module before using the database.
I dont have any test yet, just BaseTest where im creating users, groups and assigning permissions.
Where could be the problem? Server normally works, configuration seems to be good. Do i need to define settings for test?
Ok. I think i know what was the problem :] I had lists with permissions stored in other module. So i were writting from module.perms import perms (normal python list). Its seems, that python is doing something more than just import that list from other module to my module. And that was the cause of failing.
Solution:
Surround code after list definition with:
if __name__ == "__main__":
...
Then everything should be working good.
Ok. I think i know what was the problem :] I had lists with permissions stored in other module. So i were writting from module.perms import perms (normal python list). Its seems, that python is doing something more than just import that list from other module to my module. And that was the cause of failing.
Solution: Surround code after list definition with:
if __name__ == "__main__":
...
Then everything should be working good.
You need to have your DATABASE setting in place in settings.py, and your app needs to be in installed apps. For example:
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': 'database.sqlite',
python manage.py test doesn't use the NAME database defined in settings.py DATABASES. From the docs -
Tests that require a database (namely, model tests) will not use your
"real" (production) database. Separate, blank databases are created
for the tests.
Regardless of whether the tests pass or fail, the test databases are
destroyed when all the tests have been executed.
By default the test databases get their names by prepending test_ to
the value of the NAME settings for the databases defined in DATABASES.
When using the SQLite database engine the tests will by default use an
in-memory database (i.e., the database will be created in memory,
bypassing the filesystem entirely!). If you want to use a different
database name, specify TEST_NAME in the dictionary for any given
database in DATABASES.
To answer your question. You can define a test database with the TEST_NAME setting. But you shouldn't have to.
Here's another potential solution for people finding this through search:
I was trying to define my own TestRunner class inside my settings file, which meant it had to import DjangoTestSuiteRunner. This import at the top of the file caused the ImproperlyConfigured error. Moving the custom TestRunner class to a separate file resolved the issue.