Using local_settings.py is awkward - here is a better way.

600 views
Skip to first unread message

Paul Whipp

unread,
May 28, 2014, 12:23:58 AM5/28/14
to mezzani...@googlegroups.com
Having the local_settings always outside of version control is a pain on large projects and not being able to arbitrarily alter settings (rather than simply overwrite them) is agony.

In 'normal' Django, the 'two scoops' method can easily be used to replace the local_settings.py import but in Mezzanine, there is the dynamic settings stuff at the end which both obfuscates how the settings are being set up and makes removing the use of local_settings relatively tricky.

For example; say I need to include an app - e.g. "debug_toolbar" so I want my local settings to have a line that does:

INSTALLED_APPS += ("debug_toolbar",)

In 'plain Django' I'd have a settings/base.py for all the base settings and I'd have a settings/dev.py that imports from it:

from settings.base import *

INSTALLED_APPS += ("debug_toolbar",)

Then my settings environment variable imports settings.dev locally and settings.live on the live site (or settings.staging... as appropriate) (I set this DJANGO_SETTINGS_MODULE in my virtualenv postactivate script making it a 'fire and forget' solution across multiple servers and sites).

The Mezzanine workaround is to make the 'local_settings' follow on from the set_dynamic_settings: Remove its import from the main settings file (which moves to settings/base.py) and then use a settings.dev.py as above for your 'local' settings (call it 'local' if you like but we have testers who run builds locally with different settings so that confuses things for us).

Mezzanine would be cleaner and easier to use if it abandoned the use of 'set_dynamic_settings' altogether.


Josh Cartmell

unread,
May 28, 2014, 10:21:44 AM5/28/14
to mezzani...@googlegroups.com
Hey Paul, it seems like you don't quite understand how local_settings.py works.  A project's settings.py imports local_settings.py allowing you to override settings as you like.  For example, in local_settings.py you could put:

INSTALLED_APPS += ("debug_toolbar",)

just like you want.

Also, leaving local_settings.py out of version control is intentional since it often contains sensitive information (db/email/etc... passwords) and settings that are different between development/production.  Mezzanine does have a version of local_settings.py that is included in version control and if you are using the fabfile to deploy it gets copied to a production server to server as it's local_settings.py.  That file is your project's deploy/local_settings.py.template (formerly deploy/live_settings.py).  In that way you can have settings that are particular to your dev environment in local_settings.py and settings specific to your production environment in deploy/local_settings.py.template.


--
You received this message because you are subscribed to the Google Groups "Mezzanine Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to mezzanine-use...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Paul Whipp

unread,
May 28, 2014, 4:24:18 PM5/28/14
to mezzani...@googlegroups.com
Thanks for the feedback Josh, I enjoy Django and am enjoying my increasing familiarity with Mezzanine. After rebuilding my own website with it, I've now created and deployed four client sites on Mezzanine so far.

INSTALLED_APPS is not in scope in local_settings.py so that line will not work and importing the settings in order to bring INSTALLED_APPS into scope is non-trivial because of the circularity issues.

For sensitive data I prefer to use environment variables so that the (non security relevant) settings for the various site installations are not left out of the repo requiring manual updates on each site when they change.

Putting the secure settings in local_settings.py results in developers and testers copying the file every which way - not good for security. While the same can be said of the bash script that sets up the secure elements as environment variables, this file quite literally stays unchanged for the life of the project so there is far less need to copy it about.

With the applications I have, a single development location and a single live site are not a common scenario (when they are the case, I leave local_settings.py as it is... until it becomes a pain). It has to go when there are staging sites, test sites, local variations for testers, mappers, developers...

My workaround is effective and I recommend it for any Mezzanine site where you need to deal with more than two working installations.

Don't mistake this for my not liking Mezzanine; it provides excellent leverage by giving me a lot of useful functionality from the outset without getting in the way of adding complex apps for data presentation.


--
You received this message because you are subscribed to a topic in the Google Groups "Mezzanine Users" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/mezzanine-users/NIyPsTXK5po/unsubscribe.
To unsubscribe from this group and all its topics, send an email to mezzanine-use...@googlegroups.com.

Josh Cartmell

unread,
May 29, 2014, 9:12:44 AM5/29/14
to mezzani...@googlegroups.com
Maybe I was the one who didn't quite understand ;)

Apologies if I jumped the gun with my comments.

Paul Whipp

unread,
May 29, 2014, 4:28:54 PM5/29/14
to mezzani...@googlegroups.com
No worries, it's why we have user groups ;)

Give the 'two scoops' (I don't know if they came up with it - it is where I read about it originally) settings folder method a try sometime.

It is very effective and you can always have a secrets.py settings file in the settings folder excluded from the repo if you don't like using environment variables for the secrets. That is clearer than hiding local_settings from the repo and will be unlikely to change over time.

Tzu-ping Chung

unread,
May 31, 2014, 8:51:02 AM5/31/14
to mezzani...@googlegroups.com

I’ve been thinking about this for quite some time personally.


The local_settings.py approach does lead to some unpleasant quirks sometimes, and the multi-settings-file approach Paul mentioned is being advocated by many lately, including PyDanny (in his Two Scoops of Django and many other occasions) and core Django developers.


I did personally use the multi-settings-file approach in some of my Mezzanine projects. Works fine for most of the functionalities as far as I am aware. There is, however, one big obstacle to adopt this for all Mezzanine projects: dynamic settings. What Mezzanine currently does is invoking set_dynamic_settings at the end of the settings.py file, after local_settings.py is imported. So things basically happen in the following order when a server starts: [1]

  • General settings (in settings.py) load.
  • User-specific settings (in local_settings.py) load.
  • Dynamic settings are generated (with set_dynamic_settings).
  • Your Django site starts running.

With this order, dynamic settings would contain all entries from general and user-specific settings, with the latter overrides general ones. But with the multi-settings-file approach, this is not that trivial to achieve. Since we use different settings files in different occasions, in order to invoke set_dynamic_settings after all settings (general and user-specific) are loaded, we’ll need to add set_dynamic_settings at the end of every setting files we wish to use. Which is obviously ugly and error-prone.


The idea is that since we can’t put the logic inside the settings files, it need to be hooked somewhere during Django’s standard startup sequence. But I’m yet to find a good place for this. A Django project has quite a few entry points (e.g. for runserver, test, and for begin served via a real WSGI server), and none of them provide good ways for hooks.


Would be glad if there are any thoughts on this. I’ve been troubled by the local_settings approachfor quite some time now, and would be more than happy if it could be improved or even go away completely.



[1]: This is not actually accurate since Django settings are loaded lazily, not on application startup. But for the purpose of this article it’s close enough.



Paul Whipp於 2014年5月30日星期五UTC+8上午4時28分54秒寫道:

Paul Whipp

unread,
Jun 1, 2014, 10:10:56 PM6/1/14
to mezzani...@googlegroups.com
I've not had any problems with the workaround. I think the mezzanine set_dynamic_settings should be phased out completely so that users can adopt any reasonable settings policy they like.

If there are really things that mezzanine needs to do to edit the settings, it should do them by editing the settings - perhaps via a management command.
Reply all
Reply to author
Forward
0 new messages