I have a bunch of apps, that may or may not contains a file called activity.py. This file basically registers model signals. It works well when I import this file in the ready method of the AppConfig class. The problem is I have a dozen app, so I don't want to have this same method in all my apps :
def ready(self):
# register signal for activity feed
from . import activity
I would like to run a script that will through the INSTALLED_APPS array, and if this app contains a file activity.py, import it.
I can't find a way to run a function for when all the apps are ready, and before the server is listening.
One thing you can do is create another app whose only purpose will be to perform that initialization and put it in INSTALLED_APPS. In that app, subclass AppConfig and override the AppConfig.ready() method.
You can try to use the following approach:
from django.conf import settings
from importlib import import_module
for app in settings.INSTALLED_APPS:
module_name = '%s.%s' % (app, "activity")
try:
import_module(module_name)
except ImportError:
pass
Related
Since Django 1.7 the AppConfig feature has been added suggesting that post_migrate signals should be put in the ready() part of its customized implementation - https://docs.djangoproject.com/en/stable/ref/signals/#post-migrate
The basic way to implement AppConfig described by the docs is to point to it in the __init__.py file using default_app_config setting. The docs would also suggest a way to override an existing AppConfig for any app:
https://docs.djangoproject.com/en/stable/ref/applications/#for-application-users
I have researched a bit and found out that django actually creates AppConfig instance for every app in INSTALLED_APPS even if its custom implementation is not implemented it would bootstrap the default for you.
My question is how one should provide a customized app configuration with post_migrate signal for an app that doesn't implement AppConfig (the easiest example would be a third party package without apps.py)?
I know that even for this app the django would go and create a default version of AppConfig but where and how should i tell it NOT to do so and use my custom AppConfig instead with overrided ready() method implementation to add post_migrate?
Let us suppose for a moment that you wished to create a custom AppConfig for django crispy_forms (which you have installed into your virtualenv).
Step 1: Create a folder named crispy_forms in your project.
Step 2: Create an __init__.py in that folder and paste the following
from django.apps import AppConfig
default_app_config = 'crispy_forms.apps.MyAppConfig'
step 3: Create an apps.py in crispy_forms folder and paste
from django.apps import AppConfig
class MyAppConfig(AppConfig):
verbose_name = 'customized crispy_forms'
name = "crispy_forms"
def __init__(self, app_name, app_module):
AppConfig.__init__(self,app_name, app_module)
print 'My app config', app_name, app_module
If django doesn't reload classes, restart the development server and then you will see something like:
My app config crispy_forms <module 'crispy_forms' from '/home/xxx/project/crispy_forms/__init__.pyc'>
My problem was quite the same, and answer here helped me to find a solution. I use in my Django app a dependency to "django-constance" to manage some application parameter inside Admin site.
But I wanted to be sure that some parameters are setup in constance as soon as you use my webapp application.
Unfortunatly, solution provided by #canufeel didn't worked, I could use constance subpackages in my app, 'import errors'.
Here is how I did it :
I created under my app a subpackage named 'myApp/constance', where I defined the same as mentioned by #canufeel.
But the change was mainly that I don't import anymore 'constance' package in INSTALLED_APPS, but 'myapp.constance' where I could override the settings like this :
MYAPP_CONSTANCE_CONFIG_VAR = {
'ACCOUNT_ACTIVATION_DAYS': (7, 'Number of days before activation is kept available'),
'BOOTSTRAP_THEME': ('slate', 'Bootstrap theme for front end', 'select_theme'),
...
}
Then override :
BASE_CONSTANCE_CONFIG = getattr(settings, 'CONSTANCE_CONFIG', {})
BASE_CONSTANCE_CONFIG.update(MYAPP_CONSTANCE_CONFIG_VAR)
settings.CONSTANCE_CONFIG = BASE_CONSTANCE_CONFIG_VAR
settings.CONSTANCE_ADDITIONAL_FIELDS = BASE_CONSTANCE_ADDITIONAL_FIELDS
settings.CONSTANCE_CONFIG_FIELDSETS = WAVES_CONSTANCE_CONFIG_FIELDSETS
that does the trick, still I think this is not a 'state of the art' solution :-)
I tried the other suggestions and they didn't work for me. But the official documentation did. The solution is so simple: For application users
To quote the Manual:
If you’re using “Rock ’n’ roll” in a project called anthology, but you
want it to show up as “Jazz Manouche” instead, you can provide your
own configuration:
# anthology/apps.py
from rock_n_roll.apps import RockNRollConfig
class JazzManoucheConfig(RockNRollConfig):
verbose_name = "Jazz Manouche"
# anthology/settings.py
INSTALLED_APPS = [
'anthology.apps.JazzManoucheConfig',
# ...
]
Recently, I've started building an app with Flask. It's pretty easy to use, yet powerful and fun to use. Unfortunately, I'm having problems understanding how the app context works. I know about current_app, app_context and that current_app references are supposed to be used inside requests, but that's probably part of my problem.
I'm building an app with the following folder structure:
app/
main/
__init__.py
error.py
forms.py
routes.py
static/
templates/
__init__.py
email.py
models.py
config.py
run.py
I'm doing an from flask import current_app in routes.py to import config settings and it works as expected.
But when I import current_app in forms.py I can do whatever I want, but I always get this error:
Traceback (most recent call last):
File "./run.py", line 6, in <module>
app = create_app('development')
File "/home/letmecode/Projects/python/flask/folder/app/__init__.py", line 34, in create_app
from main import main as main_blueprint
File "/home/letmecode/Projects/python/flask/folder/app/main/__init__.py", line 5, in <module>
from . import routes, errors, forms
File "/home/letmecode/Projects/python/flask/folder/app/main/routes.py", line 8, in <module>
from .forms import (ChangePasswordForm, ChangeEmailForm, CreateItemForm, RetrievePasswordForm, LoginForm,
File "/home/letmecode/Projects/python/flask/folder/app/main/forms.py", line 132, in <module>
class CreateItemForm(Form):
File "/home/letmecode/Projects/python/flask/folder/app/main/forms.py", line 133, in CreateItemForm
print current_app
File "/home/letmecode/.virtualenvs/folder/local/lib/python2.7/site-packages/werkzeug/local.py", line 362, in <lambda>
__str__ = lambda x: str(x._get_current_object())
File "/home/letmecode/.virtualenvs/folder/local/lib/python2.7/site-packages/werkzeug/local.py", line 302, in _get_current_object
return self.__local()
File "/home/letmecode/.virtualenvs/folder/local/lib/python2.7/site-packages/flask/globals.py", line 34, in _find_app
raise RuntimeError('working outside of application context')
RuntimeError: working outside of application context
forms.py is just a module that contains flask-wtf form classes and validator functions.
My problem is, that I want to reference the app context inside there, in order to get settings that are used throughout the app.
What am I doing wrong here? I guess what happens inside forms.py is not part of a request and therefore fails somehow. But how else am I supposed to reference the app context, then?
Edit:
#forms.py
from flask import current_app
#[...]
class CreateItemForm(Form):
title = TextField('Title', [
validators.Length(min=3, max=140),
validators.Regexp('^[a-zA-Z][a-zA-Z0-9 ]+$', 0, 'Item titles must start with a letter and consist of numbers and letters, only')
])
description = TextAreaField('Description', [
validators.Length(min=3, max=1000),
])
tags = TextField('Tags')
branch = SelectField(
'Branch',
choices=current_app.config['BRANCHES']
)
The underlying issue is that CreateItemForm and all of the attributes are created when the forms module is imported for the first time. That means that the branch field is created whenever import .form is run, and therefore current_app is accessed then:
# app/main/routes.py
from .forms import ( ..., CreateItemForm, ...)
Looking at your stack trace, this happens in your create_app call - most likely, your create_app looks something like this:
def create_app(config_name):
app = Flask('some-name-here')
app.config.from_SOMETHING(config_name)
# Register things here
from main import main as main_blueprint
app.register_blueprint(...)
return app
At # Register things here you can simply create an app_context and import everything inside of that:
# Register things here
# Creating an explicit application context to allow
# easy access to current_app.config, etc.
with app.app_context():
from main import main as main_blueprint
app.register_blueprint(...)
return app
I found that I was being an idiot. You don't have to provide choices per form model. You can (and should) provide them via the view/route function e.g.:
form.select_field.choices = [('value1', 'label1'), ('value2', 'label2')]
This doesn't explicitly answer my question, but renders it somewhat obsolete. However, I won't accept my own answer as a solution (yet), because I am curious as to whether it's at all possible to import configuration options from via app/current_app in this case, without getting hacky. If my curiosity won't be satisfied, I'll accept my own answer.
I wish the wtforms/flask-wtf documentation would focus less on the obvious and more on the not so obvious.
I have not been able to execute the deletion of any User that is created during test while tearDown() methods are run. Error is puzzling, as it suggest no models are loaded.
have tried the following:
User.objects.filter(id__in=users_to_remove).delete()
User.objects.filter(username='testuser2').delete()
And both return the same error message.
Does anyone know what is the propper way to delete a user from the testing file?
Detail of Functional Test File:
https://gist.github.com/leoreq/af090569980f06985f83
Error Message Returned:
Erorr Message returned in terminal
You need to call django.setup() after setting the environment variable.
# Set up django
import os
import sys
import django
project_dir = abspath(dirname(dirname(__file__)))
sys.path.insert(0, project_dir)
os.environ['DJANGO_SETTINGS_MODULE'] = 'slapp.settings'
django.setup()
I've got a weird problem.
I am building a Flask app with SQLAlchemy. I have a file with models, namely, models.py. And I have a User model there.
If I open my "views.py" and insert a string
import models
and then use the User model like
u=models.User.query.filter_by(name='John',password='Doe').first()
everything works fine.
But if instead of "import models" i put
from models import User
Python crashes and says:
ImportError: cannot import name User
how can this be possible?
you most likely have a circular import; your, lets say 'app' module:
# app.py
import models
...
def doSomething():
models.User....
but your models module also imports app
import app
class User:
...
since models imports app, and app imports models, python has not finished importing models at the point app tries to import models.User; the User class has not been defined (yet). Either break the cyclic import (make sure models doesn't import anything that also imports models), or you'll just have to make do with models.User instead of the shorter User in app.
Instead of
from models import User
use
from models import *
In this case, you are importing the models into views.py therefore if you need a class from models, import it from views.py and the circular import problem will be resolved.
I have a series of blueprints I'm using, and I want to be able to bundle them further into a package I can use as seamlessly as possible with any number of other applications. A bundle of blueprints that provides an entire engine to an application. I sort of created my own solution, but it is manual and requires too much effort to be effective. It doesn't seem like an extension, and it is more than one blueprint(several that provide a common functionality).
Is this done? How?
(Application dispatching methods of tying together several programs might work isn't what I'm looking for)
Check this out: Nesting Blueprints → https://flask.palletsprojects.com/en/2.0.x/blueprints/#nesting-blueprints
parent = Blueprint('parent', __name__, url_prefix='/parent')
child = Blueprint('child', __name__, url_prefix='/child')
parent.register_blueprint(child)
app.register_blueprint(parent)
I wish the Blueprint object has a register_blueprint function just as the Flask object does. It would automatically place and registered blueprints under the current Blueprints' url.
The simplest way would be to create a function that takes an instance of a Flask application and registers all your blueprints on it in one go. Something like this:
# sub_site/__init__.py
from .sub_page1 import bp as sb1bp
from .sub_page2 import bp as sb2bp
# ... etc. ...
def register_sub_site(app, url_prefix="/sub-site"):
app.register_blueprint(sb1bp, url_prefix=url_prefix)
app.register_blueprint(sb2bp, url_prefix=url_prefix)
# ... etc. ...
# sub_site/sub_page1.py
from flask import Blueprint
bp = Blueprint("sub_page1", __name__)
#bp.route("/")
def sub_page1_index():
pass
Alternately, you could use something like HipPocket's autoload function (full disclosure: I wrote HipPocket) to simplify the import handling:
# sub_site/__init__.py
from hip_pocket.tasks import autoload
def register_sub_site(app,
url_prefix="/sub-site",
base_import_name="sub_site"):
autoload(app, base_import_name, blueprint_name="bp")
However, as it currently stands you couldn't use the same structure as example #1 (HipPocket assumes you are using packages for each Blueprint). Instead, your layout would look like this:
# sub_site/sub_page1/__init__.py
# This space intentionally left blank
# sub_site/sub_page1/routes.py
from flask import Blueprint
bp = Blueprint("sub_page1", __name__)
#bp.route("/")
def sub_page1_index():
pass
I have solution for myself how to load blueprints defined in configuration, so then you can have something like CORE_APPS = ('core', 'admin', 'smth') in config and when you construct app you can register those apps (of course those strings in CORE_APPS must be the names of the files you want to import in your python path).
So I'm using function to create app:
app = create_app()
def create_app():
app = Flask(__name__)
# I have class for my configs so configuring from object
app.config.from_object('configsClass')
# does a lot of different stuff but the main thing could help you:
from werkzeug.utils import import_string
for app in app.config['CORE_APPS']
real_app = import_string(app)
app.register_blueprint(real_app)
After that your blueprint should be registered. Of course you can have different format in configs to support custom url prefixes and so on and so on :)
Of course you can also do something like this in your main blueprint, so in the application creation you will need to register that one main blueprint.