Overriding settings in Django when used by the models

368 views
Skip to first unread message

אורי

unread,
Dec 30, 2018, 11:07:37 PM12/30/18
to django...@googlegroups.com

We are using Django for Speedy Net and Speedy Match (currently Django 1.11.17, we can't upgrade to a newer version of Django because of one of our requirements, django-modeltranslation). Some of our settings are used by the models. For example:

class USER_SETTINGS(object):
    MIN_USERNAME_LENGTH = 6
    MAX_USERNAME_LENGTH = 40

    MIN_SLUG_LENGTH = 6
    MAX_SLUG_LENGTH = 200

    # Users can register from age 0 to 180, but can't be kept on the site after age 250.
    MIN_AGE_ALLOWED_IN_MODEL = 0  # In years.
    MAX_AGE_ALLOWED_IN_MODEL = 250  # In years.

    MIN_AGE_ALLOWED_IN_FORMS = 0  # In years.
    MAX_AGE_ALLOWED_IN_FORMS = 180  # In years.

    MIN_PASSWORD_LENGTH = 8
    MAX_PASSWORD_LENGTH = 120

    MAX_NUMBER_OF_FRIENDS_ALLOWED = 800

    PASSWORD_VALIDATORS = [
        {
            'NAME': 'speedy.core.accounts.validators.PasswordMinLengthValidator',
        },
        {
            'NAME': 'speedy.core.accounts.validators.PasswordMaxLengthValidator',
        },
    ]

(which is defined in https://github.com/speedy-net/speedy-net/blob/uri_merge_with_master_2018-12-26_a/speedy/net/settings/global_settings.py). And then in the models I use:

from django.conf import settings as django_settings

class User(ValidateUserPasswordMixin, PermissionsMixin, Entity, AbstractBaseUser):
    settings = django_settings.USER_SETTINGS

(and then use attributes of settings, such as settings.MIN_SLUG_LENGTH, in the class).

The problem is, when I try to override such settings in tests (you can see my question & answer on Can I define classes in Django settings, and how can I override such settings in tests?), User.settings remains the same and is not overridden by the settings I tried to override. This is a problem since in the model I passed settings.MIN_SLUG_LENGTH for example to validators, which are also passed other values by other models. Is it possible to define the models and settings in such a way which the correct settings will be used both in production and in tests, including when I want to override them?

I'm aware of this quote from https://docs.djangoproject.com/en/dev/topics/testing/tools/#overriding-settings:

Warning

The settings file contains some settings that are only consulted during initialization of Django internals. If you change them with override_settings, the setting is changed if you access it via the django.conf.settings module, however, Django’s internals access it differently. Effectively, using override_settings() or modify_settings() with these settings is probably not going to do what you expect it to do.

We do not recommend altering the DATABASES setting. Altering the CACHES setting is possible, but a bit tricky if you are using internals that make using of caching, like django.contrib.sessions. For example, you will have to reinitialize the session backend in a test that uses cached sessions and overrides CACHES.

Finally, avoid aliasing your settings as module-level constants as override_settings() won’t work on such values since they are only evaluated the first time the module is imported.

Which I understand are relevant in this case, but how do I define the settings in such a way that I can override them?

Thanks,
אורי (Uri)


אורי

Jason

unread,
Dec 31, 2018, 8:12:27 AM12/31/18
to Django users
Sounds like what you want is something in https://djangopackages.org/grids/g/live-setting/

This will let you change settings via an admin interface

אורי

unread,
Jan 4, 2019, 6:16:01 AM1/4/19
to django...@googlegroups.com
I don't understand why is it relevant to my question? It's not what I asked.

On Mon, Dec 31, 2018 at 3:12 PM Jason <jjohn...@gmail.com> wrote:
Sounds like what you want is something in https://djangopackages.org/grids/g/live-setting/

This will let you change settings via an admin interface

--
You received this message because you are subscribed to the Google Groups "Django users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to django-users...@googlegroups.com.
To post to this group, send email to django...@googlegroups.com.
Visit this group at https://groups.google.com/group/django-users.
To view this discussion on the web visit https://groups.google.com/d/msgid/django-users/a363549d-2e5a-4323-86af-cb8c14d9d860%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Vinicius Assef

unread,
Jan 23, 2019, 8:33:28 AM1/23/19
to django...@googlegroups.com
I hope you already got this solved. If not, there's a way to achieve what you are looking for.

Get settings.MIN_SLUG_LENGTH from an environment variable. Use it in your settings.py:

MIN_SLUG_LENGTH = os.getenv('ENV_MIN_SLUG_LENGTH')

You'll need to set ENV_MIN_SLUG_LENGTH before running your tests in the shell will run them.

Note: ENV_MIN_SLUG_LENGTH could be any name. This is only for demonstration purposes, OK?

Shalom!


--
You received this message because you are subscribed to the Google Groups "Django users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to django-users...@googlegroups.com.
To post to this group, send email to django...@googlegroups.com.
Visit this group at https://groups.google.com/group/django-users.

Carlton Gibson

unread,
Jan 24, 2019, 4:08:53 AM1/24/19
to Django users
Hi Uri. 

Does it work if you make `User.settings` a property, that fetches the values dynamically, rather than assigning them once at import time? 

Something like: 

@property
def settings(self):
    return django_settings.USER_SETTINGS


אורי

unread,
Mar 30, 2019, 12:46:48 PM3/30/19
to django...@googlegroups.com
Hi Carlton,

1. I apologize for the time taking me to reply. I had other things to handle before I could handle this issue.

2. The settings in models such as User are per class/model and not per instance. You can see the models in the following file:

For example, you can see the following code:
    AGE_VALID_VALUES_IN_MODEL = range(settings.MIN_AGE_ALLOWED_IN_MODEL, settings.MAX_AGE_ALLOWED_IN_MODEL)
    AGE_VALID_VALUES_IN_FORMS = range(settings.MIN_AGE_ALLOWED_IN_FORMS, settings.MAX_AGE_ALLOWED_IN_FORMS)

These constants, for example, are used in the validators:


def age_is_valid_in_model(age):
    from .models import User
    return (age in User.AGE_VALID_VALUES_IN_MODEL)


def age_is_valid_in_forms(age):
    from .models import User
    return (age in User.AGE_VALID_VALUES_IN_FORMS)


And also `User.settings` appears many times in our code.

In general the model in all the project uses the same constant values, except in some tests where I want to override these values in order to test some specific cases which can't be tested with the values used in production. So I'm not sure using a property is the correct thing to do here. I'm looking for a way to define settings per class/model, but in a way that can be overridden in tests.

What do you think?

3. (Currently there is a hack I used in the tests, you can see `def _1___set_up` in https://github.com/speedy-net/speedy-net/blob/staging/speedy/core/base/test/models.py but it's a temporary hack and I don't think it's good as a permanent solution.

By the way, I tried to call the function ___set_up but it didn't work, there is a problem with functions which start with 2 or more underlines.)

4. By the way, `validators` may be a property since it's only used per instance, but I'm not sure about settings. Maybe I can use the settings differently in `validators` and define it there as a property?

--
You received this message because you are subscribed to the Google Groups "Django users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to django-users...@googlegroups.com.
To post to this group, send email to django...@googlegroups.com.
Visit this group at https://groups.google.com/group/django-users.
Reply all
Reply to author
Forward
0 new messages