Custom User Model error
Asked Answered
C

2

8

I'm trying to set up my custom user model in Django. The reason is that I want to use email as the username, and remove the username field entirely. I've run into a error, that I just can't figure out.

Manager isn't available; User has been swapped for 'app.MyUser'
Exception Location: .../django/db/models/manager.py in __get__, line 256
Python Version: 2.7.3

Python Path:    
[...project specific files,
'/usr/lib/python2.7',
'/usr/lib/python2.7/plat-linux2',
'/usr/lib/python2.7/lib-tk',
'/usr/lib/python2.7/lib-old',
'/usr/lib/python2.7/lib-dynload',
'/usr/local/lib/python2.7/dist-packages',
'/usr/lib/python2.7/dist-packages',
'/usr/lib/python2.7/dist-packages/PIL',
'/usr/lib/python2.7/dist-packages/gtk-2.0',
'/usr/lib/pymodules/python2.7',
'/usr/lib/python2.7/dist-packages/wx-2.8-gtk2-unicode']

I've googled like crazy, but haven't found too many pages about this error message. I have found some pages, with suggestions on how to solve it, but none of the suggestions have worked for me.

My code: I've set the custom user model. I have declared the custom user model AUTH_USER_MODEL = 'app.MyUser' in settings.py. I have also set up a custom UserManager:

class MyUserManager(BaseUserManager):

    def create_user(self, email, password=None):
        """
        Creates and saves a User with the given email. Note that none of the optional fields gets values in the creation. These fields will have to be filled out later on.
        """

        if not email:
            raise ValueError('Users must have an email address')

        user = self.model(email=MyUserManager.normalize_email(email))

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

    def create_superuser(self, email, password=None):
        """
        Creates and saves a superuser with the the above mentioned attributes

        """

        user = self.create_user(email, password=password)
        user.is_admin = True
        user.save(using=self._db)
        return user


class MyUser(AbstractBaseUser, PermissionsMixin):
    """
    Custom made User model. No username, instead email is used as unique field and index
    """

    Genders = (('M', 'Man'), ('K', 'Woman'))    
    FirstName = models.CharField(max_length=30)
    LastName = models.CharField(max_length=40)
    Gender = models.CharField(max_length=2, choices=Genders, default='K')
    email = models.EmailField(verbose_name='email address', max_length=255, unique=True, db_index=True,)
    twitter = models.CharField(max_length=30)
    is_admin = models.BooleanField(default=False)


    USERNAME_FIELD = 'email'
    REQUIRED_FIELDS = []

    def get_full_name(self):
        # The user is identified by their email address
        return self.email

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

    def __unicode__(self):
        return self.email

    objects = MyUserManager()

I've tried to declare to different types of UserAdmins, none of which is making any difference,the first one I tried was;

class MyUserAdmin(UserAdmin):
    # The forms to add and change user instances
    #form = UserChangeForm
    #add_form = FrontpageRegistrationForm

    list_display = ('email', 'FirstName', 'LastName', 'Gender', 'twitter')
    list_filter = ()

    add_fieldsets = ((None, {'classes': ('wide',),'fields': ('email', 'password1', 'password2')}),)

    search_fields = ('email',)
    ordering = ('email',)
    filter_horizontal = ()

admin.site.register(MyUser, MyUserAdmin)

I've commented out the two attributes add_form and form because they raised some form errors I wanted to get back to at a later point.

The second UserAdmin was made, after reading about a possible fix here. This didn't help the situation though;

class MyUserAdmin(admin.ModelAdmin):
    # The forms to add and change user instances
    #form = UserChangeForm
    add_form = FrontpageRegistrationForm
    add_fieldsets = ((None, {'classes': ('wide',),'fields': ('email', 'password1', 'password2')}),)

    def get_fieldsets(self, request, obj=None):
        if not obj:
            return self.add_fieldsets
        return super(MyUserAdmin, self).get_fieldsets(request, obj)

    def get_form(self, request, obj=None, **kwargs):
        defaults = {}
        if obj is None:
            defaults.update({'form': self.add_form,'fields': admin.util.flatten_fieldsets(self.add_fieldsets),})

    defaults.update(kwargs)
    return super(MyUserAdmin, self).get_form(request, obj, **defaults)

I've also tried deleting all tables in the db with no luck.

I would be eternally greatful to anyone who even looks at the problem. And if any one were to solve this, I would try my best to talk my wife into naming our firstborn after the Avatar that gave me a solution so that I could go on living my life.

EDIT: I tried setting the AUTH_USER_MODELto mainfolder.app.MyUserI'm sure the "mainfolder" is on the pythonpath. init.py in the app should be correct. The new settings.py gave the following server error; auth.user: AUTH_USER_MODEL is not of the form 'app_label.app_name'.admin.logentry: 'user' has a relation with model smartflightsearch.SFSdb.MyUser, which has either not been installed or is abstract.registration.registrationprofile: 'user' has a relation with model, which has either not been installed or is abstract. A new clue I don't know how to interpret..

Convolvulaceous answered 5/5, 2013 at 14:25 Comment(6)
Is your app name is 'app'?Reference
First of all, don't panic, we'll solve this. :) When do you see the error? Does the error go away if you disable admin? Have you tried debugging in step by step mode?Crosspurpose
@Ivan Ok, that's great to hear :) The error occurs after entering the user credentials on the /admin and pressing "log on". I would expect the error to go away if I turn off admin, Do not have the chance to test right now, But pages not relating to admin works fine.Convolvulaceous
@Reference No, I changed the code sligtly when posting for anonymity purposes, might be a bit paranoid, but anyway.Convolvulaceous
I think we can narrow the problem down to your MyUserAdmin form. When you've submitted the question, your AUTH_USER_MODEL was declared correctly. Have you tried this fix?Crosspurpose
@Rookie, do you still get the error after ensuring that FrontpageRegistrationForm has model = get_user_model() in Meta?Crosspurpose
C
10

TL;DR: Use the code from the Solution part at the end of the following answer.

Longer explanation: You see, as of Django 1.5, it's not enough to subclass Django's UserAdmin to be able to interact with swappable user models: you need to override respective forms as well.

If you jump to django.contrib.auth.admin source, you'll see that the UserAdmin's form and add_form have these values:

# django/contrib/auth/admin.py
class UserAdmin(admin.ModelAdmin):
    ...
    form = UserChangeForm
    add_form = UserCreationForm 

Which point us to forms in django.contrib.auth.forms that do not respect swappable user models:

# django/contrib/auth/forms.py
class UserCreationForm(forms.ModelForm):
    ...
    class Meta:
        model = User  # non-swappable User model here.

class UserChangeForm(forms.ModelForm):
    ...
    class Meta:
        model = User  # non-swappable User model here.

Solution: So, you should follow a great already existing answer (don't forget to vote it up!) which boils down to this:

from django.contrib.auth import get_user_model
from django.contrib.auth.admin import UserAdmin
from django.contrib.auth.forms import UserCreationForm, UserChangeForm

class MyUserChangeForm(UserChangeForm):
    class Meta:
        model = get_user_model()

class MyUserCreationForm(UserCreationForm):
    class Meta:
        model = get_user_model()

class MyUserAdmin(UserAdmin):
    form = MyUserChangeForm
    add_form = MyUserCreationForm

admin.site.register(MyUser, MyUserAdmin)

Hopefully, this would be fixed in the future releases of Django (here's the corresponding ticket in the bug tracker).

Crosspurpose answered 6/5, 2013 at 11:27 Comment(5)
Dear @Ivan, honestly I cannot believe how kind you have been, spending so much of your time and energy to help me with this. Your efforts are truly appreciated! I wish there was some sort of a hero badge each user could give out only once. If such a thing existed, I would give the badge to you! I didn't have any time to work with the problem today, all I have tried is to copy the the forms and the UserAdmin from your solution. That raised an error message, but it seems to stem from the fact that all the fields in the User model, haven't been declared in the change/creation forms. Lt u knw tmrwConvolvulaceous
Thank you very much! And I should probably give you the best comment I ever received badge. :)))Crosspurpose
I don't know, this is probably not the best place to write this, but somehow I can portrait you as a very mature person that values people around him and knows how to care about them. You remind me of my grandfather.Crosspurpose
Thank you for your kind words, but you think to highly of me! But I have been curious of you as well, because of your generous nature, helping a complete stranger with his problems :). It is people like you that make the world a better place, I'm sure! I'm sorry for not getting back to you yesterday, but I unexpectedly had to work at all day. Today is a holiday in Norway (and a lot of other countries too, I imagine), so that means python, hurray :) Your answer solved my problem, so thank you so much again!!Convolvulaceous
Heah, yesterday we had a holiday too, but I spent it drinking vodka with my father and talking about our relatives that fought and/or died in the war. Actually, in the past I was deeply involved in non-commercial projects, and have some plans for the future too. Here are some works of the writer I helped to promote. Again, thanks for kind words! )))))Crosspurpose
L
2

When you said you set AUTH_USER_MODEL = 'app.MyUser' I'm assuming your app where is located the MyUser class, have a structure, perharps, like this:

inside the app/ dir: init.py and models.py and stuff..

so inside the models.py you have the MyUser and inside the init.py:

from models import MyUser

Logjam answered 5/5, 2013 at 20:29 Comment(4)
Thank you for taking the time to look at my problem @user1808134. Yes, the app does contain init.py. I hadn't declared anything in it, but did so now, after seeing your answer. I inserted __all__ = ['views','tests', 'static','models','admin',]but to no avail, same error occurs when pressing "log in" on the admin page (PS. Also tried with from models import MyUser in the init.py fileConvolvulaceous
I tried setting the AUTH_USER_MODELto mainfolder.app.MyUserI'm sure the "mainfolder" is on the pythonpath. I still have the init.py as above. The new settings.py gave the following server error; auth.user: AUTH_USER_MODEL is not of the form 'app_label.app_name'.admin.logentry: 'user' has a relation with model smartflightsearch.SFSdb.MyUser, which has either not been installed or is abstract.registration.registrationprofile: 'user' has a relation with model, which has either not been installed or is abstract. Does this give any hints?Convolvulaceous
I did some research about this issue, and didn't find something enlightening =/ Last time I did work with the new Django custom auth, I've followed the instructions from the django docs, which I know its is not much.Logjam
Thank you for your time. FYI I was helped with the above answer.Convolvulaceous

© 2022 - 2024 — McMap. All rights reserved.