Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve app settings #906

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions changelog.d/+improve-app-settings.changed.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Make it possible to change any setting via the (EXTRA|OVERRIDING)\_APPS-machinery .
54 changes: 47 additions & 7 deletions docs/reference/site-specific-settings.rst
Original file line number Diff line number Diff line change
Expand Up @@ -58,16 +58,40 @@ Settings for adding additional Django apps
Format of the app settings
~~~~~~~~~~~~~~~~~~~~~~~~~~

Both settings are a list of dicts.

App
...

Both settings are a list of dicts. The minimal content of the dict is::
To add an app, the minimal content of the dict is::

{ "app_name": "myapp" }

"myapp" is the same string you would normally put into
:setting:`INSTALLED_APPS`.

Settings
........

You can overwrite any setting with the "settings"-key::

{
"settings": {
"LOGIN_URL": "/magic/"
}
}

This is useful for settings that do not belong to specific apps.

You can set settings for an app too::

{
"app_name": "myapp",
"settings": {
"MYAPP_MAGIC_NUMBER": 785464279385649275692
}
}

Urls
....

Expand All @@ -85,7 +109,7 @@ There are two possible formats:
"app_name": "myapp",
"urls": {
"path": "myapp/",
"urlpatterns_module": "myapp.urls",
"urlpatterns_module": "myapp.urls"
}
}

Expand All @@ -100,7 +124,7 @@ There are two possible formats:
"urls": {
"path": "myapp/",
"urlpatterns_module": "myapp.urls",
"namespace": "mynamespace",
"namespace": "mynamespace"
}
}

Expand All @@ -125,22 +149,30 @@ Format::
"context_processors": [
"holiday_cheer.context_processors.date_context",
"holiday_cheer.context_processors.holidays"
],
]
}

Context processors that are not specific to an app can also be set::

{
"context_processors": [
"django.template.context_processors.debug"
]
}

Middleware
..........

Optionally, additional middlewares can be added to :setting:`MIDDLEWARE`-setting.
Optionally, additional middlewares can be added to the :setting:`MIDDLEWARE`-setting.

Format::

{
"app_name": "holiday_cheer",
"middleware": {
"holiday_cheer.appended_middleware": "end",
"holiday_cheer.prepended_middleware": "start",
},
"holiday_cheer.prepended_middleware": "start"
}
}

Subformat::
Expand All @@ -153,6 +185,14 @@ possible to prepend (ACTION is "start"). A prepended middleware will be run
*before* the security- and session middlewares which might not be what you
want.

Middleware not belonging to an app can also be added::

{
"middleware": {
"django.middleware.cache.GZipMiddleware": "end"
}
}

Dataporten
----------

Expand Down
5 changes: 3 additions & 2 deletions src/argus/site/settings/_serializers.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from typing import Optional, List, Dict
from typing import Optional, List, Dict, Any

from pydantic import BaseModel, Field, RootModel

Expand All @@ -10,10 +10,11 @@ class AppUrlSetting(BaseModel):


class AppSetting(BaseModel):
app_name: str
app_name: Optional[str] = None
urls: Optional[AppUrlSetting] = None
context_processors: Optional[List[str]] = None
middleware: Optional[Dict[str, str]] = None
settings: Optional[Dict[str, Any]] = None


class ListAppSetting(RootModel):
Expand Down
38 changes: 15 additions & 23 deletions src/argus/site/settings/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@

# Import some helpers
from . import *
from ..utils import update_context_processors_list, update_middleware_list
from ..utils import update_settings

# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/4.2/howto/deployment/checklist/
Expand All @@ -26,15 +26,6 @@

ALLOWED_HOSTS = []

# Application definition

_overriding_apps_env = get_json_env("ARGUS_OVERRIDING_APPS", [], quiet=False)
OVERRIDING_APPS = validate_app_setting(_overriding_apps_env)
del _overriding_apps_env
_extra_apps_env = get_json_env("ARGUS_EXTRA_APPS", [], quiet=False)
EXTRA_APPS = validate_app_setting(_extra_apps_env)
del _extra_apps_env

# fmt: off
# fsck off, black
INSTALLED_APPS = [
Expand Down Expand Up @@ -100,19 +91,6 @@
}
]

# override themes, urls, context processors
if OVERRIDING_APPS:
_overriding_app_names = [app.app_name for app in OVERRIDING_APPS]
INSTALLED_APPS = _overriding_app_names + INSTALLED_APPS
TEMPLATES = update_context_processors_list(TEMPLATES, OVERRIDING_APPS)
MIDDLEWARE = update_middleware_list(MIDDLEWARE, OVERRIDING_APPS)
# add extra functionality without overrides
if EXTRA_APPS:
_extra_app_names = [app.app_name for app in EXTRA_APPS]
INSTALLED_APPS += _extra_app_names
TEMPLATES = update_context_processors_list(TEMPLATES, EXTRA_APPS)
MIDDLEWARE = update_middleware_list(MIDDLEWARE, EXTRA_APPS)

WSGI_APPLICATION = "argus.site.wsgi.application"

# Database
Expand Down Expand Up @@ -334,3 +312,17 @@
#
# SOCIAL_AUTH_DATAPORTEN_FEIDE_KEY = SOCIAL_AUTH_DATAPORTEN_KEY
# SOCIAL_AUTH_DATAPORTEN_FEIDE_SECRET = SOCIAL_AUTH_DATAPORTEN_SECRET

# App settings: override themes, urls, context processors

# add apps that may override other apps
_overriding_apps_env = get_json_env("ARGUS_OVERRIDING_APPS", [], quiet=False)
OVERRIDING_APPS = validate_app_setting(_overriding_apps_env)
del _overriding_apps_env
update_settings(globals(), OVERRIDING_APPS, override=True)

# add extra functionality without overrides
_extra_apps_env = get_json_env("ARGUS_EXTRA_APPS", [], quiet=False)
EXTRA_APPS = validate_app_setting(_extra_apps_env)
del _extra_apps_env
update_settings(globals(), EXTRA_APPS)
6 changes: 3 additions & 3 deletions src/argus/site/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
from argus.auth.views import ObtainNewAuthToken, AuthMethodListView
from argus.dataporten import views as dataporten_views
from argus.notificationprofile.views import SchemaView
from argus.site.utils import get_urlpatterns_from_setting
from argus.site.utils import get_urlpatterns
from argus.site.views import error, index, MetadataView


Expand All @@ -51,10 +51,10 @@
path("", index, name="api-home"),
]

prefixed_urlpatterns = get_urlpatterns_from_setting(settings.OVERRIDING_APPS)
prefixed_urlpatterns = get_urlpatterns(settings.OVERRIDING_APPS)
if prefixed_urlpatterns:
urlpatterns = prefixed_urlpatterns + urlpatterns

postfixed_urlpatterns = get_urlpatterns_from_setting(settings.EXTRA_APPS)
postfixed_urlpatterns = get_urlpatterns(settings.EXTRA_APPS)
if postfixed_urlpatterns:
urlpatterns += postfixed_urlpatterns
36 changes: 33 additions & 3 deletions src/argus/site/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,15 @@
from django.urls import include, path


def get_urlpatterns_from_setting(setting):
if not setting:
def get_app_names(app_settings):
return [app.app_name for app in app_settings if app.app_name]


def get_urlpatterns(app_settings):
if not app_settings:
return []
urlpatterns = []
for app in setting:
for app in app_settings:
if not app.urls:
continue
if app.urls.namespace:
Expand Down Expand Up @@ -58,3 +62,29 @@ def update_middleware_list(middleware_setting, app_settings):
end_list.append(middleware)
safety_copy = start_list + safety_copy + end_list
return safety_copy


def get_settings(app_settings):
settings = {}
for app in app_settings:
if not getattr(app, "settings", None):
continue
settings.update(app.settings)
return settings


def update_settings(current_settings, app_settings, override=False):
TEMPLATES = current_settings["TEMPLATES"]
INSTALLED_APPS = current_settings["INSTALLED_APPS"]
MIDDLEWARE = current_settings["MIDDLEWARE"]

_app_names = get_app_names(app_settings)
if override:
INSTALLED_APPS = _app_names + INSTALLED_APPS
else:
INSTALLED_APPS += _app_names
TEMPLATES = update_context_processors_list(TEMPLATES, app_settings)
MIDDLEWARE = update_middleware_list(MIDDLEWARE, app_settings)

for setting, value in get_settings(app_settings.items()):
current_settings[setting] = value
Loading