Django 1.5 custom User model error. "Manager isn't available; User has been swapped"
Asked Answered
C

7

20

I extend the django user model as described in the dev doc. I wan't to keep most of the original User model features so I extend the AbstractUser class. I've defined in settings.py:

AUTH_USER_MODEL = 'myapp.CustomUser'

My user class:

class CustomUser(AbstractUser):
  custom_field = models.ForeignKey('OtherModel')
  objects = UserManager()

Everything seems to work fine but when I try to make it managed by the admin site:

admin.site.register(CustomUser, UserAdmin)

I get this error on the admin CustomUser creation page (after validation of the password confirmation form):

AttributeError: Manager isn't available; User has been swapped for 'myapp.CustomUser'

The point is that I need this model managed by the admin site in order to have the same creation process as with the original User model (two step process with password validation).

Codicil answered 26/11, 2012 at 15:42 Comment(2)
The first line of @thecore's correctly fixes the problem (https://mcmap.net/q/616690/-django-1-5-custom-user-model-error-quot-manager-isn-39-t-available-user-has-been-swapped-quot). Maybe you could mark it as "the answer" - would have saved me time! ;)Neighbors
@RichardCorden THANK YOU!!!Biform
L
20

You need only change form for adding user(overwrite clean_username and change User on get_user_model()

Full working example(If you inherited from AbstractUser)

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()

    def clean_username(self):
        username = self.cleaned_data["username"]
        try:
            get_user_model().objects.get(username=username)
        except get_user_model().DoesNotExist:
            return username
        raise forms.ValidationError(self.error_messages['duplicate_username'])

class MyUserAdmin(UserAdmin):
    form = MyUserChangeForm
    add_form = MyUserCreationForm
    fieldsets = (
        (None, {'fields': [('username', 'password'),]}),
        (_('Personal info'), {'fields': ('first_name', 'last_name', 'email')}),
        (_('Permissions'), {'fields': ('is_active', 'is_staff', 'is_superuser',
                                   'groups', 'user_permissions')}),
        (_('Important dates'), {'fields': ('last_login', 'date_joined')}),
        )

admin.site.register(MyUser, MyUserAdmin)
Latashalatashia answered 30/11, 2012 at 8:25 Comment(4)
You could split your answer into the minimum required to fix the problem (ie. to use get_user_model and overwrite clean_username) just to emphasize that this is all that's needed. More info can be found here (code.djangoproject.com/ticket/19353)Neighbors
I write answer before view this ticket. And now see then ticket is not closed.Latashalatashia
Ok - you got the +1 anyway!Neighbors
:) Real not only get_user_model is answer. Need redefine forms for Change and Creation user, else error in admin. I see ticket- may be not want lost backward compatible and add get_user_model() in forms Meta..Latashalatashia
A
14

I struggled with this error for hours. For me I needed to remove all references to

from django.contrib.auth.models import User

and then replace it with:

from myapp.models import MyUser as User

This is assuming your custom User model is in an app called myapp and you called the model MyUser.

I'm using as User so that I don't have to change where my existing code that makes reference to the the User object from django.contrib.auth.models.

Good luck!

Alan

@aviars

Anthropophagy answered 8/10, 2013 at 0:40 Comment(0)
S
4

You probably should look at full example in official documentation:

https://docs.djangoproject.com/en/dev/topics/auth/customizing/#a-full-example

There are some uncovered questions (permissions handling, for example), but, at least, it's working.

Sanyu answered 8/3, 2013 at 10:56 Comment(1)
Thanks, Sometimes Official references are way more easy and awesomeLambaste
R
0

From Django docs:

You should also define a custom manager for your User model.

Runkel answered 26/11, 2012 at 15:58 Comment(3)
Actually I extended UserManager, but I get the same result. I didn't show it in order to make my question shorter.Codicil
You should probably extend BaseUserManager.Runkel
If I extend BaseUserManager I have to override most of the AbstractUser fields and methods, particulary if I want to use the admin site for user creation. I'd prefer to use AbstractUser, as long as it's mentionned in the django dev doc.Codicil
S
0

Subclass AbstractUser already handle objects = UserManager() for you (this code on github at line 327). You don't need to define it in your model again.

I'm not sure why it come with that error. But below config seem work for me with latest Dev version.

Model.py:

class CustomUser(AbstractUser):
  custom_field = models.ForeignKey('OtherModel')
  # remove : objects = UserManager()
Shandra answered 26/11, 2012 at 17:2 Comment(1)
Thanks for reply. The result is the same without this definition. I just tested now. In fact, if I don't mind the admin site everything works. The error occurs when I send the first user creation form in the model site (the form with username password and password confirmation fields)Codicil
C
0

I've found a solution: I don't use UserAdmin to register the CustomUser in the admin site, I use a custom ModelAdmin.

class CustomUserAdmin(admin.ModelAdmin):

  add_form = CustomUserCreationAdminForm
  add_fieldsets = (
    (None, {
        'classes': ('wide',),
        'fields': ('username', 'password1', 'password2')}
    ),
  )
  def get_fieldsets(self, request, obj=None):
    if not obj:
        return self.add_fieldsets
    return super(CustomUserAdmin, 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(CustomUserAdmin, self).get_form(request, obj, **defaults)

Because I want to have a creation form different from the update form, I override the get_form function of the Model Admin as done in the UserAdmin django code. I also have created a custom Creation form for my custom user: CustomUserCreationForm

I received a response in the django-users mailing list that may be better than mine: Unregister the original User class from the admin site and then register the CustomUser with UserAdmin:

admin.site.unregister(User)
admin.site.register(CustomUser, UserAdmin)

Not tested yet.

EDIT: this last solution doesn't work

Regards

Codicil answered 27/11, 2012 at 21:23 Comment(0)
E
0

UserAdmin is already registered to manage User, at the end of contrib/auth/admin.py

admin.site.register(User, UserAdmin)

Given you want to register UserAdmin with CustomUser, I think you would first have to unregister the User/UserAdmin pair:

admin.site.unregister(User)

then register your new model. Given the lack of control in the order of module loading, you could create a class derived from UserAdmin and manage your user model with it. This would work everytime, if I'm thinking properly.

Expectation answered 16/5, 2013 at 16:0 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.