Search code examples
djangonamespacesforeign-key-relationshipdjango-appssubapplication

django app with subapps. app_labels for subapps and foreignkey relations between them


I'm trying create a django app with multiple subapps. My current dir layout for the app is (filtered out admin.py, test.py and views.py for brevity):

myapp
    __init__.py
    models.py
    subapp1/
        __init__.py
        models.py
    subapp2
        __init__.py
        models.py

Where myapp/models.py looks like:

class Foo(models.Model):
    name = models.CharField(max_length=32)

and myapp/subapp1/models.py looks like:

class Bar(models.Model):
    foo = models.ForeignKey('myapp.Foo')
    some_other_field = models.CharField(max_length=32)

and myapp/subapp2/models.py looks like:

class Baz(models.Model):
    bar = models.ForeignKey('subapp1.Bar')

In my settings.py I have:

INSTALLED_APPS = (
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'myapp',
    'myapp.subapp1',
    'myapp.subapp2'
)

However when I attempt to run ./manage.py makemigrations myapp.subapp1 I get the error:

App 'myapp.subapp1' could not be found. Is it in INSTALLED_APPS?

But I am able to run ./manage.py makemigrations subapp1 and the equivalent for subapp2 successfully. What I'm worried about is app namespace collisions.

If I add a myapp/subapp1/apps.py

from django.apps import AppConfig

class SubApp1Config(AppConfig):
    name = 'myapp.subapp1'
    label = 'myapp.subapp1'

and then to myapp/subapp1/__init__.py

default_app_config = 'myapp.subapp1.apps.SubApp1Config'

Do the equivalent for 'myapp/subapp2' and comment out 'myapp.app2' from INSTALLED_APPS

I can then run ./manage.py makemigrations myapp.subapp1 successfully.

However if I then uncomment myapp.subapp2 from INSTALLED_APPS

and change myapp/subapp2/models.py to look like:

class Baz(models.Model):
    bar = models.ForeignKey('myapp.subapp1.Bar')

and then run ./manage.py makemigrations myapp.subapp2 I get:

SystemCheckError: System check identified some issues:

ERRORS:
myapp.subapp2.Baz.bar: (fields.E300) Field defines a relation with model 'myapp.subapp1.Bar', which is either not installed, or is abstract.

How am I supposed to describe the foreign key relation between myapp.subapp2.Baz.bar and myapp.subapp1.Bar?

Thanks in advance.


Solution

  • I actually figured this out long ago, but I suppose I shouldn't keep a question unanswered. I didn't end up having to use this - it was merely an exercise in making part of an app optional. Having a foreign key between optional subapps was a bit contrived, I was simply trying to figure out how to reference them.

    It turned out I was simply confused between the app_label and what you put in INSTALLED_APPS

    In this case, I'd simply set the app_labels to myapp_subapp1 and myapp_subapp2, however, in INSTALLED_APPS, they'd be installed as myapp.subapp1 and myapp.subapp2.

    This will both list the subapps when you type ./manage.py showmigrations as myapp_subapp1 and myapp_subapp2 rather than subapp1 and subapp2, which was worrying as a subapp with a real name might clash with something else. For instance, I don't like how django-mutant doesn't namespace it's contrib stuff, so you end up with app_labels like web, text, which could totally class with something instead of mutant_web, etc.

    Then when using foreign keys they'd be referenced as myapp_subapp1.Bar instead of what I was doing previously as 'myapp.subapp1.Bar'