kbsol
kbsol

Reputation: 532

django-rest-auth error - save() takes 1 positional argument but 2 were given

I'm using django-rest-auth with a custom user model, registration view and serializer. What I'm trying to achieve is an email login instead of username. The api view shows correctly but when I post, I get the error:

TypeError at /rest-auth/registration/
save() takes 1 positional argument but 2 were given

this is the traceback: http://dpaste.com/2FR3DZY

serializer.py

class CustomUserSerializer(serializers.ModelSerializer):
"""Serializer for User objects."""

    class Meta:
        model = models.User
        fields = ('id', 'email', 'name', 'password')
        extra_kwargs ={'password': {'write_only': True}}

    def create(self, validated_data):
        """Create and return a new User."""

        user = models.User(
            email=validated_data['email'],
            name=validated_data['name'] 
        )

        user.set_password(validated_data['password'])
        user.save()

        return user

views.py

class CustomRegistrationsView(RegisterView):
    serializer_class = CustomUserSerializer

urls.py

path('rest-auth/registration/', CustomRegistrationsView.as_view(), name='rest_register'),   
path('rest-auth/', include('rest_auth.urls')),

models.py

class UserManager(BaseUserManager):
"""Helps Django work with our custom user model."""

    def create_user(self, email, name, password=None):
        """Creates a new user object."""

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

        email = self.normalize_email(email)
        user = self.model(email=email, name=name)

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

        return user

    def create_superuser(self, email, name, password):
        """Creates and saves a new superuser with given details."""

        user = self.create_user(email, name, password)

        user.is_superuser = True
        user.is_staff = True

        user.save(using=self._db)

        return user

class User(AbstractBaseUser, PermissionsMixin):
    """Represents a "user" inside our system."""

    email = models.EmailField(max_length=255, unique=True)
    name = models.CharField(max_length=255)
    is_active = models.BooleanField(default=True)
    is_staff = models.BooleanField(default=False)

    objects = UserManager()

    USERNAME_FIELD = 'email'
    REQUIRED_FIELDS = ['name']

    def get_full_name(self):
        """Used to get a users full name."""

        return self.name

    def get_short_name(self):
        """Used to get a users short name."""

        return self.name

    def __str__(self):
        """Django uses this when it needs to convert the object to a string"""

        return self.email

Can anyone advise?

Upvotes: 3

Views: 3709

Answers (2)

Abdulmalik Abdulwahab
Abdulmalik Abdulwahab

Reputation: 76

Because your custom registration view inherits from RegisterView,perform_create method define in RegisterView will call your serializer's save method with a request object based on the implementation and since your serializer inherits from ModelSerializer, the save method does not take any positional argument hence the error.

CustomUserSerializer needs to define a save method that takes the request object as an argument. Check this exempt below from django-rest-auth configuration

The custom REGISTER_SERIALIZER must define a def save(self, request) method that returns a user model instance.

I'll suggest you take a look at the implementation of the default REGISTER_SERIALIZER it'll guide how your custom serializer should look.

Upvotes: 2

Enthusiast Martin
Enthusiast Martin

Reputation: 3091

The Problem is this:

django-rest-auth implements custom RegisterSerializer where the save method takes one additional positional argument request.

  def save(self, request):

This serializer is used by RegisterView from djang-rest-auth.

Normal serializer save method looks like this:

  def save(self, **kwargs):

You use your custom serializer in your view which parent is django-rest-auth RegisterView but your save method does not have the positional request argument, hence the problem.

And the logic in RegisterView assumes correct serializer implementation.

Try to use RegisterSerializer as parent to your serializer - you just need to investigate if it is straigtforward or you need to add/implement something else.

But it might be bit tricky.

But as it seems, you have custom model, custom serializer, custom view - i dont see any reason to use django-rest-auth RegisterView. Just implement your registration view.

Upvotes: 1

Related Questions