Search code examples
djangomodelnatural-key

Django: no attribute 'get_by_natural_key'


i currently try the implement my very own user model. Therefor i created a new app "accounts". But each time when i try to create anew user i get the following error:

AttributeError: 'AnonymousUser' object has no attribute '_meta'

accounts - models.py:

from django.db import models
from django.contrib.auth.models import (
    BaseUserManager, AbstractBaseUser
)



#User Model Manager
class UserManager(BaseUserManager):
    def create_user(self, username, password=None):
        """
        Creates and saves a User with the given username and password.
        """
        if not username:
            raise ValueError('Error: The User you want to create must have an username, try again')

        user = self.model(
            user=self.normalize_username(username),
        )

        user.set_password(password)
        user.save(using=self._db)
        return user

    def create_staffuser(self, username, password):
        """
        Creates and saves a staff user with the given username and password.
        """
        user = self.create_user(
            username,
            password=password,
        )
        user.staff = True
        user.save(using=self._db)
        return user

    def create_superuser(self, username, password):
        """
        Creates and saves a superuser with the given username and password.
        """
        user = self.create_user(
            username,
            password=password,
        )
        user.staff = True
        user.admin = True
        user.save(using=self._db)
        return user


class User(AbstractBaseUser):

    #User fields
    user = models.CharField(verbose_name='username',max_length=30,unique=True)
    bio = models.TextField(max_length=5000, blank=True, null=True)
    pubpgp = models.TextField(blank=True, null=True)

    #Account typs
    active = models.BooleanField(default=True)
    staff = models.BooleanField(default=False) # a admin user; non super-user
    admin = models.BooleanField(default=False) # a superuser
    # notice the absence of a "Password field", that's built in.

    USERNAME_FIELD = 'user'
    REQUIRED_FIELDS = [] # Username & Password are required by default.

    def get_full_name(self):
        # The user is identified by their Username ;)
        return self.user

    def get_short_name(self):
        # The user is identified by their Username address
        return self.user
    def __str__(self):
        return self.user

    def has_perm(self, perm, obj=None):
        """Does the user have a specific permission?"""
        # Simplest possible answer: Yes, always
        return True

    def has_module_perms(self, app_label):
        """Does the user have permissions to view the app `app_label`?"""
        # Simplest possible answer: Yes, always
        return True

    @property
    def is_staff(self):
        """Is the user a member of staff?"""
        return self.staff

    @property
    def is_admin(self):
        """Is the user a admin member?"""
        return self.admin

    @property
    def is_active(self):
        """Is the user active?"""
        return self.active

    objects = UserManager()

After that i jumpt back to settings.py and added the custom user model to my acctual blog application:

AUTH_USER_MODEL = 'accounts.User'

and i also added

INSTALLED_APPS = [
...
    'accounts',
...   
]

All this user model/django stuff is a bit new to me and i have no idea what the error "AttributeError: 'Manager' object has no attribute 'get_by_natural_key'" means.

Thanks :D


Solution

  • Edit: AttributeError: 'UserManager' object has no attribute 'normalize_username'

    normalize_username belongs to AbstractBaseUser, you can try the code below.

    In signup view, when you save the form you already get the user (form.save()). Because the reason from authentication is to verify a set of credentials and getting the user (but we already have the user)

    In this line: user = authenticate(username=username, password=raw_password), the authenticate method takes request as the first argument, so it should be: user = authenticate(request, username=username, password=raw_password), therefore you got the Error 'AnonymousUser' object has no attribute '_meta'.

    Try:

    def signup(request):
        if request.method == 'POST':
            form = UserCreationForm(request.POST)
            if form.is_valid():
                user = form.save()
                login(request, user)
                return redirect('post_list')
    

    Edit UserManager:

    Reaname all created users to some other name (ex. my_user) because you have tow varibales with the same name (the USERNAME_FIELD and the user created)

    Here is the signature of create_user and create_superuser

    create_user(*username_field*, password=None, **other_fields) create_superuser(*username_field*, password, **other_fields)

    They take the USERNAME_FIELD as the first argument, and yours is user

    class UserManager(BaseUserManager):
        def create_user(self, user, password=None):
            """
            Creates and saves a User with the given username and password.
            """
            if not user:
                raise ValueError('Error: The User you want to create must have an username, try again')
    
            my_user = self.model(
                user=self.model.normalize_username(user),
            )
    
            my_user.set_password(password)
            my_user.save(using=self._db)
            return my_user
    
        def create_staffuser(self, user, password):
            """
            Creates and saves a staff user with the given username and password.
            """
            my_user = self.create_user(
                user,
                password=password,
            )
            my_user.staff = True
            my_user.save(using=self._db)
            return my_user
    
        def create_superuser(self, user, password):
            """
            Creates and saves a superuser with the given username and password.
            """
            my_user = self.create_user(
                user,
                password=password,
            )
            my_user.staff = True
            my_user.admin = True
            my_user.save(using=self._db)
            return my_user
    

    I hope this will help.