0

Trying to set up custom user model on the start of django project, but i am facing a recurrent problem that i have only been able to patch, that now is affecting the changepassword of admin interface. On change password form submit, it crashes with error:

AttributeError at /admin/custom_users/customuser/7/password/

'NoneType' object has no attribute 'strip'

Environment:


Request Method: POST
Request URL: http://127.0.0.1:8000/admin/custom_users/customuser/7/password/

Django Version: 2.2
Python Version: 3.7.3
Installed Applications:
['django.contrib.admin',
 'django.contrib.auth',
 'django.contrib.contenttypes',
 'django.contrib.sessions',
 'django.contrib.messages',
 'django.contrib.staticfiles',
 'cashflow.apps.CashflowConfig',
 'custom_users.apps.CustomUsersConfig']
Installed Middleware:
['django.middleware.security.SecurityMiddleware',
 'django.contrib.sessions.middleware.SessionMiddleware',
 'django.middleware.common.CommonMiddleware',
 'django.middleware.csrf.CsrfViewMiddleware',
 'django.contrib.auth.middleware.AuthenticationMiddleware',
 'django.contrib.messages.middleware.MessageMiddleware',
 'django.middleware.clickjacking.XFrameOptionsMiddleware']



Traceback:

File "/home/mh/devel/dreamit_control/env/lib/python3.7/site-packages/mysql/connector/connection_cext.py" in cmd_query
  395.                                raw_as_string=raw_as_string)

During handling of the above exception (Column 'is_superuser' cannot be null), another exception occurred:

File "/home/mh/devel/dreamit_control/env/lib/python3.7/site-packages/mysql/connector/django/base.py" in _execute_wrapper
  168.             return method(query, args)

File "/home/mh/devel/dreamit_control/env/lib/python3.7/site-packages/mysql/connector/cursor_cext.py" in execute
  266.                                          raw_as_string=self._raw_as_string)

File "/home/mh/devel/dreamit_control/env/lib/python3.7/site-packages/mysql/connector/connection_cext.py" in cmd_query
  398.                                              sqlstate=exc.sqlstate)

During handling of the above exception (1048 (23000): Column 'is_superuser' cannot be null), another exception occurred:

File "/home/mh/devel/dreamit_control/env/lib/python3.7/site-packages/django/db/backends/utils.py" in execute
  99.             return super().execute(sql, params)

File "/home/mh/devel/dreamit_control/env/lib/python3.7/site-packages/django/db/backends/utils.py" in execute
  67.         return self._execute_with_wrappers(sql, params, many=False, executor=self._execute)

File "/home/mh/devel/dreamit_control/env/lib/python3.7/site-packages/django/db/backends/utils.py" in _execute_with_wrappers
  76.         return executor(sql, params, many, context)

File "/home/mh/devel/dreamit_control/env/lib/python3.7/site-packages/django/db/backends/utils.py" in _execute
  84.                 return self.cursor.execute(sql, params)

File "/home/mh/devel/dreamit_control/env/lib/python3.7/site-packages/mysql/connector/django/base.py" in execute
  218.         return self._execute_wrapper(self.cursor.execute, query, new_args)

File "/home/mh/devel/dreamit_control/env/lib/python3.7/site-packages/mysql/connector/django/base.py" in _execute_wrapper
  174.                         utils.IntegrityError(err.msg), sys.exc_info()[2])

File "/home/mh/devel/dreamit_control/env/lib/python3.7/site-packages/django/utils/six.py" in reraise
  683.             raise value.with_traceback(tb)

File "/home/mh/devel/dreamit_control/env/lib/python3.7/site-packages/mysql/connector/django/base.py" in _execute_wrapper
  168.             return method(query, args)

File "/home/mh/devel/dreamit_control/env/lib/python3.7/site-packages/mysql/connector/cursor_cext.py" in execute
  266.                                          raw_as_string=self._raw_as_string)

File "/home/mh/devel/dreamit_control/env/lib/python3.7/site-packages/mysql/connector/connection_cext.py" in cmd_query
  398.                                              sqlstate=exc.sqlstate)

During handling of the above exception (Column 'is_superuser' cannot be null), another exception occurred:

File "/home/mh/devel/dreamit_control/env/lib/python3.7/site-packages/mysql/connector/cursor_cext.py" in statement
  606.             return self._executed.strip().decode('utf8')

During handling of the above exception ('NoneType' object has no attribute 'strip'), another exception occurred:

File "/home/mh/devel/dreamit_control/env/lib/python3.7/site-packages/django/core/handlers/exception.py" in inner
  34.             response = get_response(request)

File "/home/mh/devel/dreamit_control/env/lib/python3.7/site-packages/django/core/handlers/base.py" in _get_response
  115.                 response = self.process_exception_by_middleware(e, request)

File "/home/mh/devel/dreamit_control/env/lib/python3.7/site-packages/django/core/handlers/base.py" in _get_response
  113.                 response = wrapped_callback(request, *callback_args, **callback_kwargs)

File "/home/mh/devel/dreamit_control/env/lib/python3.7/site-packages/django/utils/decorators.py" in _wrapped_view
  142.                     response = view_func(request, *args, **kwargs)

File "/home/mh/devel/dreamit_control/env/lib/python3.7/site-packages/django/views/decorators/cache.py" in _wrapped_view_func
  44.         response = view_func(request, *args, **kwargs)

File "/home/mh/devel/dreamit_control/env/lib/python3.7/site-packages/django/contrib/admin/sites.py" in inner
  223.             return view(request, *args, **kwargs)

File "/home/mh/devel/dreamit_control/env/lib/python3.7/site-packages/django/utils/decorators.py" in _wrapper
  45.         return bound_method(*args, **kwargs)

File "/home/mh/devel/dreamit_control/env/lib/python3.7/site-packages/django/views/decorators/debug.py" in sensitive_post_parameters_wrapper
  76.             return view(request, *args, **kwargs)

File "/home/mh/devel/dreamit_control/env/lib/python3.7/site-packages/django/contrib/auth/admin.py" in user_change_password
  141.                 form.save()

File "/home/mh/devel/dreamit_control/dcontrol/custom_users/forms.py" in save
  32.             self.user.save()

File "/home/mh/devel/dreamit_control/env/lib/python3.7/site-packages/django/contrib/auth/base_user.py" in save
  66.         super().save(*args, **kwargs)

File "/home/mh/devel/dreamit_control/env/lib/python3.7/site-packages/django/db/models/base.py" in save
  741.                        force_update=force_update, update_fields=update_fields)

File "/home/mh/devel/dreamit_control/env/lib/python3.7/site-packages/django/db/models/base.py" in save_base
  779.                 force_update, using, update_fields,

File "/home/mh/devel/dreamit_control/env/lib/python3.7/site-packages/django/db/models/base.py" in _save_table
  851.                                       forced_update)

File "/home/mh/devel/dreamit_control/env/lib/python3.7/site-packages/django/db/models/base.py" in _do_update
  900.         return filtered._update(values) > 0

File "/home/mh/devel/dreamit_control/env/lib/python3.7/site-packages/django/db/models/query.py" in _update
  760.         return query.get_compiler(self.db).execute_sql(CURSOR)

File "/home/mh/devel/dreamit_control/env/lib/python3.7/site-packages/django/db/models/sql/compiler.py" in execute_sql
  1426.         cursor = super().execute_sql(result_type)

File "/home/mh/devel/dreamit_control/env/lib/python3.7/site-packages/django/db/models/sql/compiler.py" in execute_sql
  1097.             cursor.execute(sql, params)

File "/home/mh/devel/dreamit_control/env/lib/python3.7/site-packages/django/db/backends/utils.py" in execute
  103.             sql = self.db.ops.last_executed_query(self.cursor, sql, params)

File "/home/mh/devel/dreamit_control/env/lib/python3.7/site-packages/mysql/connector/django/operations.py" in last_executed_query
  127.         return force_text(cursor.statement, errors='replace')

File "/home/mh/devel/dreamit_control/env/lib/python3.7/site-packages/mysql/connector/django/base.py" in __getattr__
  230.         return getattr(self.cursor, attr)

File "/home/mh/devel/dreamit_control/env/lib/python3.7/site-packages/mysql/connector/cursor_cext.py" in statement
  608.             return self._executed.strip()

Exception Type: AttributeError at /admin/custom_users/customuser/7/password/
Exception Value: 'NoneType' object has no attribute 'strip'

on stack trace, i can see that the problem is that is_staff=NULL and is_superuser=NULL on the attempted query.

I dont know why django passes this parameters as null on passwordchange since they are set to false on model and nowhere are they as fields on the CustomUserPassForm. Had this same issue on user change form, but after adding fieldsets to CustomUserAdmin(UserAdmin) class, i was able to edit a user. (as the is_superuser and is_staff input checkboxes appeared on form in html)

models.py

class CustomUserManager(BaseUserManager):
    def create_user(self, email, password, **extra_fields):
        if not email:
            raise ValueError('correo es obligatorio')
        email = self.normalize_email(email)
        extra_fields.setdefault('is_superuser', False)
        extra_fields.setdefault('is_staff', False)
        user = self.model(email=email, **extra_fields)
        user.set_password(password)
        user.save()
        return user

    def create_superuser(self, email, password, **extra_fields):
        extra_fields.setdefault('is_staff', True)
        extra_fields.setdefault('is_superuser', True)
        extra_fields.setdefault('is_active', 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 musthave is_superuser=True')
        return self.create_user(email, password, **extra_fields)

class CustomUser(AbstractUser, PermissionsMixin):
    cargo = models.TextField(max_length=50, null=True)
    rut = models.IntegerField(null=True)
    DIGITO_VERIFICADOR_CHOICES = (
        ('1','1'),
        ('2','2'),
        ('3','3'),
        ('4','4'),
        ('5','5'),
        ('6','6'),
        ('7','7'),
        ('8','8'),
        ('9','9'),
        ('0','0'),
        ('K','K')
    )
    digito_verificador = models.CharField(max_length=1, choices=DIGITO_VERIFICADOR_CHOICES, null=True)
    nombre = models.CharField(max_length=25, default="john")
    apellido = models.CharField(max_length=25, default="doe")
    email = models.EmailField(verbose_name='correo', max_length=255, unique=True)
    username = models.TextField(max_length=255, null=True)
    is_superuser = models.BooleanField(default=False, blank=True)
    is_staff = models.BooleanField(default=False, blank=True)

    USERNAME_FIELD = 'email'
    REQUIRED_FIELDS = []

    objects = CustomUserManager()

forms.py

class CustomUserCreationForm(UserCreationForm):

    class Meta(UserCreationForm):
        model = get_user_model()
        fields = ['email', 'rut', 'digito_verificador',]

class CustomUserChangeForm(UserChangeForm):

    rut = forms.IntegerField(min_value=1000000)
    #is_superUser = forms.BooleanField()
    class Meta:
        model = get_user_model()
        fields =  ['rut', 'digito_verificador',]
        #['email', 'is_superuser','is_staff' ]


class CustomUserPassForm(AdminPasswordChangeForm):
#    is_staff = forms.BooleanField(initial=False)
 #   is_superuser = forms.BooleanField(initial=False)

    #fields = ['is_staff','is_superuser']
    def save(self, commit=True):
        password = self.cleaned_data["password1"]
        self.user.set_password(password)
        print(self.user)
        if commit:
            self.user.save()
        return self.user

admin.py

class CustomUserAdmin(UserAdmin):
    add_form = CustomUserCreationForm
    form = CustomUserChangeForm
    change_password_form = CustomUserPassForm
    model = get_user_model()
    list_display = ['email', ]
    fieldsets = (
        (None, {'fields': ('email', 'password')}),
        ('personal info',{'fields': ('nombre', 'apellido',('rut','digito_verificador'))}),
        ('permissions', {'fields':('is_superuser', 'is_staff')})
    )
    add_fieldsets = (
        (None, {
            'classes':('wide',),
            'fields':('email', 'password1', 'password2'),
        }
        ),
    )

admin.site.register(CustomUser, CustomUserAdmin)

Have been two days reading tutorials and documentation, including official django guide, all which leave out any information about implementation of change_password_form.

Tom Carrick
  • 6,349
  • 13
  • 54
  • 78

1 Answers1

0

The problem was the save method of the CustomUserPassForm. For some reason (i havent done the complete followup) the user attribute had is_staff and is_superuser set to NULL. forcing these to false patched the problem.

class CustomUserPassForm(AdminPasswordChangeForm):

    def save(self, commit=True):
        password = self.cleaned_data["password1"]
        self.user.set_password(password)
        self.user.is_staff = False
        self.user.is_superuser = False

        if commit:
            self.user.save()

        return self.user

Now if anyone can shed some light as to why, i'd be appreciated (also, how to set the is_staff and is_superuser to the same value that is actually held in db.)

  • After more documentation reading, it seems the problem was the lack of class Meta: model=get_user_model() on the CustomUserPassForm that was leading to the incorrect user model being used. – Manuel Herrera May 16 '19 at 22:56