0

I have followed this tutorial to customize the user model in my django app:

https://testdriven.io/blog/django-custom-user-model/

The idea is to get rid of "username" and use "email" as the user key. I could follow the instructions and it worked allright, no problem.

Apart from that, I need all my database fields to be encrypted (and, some of them, searchable). So I used this library:

https://pypi.org/project/django-searchable-encrypted-fields/

And, also, no problem. I could encrypt my DB fields.

The issue comes when I also try to encrypt my Django customUser's "email" field, by doing this:

class CustomUser(AbstractBaseUser, PermissionsMixin):
    _email_data = fields.EncryptedCharField(max_length=100, blank=True)
    email = fields.SearchField(hash_key="94fd9321e57f061805...redacted...43d9485776dee73a", encrypted_field_name="_email_data", unique=True)
    is_staff = models.BooleanField(default=False)
    is_active = models.BooleanField(default=True)
    date_joined = models.DateTimeField(default=timezone.now)

    USERNAME_FIELD = 'email'
    REQUIRED_FIELDS = []

    objects = CustomUserManager()

    def __str__(self):
        return self.email

This breaks my user model. After doing this, when I try to create a superuser I get this error (after typing the email address):

(base) C:\Users\jaume\Desktop\Projects\repos\whistleblower>python manage.py createsuperuser
Email: admin@admin.com
Traceback (most recent call last):
  File "manage.py", line 22, in <module>
    main()
  File "manage.py", line 18, in main
    execute_from_command_line(sys.argv)
  File "C:\ProgramData\Anaconda3\lib\site-packages\django\core\management\__init__.py", line 401, in execute_from_command_line
    utility.execute()
  File "C:\ProgramData\Anaconda3\lib\site-packages\django\core\management\__init__.py", line 395, in execute
    self.fetch_command(subcommand).run_from_argv(self.argv)
  File "C:\ProgramData\Anaconda3\lib\site-packages\django\core\management\base.py", line 330, in run_from_argv
    self.execute(*args, **cmd_options)
  File "C:\ProgramData\Anaconda3\lib\site-packages\django\contrib\auth\management\commands\createsuperuser.py", line 79, in execute
    return super().execute(*args, **options)
  File "C:\ProgramData\Anaconda3\lib\site-packages\django\core\management\base.py", line 371, in execute
    output = self.handle(*args, **options)
  File "C:\ProgramData\Anaconda3\lib\site-packages\django\contrib\auth\management\commands\createsuperuser.py", line 111, in handle
    username = self.get_input_data(self.username_field, message, default_username)
  File "C:\ProgramData\Anaconda3\lib\site-packages\django\contrib\auth\management\commands\createsuperuser.py", line 213, in get_input_data
    val = field.clean(raw_value, None)
  File "C:\ProgramData\Anaconda3\lib\site-packages\encrypted_fields\fields.py", line 364, in clean
    return model_instance._meta.get_field(self.encrypted_field_name).clean(
AttributeError: 'NoneType' object has no attribute '_meta'

Does anyone know how to solve this issue? Or, if it is not possible, how else could I have the email encrypted like the rest of the fields?

I am running:

  • Python 3.8.3
  • Django 3.1.4
  • PostgreSQL 13.1 on Windows 10

Thank you very much :)

jaume
  • 163
  • 2
  • 11

1 Answers1

0

The package creator pointed out to me that the 'createsuperuser' was a known issue. See the bottom of Django-Searchable-Encrypted_Field's README (https://pypi.org/project/django-searchable-encrypted-fields/):

In our test app, the User model uses a SearchField for the username. This means that when creating a superuser you must provide the --username argument: python manage.py createsuperuser --username bob to avoid an error.

In my case, since my user model had 'email' but not 'username', he suggested I tried:

python manage.py createsuperuser --email whatever@test.com

It did not work, but made me realize that the problem was only when creating superusers. The app was otherwise working alright. So I just used the python shell to create a regular user and then set its 'is_superuser' property to True (see instructions: How to create user from django shell):

user=User.objects.create_user('whatever@test.com', password='bar')
user.is_superuser=True
user.is_staff=True
user.save()

The package creator then confirmed that everything else would work as expected. Kudos to him! (Guy Willett)

jaume
  • 163
  • 2
  • 11