Могу ли я определить классы в настройках Django и как я могу переопределить такие настройки в тестах? - PullRequest
0 голосов
/ 27 декабря 2018

Мы используем Django для Speedy Net и Speedy Match (в настоящее время Django 1.11.17, мы не можем перейти на более новую версию Django из-за одного из наших требований, django-modeltranslation).Я хочу определить некоторые из наших настроек как классы.Например:

class UserSettings(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

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

(что определено в https://github.com/speedy-net/speedy-net/blob/staging/speedy/net/settings/global_settings.py). А затем в моделях я попытался использовать:

from django.conf import settings as django_settings

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

(а затем использовать атрибуты settings, например settings.MIN_USERNAME_LENGTH, в классе).

Но оно выдает исключение

AttributeError: 'Settings' object has no attribute 'UserSettings'

(но оно не выдает исключение, если я использую там константу, котораяэто не класс).

Это первая проблема. А пока я определил вместо этого:

from speedy.net.settings import global_settings as speedy_net_global_settings

class User(ValidateUserPasswordMixin, PermissionsMixin, Entity, AbstractBaseUser):
    settings = speedy_net_global_settings.UserSettings

Вторая проблема: как мне переопределить такие настройки в тестах?Например, я использую следующий код:

from speedy.core.settings import tests as tests_settings

@override_settings(MAX_NUMBER_OF_FRIENDS_ALLOWED=tests_settings.OVERRIDE_MAX_NUMBER_OF_FRIENDS_ALLOWED)

in https://github.com/speedy-net/speedy-net/blob/staging/speedy/core/friends/tests/test_views.py. Но если MAX_NUMBER_OF_FRIENDS_ALLOWED будет определено в классе UserSettings, как мне его переопределить?

Ответы [ 2 ]

0 голосов
/ 28 декабря 2018

Спасибо @Blender за подсказку:

Объект настроек Django явно пропускает любые объекты в вашем модуле настроек с именами не в верхнем регистре.Если вы переименуете свой класс в USER_SETTINGS, он будет работать.

Я не знал, что все настройки должны быть в верхнем регистре.Поэтому я переименовал class UserSettings в class USER_SETTINGS (хотя PyCharm это не нравится), но я проверил и также можно добавить этот код в конец файла:

USER_SETTINGS = UserSettings

Без переименованиякласс.

Что касается моего второго вопроса - как мне переопределить такие настройки в тестах?Я добавил файл с именем utils.py:

def get_django_settings_class_with_override_settings(django_settings_class, **override_settings):
    class django_settings_class_with_override_settings(django_settings_class):
        pass

    for setting, value in override_settings.items():
        setattr(django_settings_class_with_override_settings, setting, value)

    return django_settings_class_with_override_settings

(Вы можете увидеть его на https://github.com/speedy-net/speedy-net/blob/staging/speedy/core/base/test/utils.py)

А затем в тестах:

from django.conf import settings as django_settings
from django.test import override_settings

from speedy.core.settings import tests as tests_settings
from speedy.core.base.test.utils import get_django_settings_class_with_override_settings

    @override_settings(USER_SETTINGS=get_django_settings_class_with_override_settings(django_settings_class=django_settings.USER_SETTINGS, MAX_NUMBER_OF_FRIENDS_ALLOWED=tests_settings.OVERRIDE_USER_SETTINGS.MAX_NUMBER_OF_FRIENDS_ALLOWED))
    def test_user_can_send_friend_request_if_not_maximum(self):
        self.assertEqual(first=django_settings.USER_SETTINGS.MAX_NUMBER_OF_FRIENDS_ALLOWED, second=4)

Я проверили я должен определить другой класс (в данном случае class django_settings_class_with_override_settings, потому что если я изменю класс django_settings_class напрямую, это также повлияет на другие тесты, которые не использовали @override_settings.

0 голосов
/ 27 декабря 2018

Django не ожидает, что вы сильно отклонитесь от его низкоуровневых вариантов дизайна, и обычно приходится бороться с вещами, которые Django явно не позволяет настраивать.

  1. Объект настроек Django явно пропускает любые объекты в вашем модуле настроек с именами не в верхнем регистре.Если вы переименуете свой класс в USER_SETTINGS, он будет работать.Если вы действительно хотите сохранить оригинальное имя вашего объекта, ужасным решением было бы обмануть Джанго:

    class UserSettings:
        ...
    
    class AlwaysUppercaseStr(str):
        def isupper(self):
            return True
    
    globals()[AlwaysUppercaseStr('UserSettings')] = globals().pop('UserSettings')
    

    Я понятия не имею, переносимо ли это в реализациях Python, но работает ли оно с CPythondir().

  2. override_settings не поддерживает то, что вы пытаетесь сделать, поэтому вам, вероятно, придется переписать этот класс, чтобы позволить глобальному объекту settings быть настраиваемым.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...