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

Reset settings admin #145

Open
wants to merge 2 commits into
base: main
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
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ config and manage typed extra settings using just the django admin.
## Installation
- Run `pip install django-extra-settings`
- Add `extra_settings` to `settings.INSTALLED_APPS`
- Run `python manage.py reset_extra_settings`
- Run `python manage.py migrate`
- Run `python manage.py collectstatic`
- Restart your application server
Expand Down Expand Up @@ -234,6 +235,11 @@ def test_with_custom_settings(self):
pass
```

### Reset
You can remove all settings and revert to default values described in `settings.py`.
For that you could run this command `python manage.py reset_extra_settings`.


## Testing
```bash
# clone repository
Expand Down
21 changes: 21 additions & 0 deletions extra_settings/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
from django.contrib.admin.sites import NotRegistered
from django.core.exceptions import ImproperlyConfigured
from django.utils.translation import gettext_lazy as _
from django.urls import path, reverse
from django.shortcuts import redirect

from extra_settings.forms import SettingForm
from extra_settings.models import Setting
Expand Down Expand Up @@ -55,6 +57,7 @@ def queryset(self, request, queryset):

class SettingAdmin(admin.ModelAdmin):
form = SettingForm
change_list_template = "extra_settings/changelist.html"
value_fields_names = (
"value_bool",
"value_date",
Expand Down Expand Up @@ -123,6 +126,24 @@ def get_fieldsets(self, request, obj=None):
def get_readonly_fields(self, request, obj=None):
return ("value_type",) if obj else ()

def get_urls(self):
urls = super().get_urls()
my_urls = [
path(
"reset/",
self.reset_settings,
name=f"{settings.EXTRA_SETTINGS_ADMIN_APP}_setting_reset",
),
]
return my_urls + urls

def reset_settings(self, request):
"""Reset existing settings to default values"""
Setting.reset_to_default()
return redirect(
reverse(f"admin:{settings.EXTRA_SETTINGS_ADMIN_APP}_setting_changelist")
)

class Media:
css = {
"all": ("extra_settings/css/extra_settings.css",),
Expand Down
4 changes: 0 additions & 4 deletions extra_settings/apps.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
from django.apps import AppConfig
from django.conf import settings
from django.db.models.signals import post_migrate


class ExtraSettingsConfig(AppConfig):
Expand All @@ -10,6 +9,3 @@ class ExtraSettingsConfig(AppConfig):

def ready(self):
from extra_settings import signals # noqa: F401
from extra_settings.models import Setting

post_migrate.connect(Setting.set_defaults_from_settings, sender=self)
Empty file.
Empty file.
27 changes: 27 additions & 0 deletions extra_settings/management/commands/reset_extra_settings.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
"""
Command to reset extra settings.
"""

import logging

from django.core.management import BaseCommand
from extra_settings.models import Setting

log = logging.getLogger(__name__)


class Command(BaseCommand):
"""Django-command for refreshing extra settings to default values"""

help = """
This command will remove all extra settings and recreate only those
that described in `settings.EXTRA_SETTINGS_DEFAULTS`.
"""

def handle(self, *_, **__) -> None:
"""
Handle command.
"""
log.info("Start refreshing extra settings...")
Setting.reset_to_default()
log.info("Refreshing of extra settings is done.")
6 changes: 6 additions & 0 deletions extra_settings/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,12 @@ def set_defaults(cls, defaults):
def set_defaults_from_settings(cls, *args, **kwargs):
cls.set_defaults(settings.EXTRA_SETTINGS_DEFAULTS)

@classmethod
def reset_to_default(cls) -> None:
"""Reset all settings to default values"""
cls.objects.all().delete()
cls.set_defaults_from_settings()

TYPE_BOOL = "bool"
# TYPE_COLOR = "color" # TODO
TYPE_DATE = "date"
Expand Down
11 changes: 11 additions & 0 deletions extra_settings/templates/extra_settings/changelist.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{% extends 'admin/change_list.html' %}
{% load i18n admin_urls %}

{% block object-tools-items %}
{% if has_add_permission %}
<li>
<a href="{% url opts|admin_urlname:'reset' %}" class="historylink">{% translate "Reset settings" %}</a>
</li>
{% endif %}
{{ block.super }}
{% endblock %}
55 changes: 44 additions & 11 deletions tests/test_admin.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
from django.contrib.admin.sites import AdminSite
from django.test import TestCase
from django.test import TestCase, override_settings

from unittest.mock import patch

from extra_settings.admin import SettingAdmin
from extra_settings.forms import SettingForm
Expand All @@ -20,18 +22,15 @@ def has_perm(self, perm):


class ExtraSettingsAdminTestCase(TestCase):
def setUp(self):
self._setting_obj, setting_created = Setting.objects.get_or_create(
@classmethod
def setUpClass(cls):
super().setUpClass()
cls._setting_obj = Setting.objects.create(
name="PACKAGE_NAME",
defaults={
"value_type": Setting.TYPE_STRING,
"value_string": "django-extra-settings",
},
value_type=Setting.TYPE_STRING,
value_string="django-extra-settings",
)
self._site = AdminSite()

def tearDown(self):
pass
cls._site = AdminSite()

def test_changelist_form(self):
ma = SettingAdmin(model=Setting, admin_site=AdminSite())
Expand Down Expand Up @@ -84,3 +83,37 @@ def test_readonly_fields(self):
self.assertEqual(
ma.get_readonly_fields(request, self._setting_obj), ("value_type",)
)

@override_settings(
EXTRA_SETTINGS_DEFAULTS=[
{
"name": "foo",
"type": "string",
"value": "bar",
},
]
)
@patch("extra_settings.admin.redirect")
@patch("extra_settings.admin.reverse")
def test_modeladmin_reset(self, mock_redirect, mock_reverse):
self.assertEqual(Setting.objects.count(), 1)
self._setting_obj.value_string = "foo"
self._setting_obj.save()
Setting.objects.create(
name="bar",
value_type=Setting.TYPE_BOOL,
value_bool=True,
)
ma = SettingAdmin(model=Setting, admin_site=AdminSite())
ma.reset_settings(request)
self.assertEqual(Setting.objects.count(), 1)
obj = Setting.objects.get(name="FOO")
self.assertEqual(obj.value_type, Setting.TYPE_STRING)
self.assertEqual(obj.value, "bar")

@override_settings(EXTRA_SETTINGS_ADMIN_APP="app")
def test_get_urls(self) -> None:
reset_url = "app_setting_reset"
ma = SettingAdmin(model=Setting, admin_site=AdminSite())
urls = [url.name for url in ma.get_urls()]
self.assertTrue(reset_url in urls)
37 changes: 33 additions & 4 deletions tests/test_models.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,11 @@


class ExtraSettingsModelsTestCase(TestCase):
def setUp(self):
@classmethod
def setUpClass(cls) -> None:
"""setup tests"""
super().setUpClass()
Setting.set_defaults_from_settings()
Setting.objects.bulk_create(
[
Setting(
Expand Down Expand Up @@ -79,9 +83,6 @@ def setUp(self):
]
)

def tearDown(self):
pass

def test_create_setting(self):
# bool
setting_value = True
Expand Down Expand Up @@ -185,11 +186,19 @@ def test_repr(self):
self.assertEqual(f"{setting_obj}", setting_repr)

def test_set_defaults_from_settings(self):
Setting.set_defaults_from_settings()
self.assertEqual(
Setting.get("TEST_DEFAULT_URL"),
"https://github.com/fabiocaccamo/django-extra-settings",
)

def test_set_defaults_from_settings_do_not_update_updated_value(self):
obj = Setting.objects.get(name="TEST_DEFAULT_URL")
obj.value = "foo"
obj.save()
Setting.set_defaults_from_settings()
self.assertEqual(Setting.get("TEST_DEFAULT_URL"), "foo")

def test_set_defaults(self):
Setting.set_defaults([])
defaults = [
Expand Down Expand Up @@ -246,3 +255,23 @@ def test_setting_type_json(self):
setting_obj.save()
setting_obj = Setting.objects.get(name="TEST_SETTING_JSON")
self.assertEqual(setting_obj.value, {"level": "L2", "role": "Admin"})

def test_reset_settings_to_default_values(self) -> None:
"""Should reset all settings to default values from settings"""
obj = Setting.objects.get(name="TEST_DEFAULT_URL")
obj.value = "foo"
obj.save()
Setting.objects.create(name="TEST", value_type=Setting.TYPE_BOOL)
self.assertEqual(Setting.get("TEST"), False)
Setting.reset_to_default()
self.assertEqual(Setting.objects.count(), 1)
obj = Setting.objects.get(name="TEST_DEFAULT_URL")
self.assertEqual(
obj.value, "https://github.com/fabiocaccamo/django-extra-settings"
)
# ensure cache was cleaned
self.assertEqual(
Setting.get(name="TEST_DEFAULT_URL"),
"https://github.com/fabiocaccamo/django-extra-settings",
)
self.assertIsNone(Setting.get("TEST"))