4

Should a component be its own application?. So we have separate our apps for that reason.

Now reusability does matter in Django. It is trivial to make our apps reusable when each module in the apps does not depends on another apps.

However, It is common to refer a model in another apps by adding ForeignKey('appname.MyModel'). It creates a hard dependency of the Django apps with another apps.

The same thing happened with import of another apps (i.e. from appname import MyModel). It creates a dependencies of the apps to another apps.

If the app contains such dependency of another apps, then it does not seems to be viable to share our apps (i.e. Not reusable).

What do I have to do to make the dependencies loose. And allow me to share my apps without having to hardcode another apps in the app.

Community
  • 1
  • 1
Yeo
  • 11,416
  • 6
  • 63
  • 90
  • Duplicate of http://stackoverflow.com/questions/11579232/how-to-bind-multiple-reusable-django-apps-together ? – Sylvain Biehler Jun 18 '15 at 08:40
  • @SylvainBiehler that one is more towards binding multiple reusable apps whereas mine is more towards decouping large app into multiple reusable apps. The question does have some overlapping but it is not the same. – Yeo Jun 18 '15 at 09:23
  • 1
    more like http://stackoverflow.com/questions/1419442/how-to-model-a-foreign-key-in-a-reusable-django-app?rq=1 ? – Sylvain Biehler Jun 18 '15 at 09:35
  • @SylvainBiehler Yes, :) This one solve the `ForeignKey` parts of my question. So now, The only question left is with the `import` as it still tightly coupled with the `appname`. Thank you. – Yeo Jun 18 '15 at 11:26

1 Answers1

4

So, it's worth noting that we don't really need to depend on your specific apps. We depend instead on having something that satisfies the same interfaces your apps expose.

This is the 'Pythonic' way to do things (sometimes referred to as duck typing as 'if it walks like a duck and quacks like a duck... it must be a duck').


You've had in comments how to solve the ForeignKey problem

To summarise, you can just add the value in settings.py:

MY_FK_MODEL = 'someapp.SomeModel'

and then use it in your models.py like so:

from django.conf import settings

class ReusableAppModel(models.Model):
    some_model = models.ForeignKey(settings.MY_FK_MODEL)

So far, so easy; now to solve the import.

We actually already have an example of this from Django itself. Which is the get_user_model() method.

We could make something like that by adding the following in settings.py:

MY_APP_DEPENDENCY = 'myapp.my_module.MyClass'

along with a helper function similar to get_user_model() somewhere in your reusable app. Let's say reusable_app/helpers.py for the sake of argument:

from django.conf import settings
from pydoc import locate


def get_my_app_dependency():
   dependency = locate(settings.MY_APP_DEPENDENCY)
   # locate() returns None if the class is not found,
   # so you could return a default class instead if you wished.
   return dependency

Then you can get that class wherever you need it by calling the method:

from reusable_app.helpers import get_my_app_dependency

MyAppDependency = get_my_app_dependency()

app_dep_instance = MyAppDependency()

The summary here is that you can allow users to specify a class/method/whatever as a string in settings.py and then use that to refer to your dependency.

This lets users 'inject' a dependency into your app.

One final note:

Whenever you have an app/module that has lots of dependencies on others, it's worth double checking to see if they really should be separate. You want to avoid creating one giant module satisfying lots of disparate responsibilities, but likewise you want to avoid artificially breaking code up when it doesn't make sense. It's a careful balance.

Tom Manterfield
  • 6,515
  • 6
  • 36
  • 52
  • Agreed, this is a good solution by using settings.py to inject all apps related dependencies. – Yeo May 06 '17 at 08:48