这最终通过可以由部署配置重新配置的 Django 设置对象解决。它的灵感主要来自这里的技术:settings.py from django-rest-framework。
例如,我的项目中有这样一个设置文件:
yourproject/settings.py
"""
Settings for <YOUR PROJECT> are all namespaced in the YOUR_PROJECT config option.
For example your project's config file (usually called `settings.py` or 'production.py') might look like this:
YOUR_PROJECT = {
'PROCESS_TASK': (
'your_project.tasks.process_task',
)
}
This module provides the `yourproject_settings` object, that is used
to access settings, checking for user settings first, then falling
back to the defaults.
"""
# This file was effectively borrow from https://github.com/tomchristie/django-rest-framework/blob/8385ae42c06b8e68a714cb67b7f0766afe316883/rest_framework/settings.py
from __future__ import unicode_literals
from django.conf import settings
from django.utils.module_loading import import_string
DEFAULTS = {
'RESEND_NOTIFICATIONS_TASK': 'core.tasks.resend_notifications',
}
# List of settings that may be in string import notation.
IMPORT_STRINGS = (
'RESEND_NOTIFICATIONS_TASK',
)
MANDATORY_SETTINGS = (
'RESEND_NOTIFICATIONS_TASK',
)
def perform_import(val, setting_name):
"""
If the given setting is a string import notation,
then perform the necessary import or imports.
"""
if val is None:
return None
if callable(val):
return val
if isinstance(val, (list, tuple)):
return [perform_import(item, setting_name) for item in val]
try:
return import_string(val)
except (ImportError, AttributeError) as e:
msg = "Could not import '%s' for setting '%s'. %s: %s." % (val, setting_name, e.__class__.__name__, e)
raise ImportError(msg)
class YourProjectSettings(object):
"""
A settings object, that allows settings to be accessed as properties.
For example:
from your_project.settings import yourproject_settings as the_settings
print(the_settings.RESEND_NOTIFICATIONS_TASK)
Any setting with string import paths will be automatically resolved
and return the class, rather than the string literal.
"""
namespace = 'YOUR_PROJECT'
def __init__(self, mandatory=None, defaults=None, import_strings=None):
self.mandatory = mandatory or MANDATORY_SETTINGS
self.defaults = defaults or DEFAULTS
self.import_strings = import_strings or IMPORT_STRINGS
self.__check_settings()
@property
def user_settings(self):
if not hasattr(self, '_user_settings'):
self._user_settings = getattr(settings, self.__class__.namespace, {})
return self._user_settings
def __getattr__(self, attr):
if attr not in self.defaults and attr not in self.mandatory:
raise AttributeError("Invalid Pyrite setting: '%s'" % attr)
try:
# Check if present in user settings
val = self.user_settings[attr]
except KeyError:
# Fall back to defaults
val = self.defaults[attr]
# Coerce import strings into classes
if attr in self.import_strings:
val = perform_import(val, attr)
# Cache the result
setattr(self, attr, val)
return val
def __check_settings(self):
for setting in self.mandatory:
if setting not in self.user_settings:
raise RuntimeError(
'The "{}" setting is required as part of the configuration for "{}", but has not been supplied.'.format(
setting, self.__class__.namespace))
yourproject_settings = YourProjectSettings(MANDATORY_SETTINGS, DEFAULTS, IMPORT_STRINGS)
这让我可以:
然后在我的视图函数中,我通过设置访问正确的函数:
core/views.py
... imports etc...
from yourproject.settings import yourproject_settings as my_settings
def handle_user_resend_request(request, user_id):
user = get_object_or_404(id=user_id)
if request.method == 'POST':
for follower in user.followers:
my_settings.RESEND_NOTIFICATIONS_TASK(follower.id)
... etc etc ...