问题
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?
回答1:
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.
回答2:
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.
来源:https://stackoverflow.com/questions/51532288/django-rest-auth-error-save-takes-1-positional-argument-but-2-were-given