Began to deal with DRF
. I want to authenticate users with jwt token
. But nothing happens. I’ve come across the problem that when creating a user, I get: {"user": {"email": ["This field is required."], "Username": ["This field is required."], "Password": ["This field is required."]}}. Although all the fields are filled.
models
class UserManager(BaseUserManager):
def create_user(self, username, email, password=None):
if username is None:
raise TypeError('Users must have a username.')
if email is None:
raise TypeError('Users must have an email address.')
user = self.model(username=username, email=self.normalize_email(email))
user.set_password(password)
user.save()
return user
class User(AbstractBaseUser, PermissionsMixin):
username = models.CharField(db_index=True, max_length=255, unique=True)
email = models.EmailField(db_index=True, unique=True)
is_active = models.BooleanField(default=True)
is_staff = models.BooleanField(default=False)
bio = RichTextUploadingField(_('bio'), blank=True)
city = models.CharField(_('city'), max_length=100, blank=True)
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = ['username']
objects = UserManager()
@property
def token(self):
return self._generate_jwt_token()
def _generate_jwt_token(self):
dt = datetime.now() + timedelta(days=60)
token = jwt.encode({
'id': self.pk,
'exp': int(dt.strftime('%s'))
}, settings.SECRET_KEY, algorithm='HS256')
return token.decode('utf-8')
serializers
class RegistrationSerializer(serializers.ModelSerializer):
password = serializers.CharField(
max_length=128,
min_length=8,
write_only=True
)
token = serializers.CharField(max_length=255, read_only=True)
class Meta:
model = User
fields = ['email', 'username', 'password', 'token']
def create(self, validated_data):
return User.objects.create_user(**validated_data)
view
class RegistrationAPIView(APIView):
permission_classes = (AllowAny,)
renderer_classes = (UserJSONRenderer,)
serializer_class = RegistrationSerializer
def post(self, request):
print('request.data: \t\t', request.data) #<QueryDict: {'{\n "email": "sasasas@sasas.ssas",\n "username": "sasasasas",\n "password": "12345678"\n}': ['']}>
print('request.data.get("user", {}): \t', request.data.get('user', {})) #{}
user = request.data.get('user', {})
serializer = self.serializer_class(data=user)
serializer.is_valid(raise_exception=True) #Error
serializer.save()
return Response(serializer.data, status=status.HTTP_201_CREATED)
I didn't read the tutorial in detail, but it seems that for some reason the payload you post to the endpoint should be of a different shape than what DRF usually expects.
There is one thing we need to fix though. Notice how the response from the "Register" request has all of the user's information at the root level. Our client expects this information to be namespaced under "user." To do that, we'll need to create a custom DRF renderer.
So instead of posting this:
{
"email": "user@example.com",
"username": "user",
"password": "hunter2"
}
You have to nest it all under the "user" key.
{
"user": {
"email": "user@example.com",
"username": "user",
"password": "hunter2"
}
}