From 421296ed524e528a1c96386b14e55b3b8a8aad6a Mon Sep 17 00:00:00 2001 From: Manjit Kumar Date: Mon, 19 Aug 2019 14:12:22 -0400 Subject: [PATCH] (add): update admin_user and admin_client fixtures - sync PR: https://github.com/pytest-dev/pytest-django/pull/748 --- pytest_django/fixtures.py | 24 +++++++---- tests/test_fixtures.py | 90 +++++++++++++++++++++++++++++++++------ 2 files changed, 92 insertions(+), 22 deletions(-) diff --git a/pytest_django/fixtures.py b/pytest_django/fixtures.py index 02dc619a5..36b0b97a4 100644 --- a/pytest_django/fixtures.py +++ b/pytest_django/fixtures.py @@ -262,33 +262,41 @@ def django_username_field(django_user_model): @pytest.fixture() def admin_user(db, django_user_model, django_username_field): """A Django admin user. - This uses an existing user with username "admin", or creates a new one with password "password". """ UserModel = django_user_model username_field = django_username_field username = "admin@example.com" if username_field == "email" else "admin" + attributes = {username_field: username} try: - user = UserModel._default_manager.get(**{username_field: username}) + user = UserModel._default_manager.get(**attributes) except UserModel.DoesNotExist: - extra_fields = {} - if username_field not in ("username", "email"): - extra_fields[username_field] = "admin" + all_user_model_fields = [x.name for x in UserModel._meta.get_fields()] + + if 'username' in all_user_model_fields: + # django.contrib.auth.UserManager expects a username field to be + # present, even if a different USERNAME_FIELD is set. + attributes['username'] = 'admin' + if 'email' in all_user_model_fields: + # Handle both email field required for default UserManager and + # cases where USERNAME_FIELD is the email. + attributes['email'] = 'admin@example.com' + user = UserModel._default_manager.create_superuser( - username, "admin@example.com", "password", **extra_fields + password='password', **attributes ) return user @pytest.fixture() -def admin_client(db, admin_user): +def admin_client(db, admin_user, django_username_field): """A Django test client logged in as an admin user.""" from django.test.client import Client client = Client() - client.login(username=admin_user.username, password="password") + client.login(username=getattr(admin_user, django_username_field), password='password') return client diff --git a/tests/test_fixtures.py b/tests/test_fixtures.py index 124127247..42f1ecdcd 100644 --- a/tests/test_fixtures.py +++ b/tests/test_fixtures.py @@ -474,6 +474,7 @@ def test_with_live_server(live_server): @pytest.mark.parametrize("username_field", ("email", "identifier")) +@pytest.mark.parametrize("original_username_field_present", (True, False)) @pytest.mark.django_project( extra_settings=""" AUTH_USER_MODEL = 'app.MyCustomUser' @@ -487,20 +488,76 @@ def test_with_live_server(live_server): ROOT_URLCONF = 'tpkg.app.urls' """ ) -def test_custom_user_model(django_testdir, username_field): - django_testdir.create_app_file( - """ - from django.contrib.auth.models import AbstractUser - from django.db import models +def test_custom_user_model(django_testdir, username_field, original_username_field_present): + if original_username_field_present: + django_testdir.create_app_file( + """ + from django.contrib.auth.models import AbstractUser + from django.db import models - class MyCustomUser(AbstractUser): - identifier = models.CharField(unique=True, max_length=100) + class MyCustomUser(AbstractUser): + identifier = models.CharField(unique=True, max_length=100) - USERNAME_FIELD = '%s' - """ - % (username_field), - "models.py", - ) + USERNAME_FIELD = '%s' + """ + % (username_field), + "models.py", + ) + else: + django_testdir.create_app_file( + """ + from django.contrib.auth.models import BaseUserManager + + class MyCustomUserManager(BaseUserManager): + def _create_user(self, email, password, **extra_fields): + if not email: + raise ValueError('The given email must be set') + email = self.normalize_email(email) + user = self.model(email=email, **extra_fields) + user.set_password(password) + user.save(using=self._db) + return user + + def create_user(self, email, password=None, **extra_fields): + extra_fields.setdefault('is_staff', False) + extra_fields.setdefault('is_superuser', False) + return self._create_user(email, password, **extra_fields) + + def create_superuser(self, email, password, **extra_fields): + extra_fields.setdefault('is_staff', True) + extra_fields.setdefault('is_superuser', True) + + if extra_fields.get('is_staff') is not True: + raise ValueError('Superuser must have is_staff=True.') + if extra_fields.get('is_superuser') is not True: + raise ValueError('Superuser must have is_superuser=True.') + + return self._create_user(email, password, **extra_fields) + """, + "managers.py" + ) + django_testdir.create_app_file( + """ + from django.contrib.auth.models import AbstractUser + from django.db import models + + from .managers import MyCustomUserManager + + class MyCustomUser(AbstractUser): + identifier = models.CharField(unique=True, max_length=100) + + USERNAME_FIELD = '%s' + REQUIRED_FIELDS = [] + objects = MyCustomUserManager() + + username_field = MyCustomUser._meta.get_field('username') + local_fields = MyCustomUser._meta.local_fields + local_fields.remove(username_field) + MyCustomUser._meta.fields = local_fields + """ + % (username_field), + "models.py", + ) django_testdir.create_app_file( """ from django.conf.urls import url @@ -539,6 +596,10 @@ def test_custom_user_model(admin_client): ) django_testdir.create_app_file("", "migrations/__init__.py") + username_db_field = "" + if original_username_field_present: + username_db_field = "('username', models.CharField(error_messages={'unique': 'A user with that username already exists.'}, max_length=30, validators=[django.core.validators.RegexValidator('^[\\w.@+-]+$', 'Enter a valid username. This value may contain only letters, numbers and @/./+/-/_ characters.', 'invalid')], help_text='Required. 30 characters or fewer. Letters, digits and @/./+/-/_ only.', unique=True, verbose_name='username'))," # noqa: E501 + django_testdir.create_app_file( """ # -*- coding: utf-8 -*- @@ -564,7 +625,7 @@ class Migration(migrations.Migration): ('password', models.CharField(max_length=128, verbose_name='password')), ('last_login', models.DateTimeField(null=True, verbose_name='last login', blank=True)), ('is_superuser', models.BooleanField(default=False, help_text='Designates that this user has all permissions without explicitly assigning them.', verbose_name='superuser status')), - ('username', models.CharField(error_messages={'unique': 'A user with that username already exists.'}, max_length=30, validators=[django.core.validators.RegexValidator('^[\\w.@+-]+$', 'Enter a valid username. This value may contain only letters, numbers and @/./+/-/_ characters.', 'invalid')], help_text='Required. 30 characters or fewer. Letters, digits and @/./+/-/_ only.', unique=True, verbose_name='username')), + %s ('first_name', models.CharField(max_length=30, verbose_name='first name', blank=True)), ('last_name', models.CharField(max_length=30, verbose_name='last name', blank=True)), ('email', models.EmailField(max_length=254, verbose_name='email address', blank=True)), @@ -583,7 +644,8 @@ class Migration(migrations.Migration): bases=None, ), ] - """, # noqa: E501 + """ # noqa: E501 + % (username_db_field), "migrations/0002_custom_user_model.py", )