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.

Reply via email to