Django application override & import path?

811 views Asked by At

Let's have a django project using a 3rd party application. I'd like to override some of its modules without touching original files. Simple subclassing is not possible here, need to override code transparently as many other apps rely on original class names and functions.

Project's structure looks like:

django_project/
  __init__.py
  settings.py
  overrides/        <-- here is a subdir with apps overrides
    __init__.py
    payment/        <-- here is an example of app to override
      __init__.py
      admin.py
      forms.py      <-- this file is ignored, original is imported
      models.py
      tests.py
      views.py

settings.py was modified with

INSTALLED_APPS=(
    'satchmo_store.shop'
    #'payment'           # original values
    'overrides.payment'  # modified app
    ...
)

The above solution however does not work, because Django does not insert path of added app into modules search path (sys.path). Django just loads admin.py, models.py, tests.py and views.py, other files like forms.py are ignored.

Is this behaviour documented somewhere ? What exactly placing a module name in INSTALLED_APPS does behind scenes ?

I hacked the situation with hardcoding new modules search path in manage.py and Apache's setting of WSGIPythonPath.

import os.path
import sys

DIRNAME       = os.path.dirname(__file__)
APPS_OVERRIDE = os.path.join(DIRNAME, 'overrides')

if not APPS_OVERRIDE in sys.path:
    sys.path.insert(1, APPS_OVERRIDE)

I doubt this is the right way. Cann't find a guide describing apps overriding.

So, how can I properly override external Django application in my project ?

The bonus question: Do I need to copy whole application directory tree, not just particular files which are really modified ? As far as I know, Python stops at first matching module path, so it won't import other modules available in following parts of the search path.

2

There are 2 answers

2
Arpit On

Try including payment as well along with override.payment as satchmo uses payment module to process payments and payment code is flexible enough to include your code as well.

4
Wolph On

Example of how to override your form:

overrides/payment/forms.py

from django import forms
class YourNewFormThingy(forms.Form): pass

overrides/payment/models.py

from satchmo.payment import forms as satchmo_payment_forms
from . import forms

satchmo_payment_forms.SomeForm = forms.YourNewFormThingy