Skip to content

User model mapping issue w/ get_user when User model uses "email" field as USERNAME_FIELD #7

@anyeone

Description

@anyeone

Hi, in my user model I am using the email address field as the username, i.e. in my User model:
USERNAME_FIELD = 'email'

This means that my User has no 'username' property.

As such, when I call CognitoUser.get_user(), I am getting an error when it tries to reconstruct my User model from the database:

File "/Users/anye/bcve/lib/python3.5/site-packages/warrant/init.py", line 460, in get_user
metadata=user_metadata,attr_map=attr_map)
File "/Users/anye/bcve/lib/python3.5/site-packages/django_warrant/backend.py", line 37, in get_user_obj
defaults=user_attrs)
File "/Users/anye/bcve/lib/python3.5/site-packages/django/db/models/manager.py", line 85, in manager_method
return getattr(self.get_queryset(), name)(*args, **kwargs)
File "/Users/anye/bcve/lib/python3.5/site-packages/django/db/models/query.py", line 476, in update_or_create
lookup, params = self._extract_model_params(defaults, **kwargs)
File "/Users/anye/bcve/lib/python3.5/site-packages/django/db/models/query.py", line 534, in _extract_model_params
"', '".join(sorted(invalid_params)),
django.core.exceptions.FieldError: Invalid field name(s) for model User: 'username'.

I tried adding a mapping between username and email but that did not help the issue. My mapping looks like:
COGNITO_ATTR_MAPPING={
'email': 'email',
'given_name': 'first_name',
'family_name': 'last_name',
'username': 'email'
}

Update:
I think the problem is actually twofold; it happens either when trying to create unknown users or get the User from cognito:
backend.py

it's the CognitoUser.user_class.objects.update_or_create() and CognitoUser.user_class.objects.get(username=username) methods that are throwing the exception because it assumes there is a username field on the user_class.

def get_user_obj(self,username=None,attribute_list=[],metadata={},attr_map={}):
user_attrs = cognito_to_dict(attribute_list,CognitoUser.COGNITO_ATTR_MAPPING)
django_fields = [f.name for f in CognitoUser.user_class._meta.get_fields()]
extra_attrs = {}
for k, v in user_attrs.items():
if k not in django_fields:
extra_attrs.update({k: user_attrs.pop(k, None)})
if getattr(settings, 'CREATE_UNKNOWN_USERS', True):
user, created = CognitoUser.user_class.objects.update_or_create(
username=username,
defaults=user_attrs)

else:
try:
user = CognitoUser.user_class.objects.get(username=username)
for k, v in iteritems(user_attrs):
setattr(user, k, v)
user.save()
except CognitoUser.user_class.DoesNotExist:
user = None
if user:
for k, v in extra_attrs.items():
setattr(user, k, v)
return user

I'm not sure if fixing this is going to require overriding these methods from the Warrant library, since those are assuming a username field, or whether you can simply add conditional logic here to either get/update_or_create by either username or USERNAME_FIELD?

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions