Question

I ran into an issue regarding app specific settings.

I've got two Django projects, P1, and P2, each of them running in their own virtual env. P2 uses some models from the apps of P1, so I used add2virtualenv (thanks to virtualenvwrapper) to tackle with depedencies.

The issue is that some of these P1 apps are relying on custom settings (simply located in p1/project/settings.py, nothing fancy so far) which obviously strongly bother P2's execution.

For instance, when I run P2's tests:

$ ./p2/manage.py test

Traceback (most recent call last):
  File "./manage.py", line 11, in <module>
    execute_from_command_line(sys.argv)
  [...]
AttributeError: 'Settings' object has no attribute 'SOME_P1_APP_CUSTOM_SETTING'

How am I supposed to deal with that ? Is it broken by design, or does Django provide something elegant to handle the distribution of app specific settings ?
I'd like to avoid copy/pasting these settings in every project that requires them.

Was it helpful?

Solution 4

The possible solutions I found accross the web:

  1. Always access settings by calling getattr() with a default value.
    Pro: simple, elegant, sounds like a good practice.
    Con: won't help with settings for which a default value doesn't make sense (like an API key).
  2. Use a third party solution like django-appconf or django-appsettings.
    Pro: keeps you from diving too deep into the problematic. Con: some might find it quite overwhelming.
  3. Put the specific extra settings __init__.py file in the app root, like suggested in Chris Burnor's post.
    Pro: clearly highlights you app's settings, makes it easy to find and to ship Con: might be a hell to deploy if you use a templating system; also might be a bit misleading since it's not such a well known practice (to my knowledge).
  4. Introduce some logic around your settings handling, like in this snippet.
    Pro: does the job.
    Con: logic doesn't have anything to do there.

OTHER TIPS

If you've got two apps, one a backend and another a service which uses it, I'd recommend you mock the backend when testing the service which uses it. That's the key to the issue here: you're trying to run tests for Thing A which also needs Thing B to be running, and that's not really catered for by the Django testserver (which is what runs under the surface when you're executing tests).

So, yes, you need to fake the backend when testing the service (and vice versa).

There are various ways to do this, including using Python's 'mock' library to mock out the API of the other app (or, more specifically, mock the functions in MyService which talk to MyBackend) and return data objects that fit with whatever behaviour you're trying to test. Those fake responses could be based on actual test fixtures loaded from JSON dumped from other app, potentially.

To make life easier, you could also write a few tests in the backend repo to ensure that the schema for the mock backend data actually matches the schema of the real backend, which would avoid regressions if one or both apps changes. If you do use a fixture for that data, storing that mock data in an intermediary repo (and then including it as an external dependency of your codebase) would be one way to ensure that it's available to both codebases without needing the actual other codebase to be installed and running alongside it during tests.

I would use three different settings files: A common file used by the two projects and other two settings files (each one for project) that imports the common one and override or extends it with proper attributes.

It is a common practice to divide the settings file for dev or prod environment and import a common one settings. You can see a sample from django-skel project.

In each one of the two settings you can import everything from the common:

from common import *

1. One Quick and feasible solution is to Filter out all settings from P1, which are required for P2's execution and Put it in common.py

And In P2, either import common.py from P1

#### P2/settings.py ####
from p1.commons import *

or

Copy the common.py settings file to P2 and import.

#### P2/settings.py ####
from commons import *

2. If this the problem only with the Test runner. then I would recommend you to create a test_settings.py which would import from settings.py in P2:

#### P2/test_settings.py ####
from settings import *

### Put here all extra settings required for the P2's test execution

and use it to run Test using --settings option e.g.

.p2/manage.py --setting=test_settings test

A well structured Settings file structure is always preferred for non buggy Application. You can follow django-skel for more insight into a good settings structure

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top