4

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?

Antoine Pinsard
  • 33,148
  • 8
  • 67
  • 87
canufeel
  • 893
  • 1
  • 11
  • 22

3 Answers3

7

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'>
canufeel
  • 893
  • 1
  • 11
  • 22
e4c5
  • 52,766
  • 11
  • 101
  • 134
  • Great suggestion! Thanks for that! But in this case i start getting the errors originating from some other parts of my app. The error context is basically like the following: `from crispy_forms.models import SomeModel ImportError: No module named 'crispy_forms.models'` – canufeel Apr 26 '16 at 15:19
  • Good observation! I didn't actually try an import from the crispy_forms app before posting this. Will take a look ASAP. – e4c5 Apr 26 '16 at 16:03
  • 1
    It seems that if we keep our `name = "crispy_forms"` Django would consider that this new custom app is a crispy_forms rewrite and then when we try to import anything from the initial `crispy_forms` plugin it would try to import it from our app. The `crispy_forms` in the `INSTALLED_APPS` would start pointing to our app with customized `AppConfing` as soon as we use the same name for it. – canufeel Apr 26 '16 at 16:18
1

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 :-)

marcoooo
  • 417
  • 4
  • 11
  • Remark : this solution may not work if multiple apps require to update constance configuration.... – marcoooo Feb 27 '17 at 08:31
  • Just pointed out in my project, in fact just need to add a file called by example "myapp_constance.py" in my apps, and include it in my __init__.py... job done, quite easy in fact :-) – marcoooo Feb 28 '17 at 12:09
1

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',
    # ...
]
run_the_race
  • 1,344
  • 2
  • 36
  • 62