Skip to content

Commit

Permalink
Refactor app and model
Browse files Browse the repository at this point in the history
  • Loading branch information
sergei-iurchenko committed Mar 10, 2023
1 parent 8b03012 commit 2cb2ccd
Show file tree
Hide file tree
Showing 19 changed files with 80 additions and 178 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,6 @@ dist/
test.db
.tox
.coverage
coverage.xml
docs/_build
.idea
40 changes: 2 additions & 38 deletions constance/apps.py
Original file line number Diff line number Diff line change
@@ -1,45 +1,9 @@
from django.db.models import signals
from django.apps import apps, AppConfig
from django.apps import AppConfig
from django.utils.translation import gettext_lazy as _


class ConstanceConfig(AppConfig):
name = 'constance'
verbose_name = _('Constance')
default_auto_field = 'django.db.models.AutoField'

def ready(self):
super().ready()
signals.post_migrate.connect(self.create_perm,
dispatch_uid='constance.create_perm')

def create_perm(self, using=None, *args, **kwargs):
"""
Creates a fake content type and permission
to be able to check for permissions
"""
from django.conf import settings

constance_dbs = getattr(settings, 'CONSTANCE_DBS', None)
if constance_dbs is not None and using not in constance_dbs:
return
if (
apps.is_installed('django.contrib.contenttypes') and
apps.is_installed('django.contrib.auth')
):
ContentType = apps.get_model('contenttypes.ContentType')
Permission = apps.get_model('auth.Permission')
content_type, created = ContentType.objects.using(using).get_or_create(
app_label='constance',
model='config',
)

Permission.objects.using(using).get_or_create(
content_type=content_type,
codename='change_config',
defaults={'name': 'Can change config'},
)
Permission.objects.using(using).get_or_create(
content_type=content_type,
codename='view_config',
defaults={'name': 'Can view config'},
)
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,13 @@
)
from django.db.models.signals import post_save

from .. import Backend
from ... import settings, signals, config
from constance.backends import Backend
from constance import settings, signals, config


class DatabaseBackend(Backend):
def __init__(self):
from .models import Constance
from constance.models import Constance
self._model = Constance
self._prefix = settings.DATABASE_PREFIX
self._autofill_timeout = settings.DATABASE_CACHE_AUTOFILL_TIMEOUT
Expand Down
6 changes: 0 additions & 6 deletions constance/backends/database/apps.py

This file was deleted.

19 changes: 0 additions & 19 deletions constance/backends/database/migrations/0002_auto_20190129_2304.py

This file was deleted.

28 changes: 10 additions & 18 deletions constance/management/commands/constance.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
from django.apps import apps
from django.conf import settings
from django.core.exceptions import ValidationError
from django.core.management import BaseCommand, CommandError
Expand All @@ -8,6 +7,7 @@

from ... import config
from ...admin import ConstanceForm, get_values
from ...models import Constance


def _set_constance_value(key, value):
Expand Down Expand Up @@ -49,7 +49,6 @@ def add_arguments(self, parser):
help='delete all Constance keys and their values if they are not in settings.CONSTANCE_CONFIG (stale keys)',
)


def _subparsers_add_parser(self, subparsers, name, **kwargs):
# API in Django >= 2.1 changed and removed cmd parameter from add_parser
if VERSION >= (2, 1) and 'cmd' in kwargs:
Expand Down Expand Up @@ -82,23 +81,16 @@ def handle(self, command, key=None, value=None, *args, **options):
self.stdout.write("{}\t{}".format(k, v), ending="\n")

elif command == 'remove_stale_keys':
try:
Constance = apps.get_model('database.Constance')
except LookupError:
Constance = None

if Constance:
actual_keys = settings.CONSTANCE_CONFIG.keys()
actual_keys = settings.CONSTANCE_CONFIG.keys()

stale_records = Constance.objects.exclude(key__in=actual_keys)
if stale_records:
self.stdout.write("The following record will be deleted:", ending="\n")
else:
self.stdout.write("There are no stale records in database.", ending="\n")
stale_records = Constance.objects.exclude(key__in=actual_keys)
if stale_records:
self.stdout.write("The following record will be deleted:", ending="\n")
else:
self.stdout.write("There are no stale records in database.", ending="\n")

for stale_record in stale_records:
self.stdout.write("{}\t{}".format(stale_record.key, stale_record.value), ending="\n")
for stale_record in stale_records:
self.stdout.write("{}\t{}".format(stale_record.key, stale_record.value), ending="\n")

stale_records.delete()
else:
self.stdout.write("Database backend is not set. Nothing is deleted", ending="\n")
stale_records.delete()
Original file line number Diff line number Diff line change
@@ -1,24 +1,25 @@
from django.db import models, migrations
from django.db import migrations, models
import picklefield.fields


class Migration(migrations.Migration):

initial = True

dependencies = []

operations = [
migrations.CreateModel(
name='Constance',
fields=[
('id', models.AutoField(verbose_name='ID', primary_key=True,
auto_created=True, serialize=False)),
('key', models.CharField(unique=True, max_length=255)),
('value', picklefield.fields.PickledObjectField(editable=False)),
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('key', models.CharField(max_length=255, unique=True)),
('value', picklefield.fields.PickledObjectField(blank=True, editable=False, null=True)),
],
options={
'verbose_name': 'constance',
'verbose_name_plural': 'constances',
'db_table': 'constance_config',
'permissions': [('change_config', 'Can change config'), ('view_config', 'Can view config')],
},
bases=(models.Model,),
),
]
33 changes: 33 additions & 0 deletions constance/migrations/0002_migrate_from_old_table.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
from django.core.management.color import no_style
from django.db import migrations, connection, DatabaseError


def _migrate_from_old_table(apps, schema_editor) -> None:
"""
Copies values from old table.
On new installations just ignore error that table does not exist.
"""
try:
with connection.cursor() as cursor:
cursor.execute('INSERT INTO constance_constance ( id, key, value ) SELECT id, key, value FROM constance_config', [])
cursor.execute('DROP TABLE constance_config', [])

except DatabaseError:
pass

Constance = apps.get_model('constance', 'Constance')
sequence_sql = connection.ops.sequence_reset_sql(no_style(), [Constance])
with connection.cursor() as cursor:
for sql in sequence_sql:
cursor.execute(sql)


class Migration(migrations.Migration):

dependencies = [('constance', '0001_initial')]

atomic = False

operations = [
migrations.RunPython(_migrate_from_old_table, reverse_code=lambda x, y: None),
]
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,10 @@ class Constance(models.Model):
class Meta:
verbose_name = _('constance')
verbose_name_plural = _('constances')
db_table = 'constance_config'
permissions = [
('change_config', 'Can change config'),
('view_config', 'Can view config'),
]

def __str__(self):
return self.key
20 changes: 3 additions & 17 deletions docs/backends.rst
Original file line number Diff line number Diff line change
Expand Up @@ -94,27 +94,17 @@ Defaults to `60` seconds.
Database
--------

The database backend is optional and stores the configuration values in a
Database backend stores configuration values in a
standard Django model. It requires the package `django-picklefield`_ for
storing those values. Please install it like so::

pip install django-constance[database]
storing those values.

You must set the ``CONSTANCE_BACKEND`` Django setting to::

CONSTANCE_BACKEND = 'constance.backends.database.DatabaseBackend'

Then add the database backend app to your :setting:`INSTALLED_APPS` setting to
make sure the data model is correctly created::

INSTALLED_APPS = (
# other apps
'constance.backends.database',
)

Please make sure to apply the database migrations::

python manage.py migrate database
python manage.py migrate

.. note:: If you're upgrading Constance to 1.0 and use Django 1.7 or higher
please make sure to let the migration system know that you've
Expand All @@ -124,10 +114,6 @@ Please make sure to apply the database migrations::

python manage.py migrate database --fake

.. note:: If you have multiple databases you can set what databases
will be used with ``CONSTANCE_DBS``

CONSTANCE_DBS = "default"

Just like the Redis backend you can set an optional prefix that is used during
database interactions (it defaults to an empty string, ``''``). To use
Expand Down
7 changes: 7 additions & 0 deletions docs/changes.rst
Original file line number Diff line number Diff line change
@@ -1,6 +1,13 @@
Changelog
---------

v3.0.0 (future)
~~~~~~~~~~~~~~~~~~~

* Refactor database backend
Backward incompatible changes:
remove 'constance.backends.database' from INSTALLED_APPS

v2.10.0 (unreleased)
~~~~~~~~~~~~~~~~~~

Expand Down
3 changes: 2 additions & 1 deletion example/cheeseshop/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,6 @@
'cheeseshop.apps.catalog',
'cheeseshop.apps.storage',
'constance',
'constance.backends.database',
)

MIDDLEWARE = (
Expand Down Expand Up @@ -149,3 +148,5 @@
# https://docs.djangoproject.com/en/1.8/howto/static-files/

STATIC_URL = '/static/'

DEFAULT_AUTO_FIELD = 'django.db.models.AutoField'
4 changes: 3 additions & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,8 +60,10 @@ def find_version(*file_paths):
include_package_data=True,
zip_safe=False,
python_requires='>=3.6',
install_requires=[
'django-picklefield',
],
extras_require={
'database': ['django-picklefield'],
'redis': ['redis'],
},
entry_points={
Expand Down
7 changes: 1 addition & 6 deletions tests/test_admin.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
from datetime import datetime

import mock
from unittest import mock
from django.contrib import admin
from django.contrib.auth.models import User, Permission
from django.contrib.contenttypes.models import ContentType
from django.core.exceptions import PermissionDenied
from django.http import HttpResponseRedirect
from django.template.defaultfilters import linebreaksbr
Expand Down Expand Up @@ -53,10 +52,6 @@ def test_custom_auth(self):
response = self.options.changelist_view(request, {})
self.assertEqual(response.status_code, 200)

def test_str(self):
ct = ContentType.objects.get(app_label='constance', model='config')
self.assertEqual(str(ct), 'config')

def test_linebreaks(self):
self.client.login(username='admin', password='nimda')
request = self.rf.get('/admin/constance/config/')
Expand Down
56 changes: 0 additions & 56 deletions tests/test_app.py

This file was deleted.

0 comments on commit 2cb2ccd

Please sign in to comment.