3

I am currently using Django==1.7.1. I have some reusable apps with same module name. This also makes app labels of models same. This is actually conflicting. You can't use both module with same name in different libraries, in your INSTALLED_APPS in your settings file.

I solved this by adding an AppConfig for the modules and changed their labels(app_label) to resolve confliction;

#librarayX.my_module.apps.py
from django.apps import AppConfig


class ModuleAppConfig(AppConfig):
    name = 'libraryX.my_module'
    label = "X_my_module"
    verbose_name = "my_module"



#librarayY.my_module.apps.py
from django.apps import AppConfig


class ModuleAppConfig(AppConfig):
    name = 'libraryY.my_module'
    label = "Y_my_module"
    verbose_name = "my_module"


#settings.py

....
INSTALLED_APPS=[
    ...
   'libraryX.my_module.apps.ModuleAppConfig',
   'libraryY.my_module.apps.ModuleAppConfig',
    ...
]
...

Now, I can add those app configs into my INSTALLED_APPS instead of modules. Conflicting is just resolved. Everything is OK until that point.

Here is my problem; When I override the label of the AppConfig, my models in that modules are not discovered by Django. When I run;

python manage.py makemigrations

Nothing seems changed. Despite I remove all migrations files, it did not even create initial one. I think, it does not see the models. Whenever I remove overridden label field from my app config, the models are discoverable back again. So, don't think my models location is wrong.

This could also be bug, I don't know. But if I am doing something wrong, what could it be?

Thanks!

Ahmet DAL
  • 4,445
  • 9
  • 47
  • 71
  • If you think this is a bug, then please log it on the django bug tracker here: https://code.djangoproject.com/newticket there are several people actively working on migration bug fixes, or they may be able to point you to a supported solution. – Josh Smeaton Dec 18 '14 at 12:59
  • Are you sure that the issue only manifests when you change the app label? Normally in Django 1.7, if you remove all migrations (and the migrations directory) for an app, Django won't create a new migrations directory for that app unless you explicitly give its label, e.g. `python manage.py makemigrations Y_my_module`, so it's expected that `python manage.py makemigrations` won't create initial migrations for apps without any. – Carl Meyer Dec 18 '14 at 13:40
  • Yep, I am sure. Even I run it with the new app_label, it says `No changes detected in app '.....'`. When I have some migrations, and I override `label`, it also creates a migration files which removes all of my models. I am sure, it does not import the models. I also described in my answer please see it. – Ahmet DAL Dec 18 '14 at 13:46
  • Maybe related for users of 1.8+ https://stackoverflow.com/a/43014201/2586761 – ptim May 29 '17 at 23:21

1 Answers1

3

I rewiewed most part of Django code deeply. Models in applications which have custom app label defined in the app config, as it is given in the question, are not being imported by Django. This is because, even you change the label in app config, models app_label is not changed. So, Django thinks, models and the custom app configs are for different application. I think, this is a bug.

In django.apps.registry, there is lines in populate method which is:

...
            # Load models.
            for app_config in self.app_configs.values():
                all_models = self.all_models[app_config.label]
                app_config.import_models(all_models)
...

This part should also import models in modules defined in app_config.name, not just for app_config.label.Cause, there are not gonna be models with app label same with the app config label. This is one of the problematic parts which causes the issue. This is not enough, changing models app_label somehow is also needed.

Solution:

Here is my workaround.

I have an abstract app config which all of my app configs are gonna be inherited from.

from collections import OrderedDict
from django.apps import AppConfig, apps


class BaseAppConfig(AppConfig):
    def __init__(self, *args, **kwargs):
        super(BaseAppConfig, self).__init__(*args, **kwargs)
        # Also import the models in modules defined in self.name
        mod_path, _, cls_name = self.name.rpartition('.')
        self.import_models(OrderedDict([(k, v) for k, v in apps.all_models[cls_name].iteritems() if self.name in v.__module__]))


    def import_models(self, all_models):
        if not self.models:
            # Set the model app_labels as self.label
            for m in all_models.values():
                m._meta.app_label = self.label
            super(BaseAppConfig, self).import_models(all_models)

This is a workaround not to touch Django code. But, I think this issue must be resolved in Django. Models app_labels should also change by the app_label value defined in the app config.

Community
  • 1
  • 1
Ahmet DAL
  • 4,445
  • 9
  • 47
  • 71
  • I don't have time at the moment to check this analysis, but would you be willing to file it as a bug at https://code.djangoproject.com/newticket ? If you can write a pull request adding a test to Django's test suite that demonstrates the bug, that's even better. – Carl Meyer Dec 18 '14 at 13:36
  • OK, I'll create a ticket and try to patch it when I find sometime. – Ahmet DAL Dec 18 '14 at 13:40
  • Hi Ahmet - did you ever create a ticket for this issue? – Carl Meyer Feb 17 '15 at 18:27
  • Hello @CarlMeyer, unfortunately I did not. I was gonna open it after I see your last comment and remember. But I tried it now, I can't reproduce the situation again with simple example with all `django 1.7` versions (0,1,2,3,4). I'll check that problematic part in my real project and test there soon and will open the ticket according to that result. – Ahmet DAL Feb 18 '15 at 10:27