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 <http://twoscoopspress.org/> 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 <https://github.com/stephenmcd/mezzanine/blob/master/mezzanine/project_template/settings.py#L364> 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秒寫道: > > 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. > > > On 29 May 2014 23:12, Josh Cartmell <[email protected] <javascript:>> > wrote: > >> Maybe I was the one who didn't quite understand ;) >> >> Apologies if I jumped the gun with my comments. >> >> >> On Wed, May 28, 2014 at 4:24 PM, Paul Whipp <[email protected] >> <javascript:>> wrote: >> >>> Thanks for the feedback Josh, I enjoy Django and am enjoying my >>> increasing familiarity with Mezzanine. After rebuilding my own website >>> <http://paulwhippconsulting.com> 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. >>> >>> >>> On 29 May 2014 00:21, Josh Cartmell <[email protected] <javascript:>> >>> wrote: >>> >>>> 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. >>>> >>>> >>>> On Wed, May 28, 2014 at 12:23 AM, Paul Whipp <[email protected] >>>> <javascript:>> wrote: >>>> >>>>> 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. >>>>> >>>>> >>>>> -- >>>>> 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 [email protected] <javascript:>. >>>>> >>>>> For more options, visit https://groups.google.com/d/optout. >>>>> >>>> >>>> -- >>>> 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 >>>> [email protected] <javascript:>. >>>> >>>> For more options, visit https://groups.google.com/d/optout. >>>> >>> >>> -- >>> 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 [email protected] <javascript:>. >>> For more options, visit https://groups.google.com/d/optout. >>> >> >> -- >> 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 >> [email protected] <javascript:>. >> For more options, visit https://groups.google.com/d/optout. >> > > -- 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 [email protected]. For more options, visit https://groups.google.com/d/optout.
