I use a serializer to process the data comming from the frontend. The data is basically a username, email and password. The data will be saved in a database and the username will be displayed in the frontend later on. I am wondering if the serializer is already escaping " and < characters to protect from xss-attacks. If it isn't, is there a simple way to configure the serializer to do so? My serializer looks like that:
# Register Serializer
class RegisterSerializer(serializers.ModelSerializer):
profile = ProfileSerializer(required=True)
class Meta:
model = User
fields = ('id', 'username', 'email', 'password', 'profile')
extra_kwargs = {'password': {'write_only': True}}
def create(self, validated_data):
user = User.objects.create_user(
username=validated_data['username'],
email=validated_data['email'],
password=validated_data['password']
)
profile_data = validated_data.pop('profile')
user.profile.company_name = profile_data['company_name']
user.is_active = False
user.save()
return user
Related
I want to make a user registration form. Everything works and the user is saved, but his password is not stored. When I see the user page in admin it is in the password field -> "Invalid password format or unknown hashing algorithm.". i use default user mode.
this is my code ->
serializers.py
class RegisterSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = ('id', 'username', 'email', 'password', )
extra_kwargs = {'password': {'write_only': True},}
def create(self, validated_data):
user = User(
username=validated_data['username']
)
user.set_password(validated_data['password'])
user.save()
return user
views.py
class CreateUser(generics.CreateAPIView):
permission_classes=[AllowAny]
serializer_class=RegisterSerializer
def post(self, request, *args, **kwargs):
serializer = self.get_serializer(data=request.data)
serializer.is_valid(raise_exception=True)
user = serializer.save()
token, _ = Token.objects.get_or_create(user=user)
return Response({
"user": RegisterSerializer(user, context=self.get_serializer_context()).data,
"token": token.key
})
So, I can get data and it all works but I can't seem to work out how to update it without updating everything, just what the user wants to update,
I came up with this 'update' method below but I can't seem to get it to work.
Any help would be greatly appreciated.
Thanks,
George.
views.py
class UserDetailsAPIView(CreateAPIView):
serializer_class = UserDetailSerializer
queryset = User.objects.all()
permission_classes = (IsAuthenticated,)
def get(self, request):
serializer = UserDetailSerializer(request.user)
return Response(serializer.data)
def update(self, validated_data):
email = validated_data['email']
first_name = validated_data['first_name']
last_name = validated_data['last_name']
phone_number = validated_data['phone_number']
password = validated_data['password']
user_obj = User(
email=email,
first_name=first_name,
last_name=last_name,
phone_number=phone_number
)
user_obj.set_password(password)
user_obj.save()
return validated_data
serializers.py
class UserDetailSerializer(ModelSerializer):
class Meta:
model = User
fields = [
'first_name',
'last_name',
'email',
'phone_number',
'is_active',
'email_confirmed',
'phone_number_confirmed',
'date_joined',
'last_login',
'nick_name',
'id'
]
You almost got it right, what you are trying to do is probably createOrUpdate, hence you better check if the User already exists.
Reference: Look at UserDetail
Notice the link user = get_or_none(User, user_id=user_id), where I first check if the user is present to update particular fields (as seen in the dictionary update_user)
Custom User Model:
class User(AbstractUser):
ROLE_CHOICES = (
('R', 'rider'),
('D', 'driver'),
)
role = models.CharField(max_length=1, choices=ROLE_CHOICES)
phone_number = models.CharField(max_length=10)
cab = models.OneToOneField('Cab', on_delete=models.CASCADE, blank=True, null=True)
Rider serializer:
class RiderSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = ('id', 'username', 'email', 'phone_number', 'password')
extra_kwargs = {
'password': {'write_only': True}
}
def create(self, validated_data):
username = validated_data.pop('username')
password = validated_data.pop('password')
instance = User(username, **validated_data)
if password is not None:
instance.set_password(password)
instance.save()
return instance
Rider function based view method:
#api_view(['GET', 'POST'])
def rider_list(request):
if request.method == 'GET':
riders = User.objects.filter(role='R')
serializer = RiderSerializer(riders, many=True)
return Response(serializer.data)
elif request.method == 'POST':
serializer = RiderSerializer(data=request.data)
if serializer.is_valid(raise_exception=True):
serializer.save(role='R')
return Response(serializer.data, status=status.HTTP_201_CREATED)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
rider endpoint: /riders/
I am able to create a user object but user authentication fails as password is getting stored as plain text in object.
I have tried using User.objects.create_user(username, password=password, **validated_data) to set password as hashed value but it does not work
I have also tried using make_password method to set hashed password but nothing seems to work.
Please tell me what am i missing. How do i store the hashed password in password field of custom user object.
create() method should be part of serializer class, not part of Meta:
class RiderSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = ('id', 'username', 'email', 'phone_number', 'password')
extra_kwargs = {
'password': {'write_only': True}
}
def create(self, validated_data):
password = validated_data.pop('password')
instance = User(**validated_data)
if password is not None:
instance.set_password(password)
instance.save()
return instance
Also you don't need to pop username field. Just pop password and use it in set_password method.
how do I create user with default group? my serializer
class UserSerializer(serializers.ModelSerializer):
password = serializers.CharField(write_only=True)
class Meta:
model = User
fields = ('username', 'first_name', 'last_name', 'email', 'password')
def create(self, validated_data):
user = super(UserSerializer, self).create(validated_data)
user.set_password(validated_data['password'])
user.save()
return user
views.py
class UserView(viewsets.ModelViewSet):
queryset = User.objects.all()
serializer_class = UserSerializer
How do I set user group when creating from this view?
Just add something like
user.groups.add(Group.objects.get(name='Whatever'))
after user.save() in the create method.
I want to send a custom response from serializers create view to front-end of my application. I tried rest framework Response tutorials but it does not work. My code is:
class UserSerializer(serializers.ModelSerializer):
"""Serializer to serialize user model object"""
class Meta:
model = User
fields = ('id', 'username', 'password', 'first_name', 'last_name')
extra_kwargs = {'password': {'write_only': True}}
def create(self, validated_data):
"""create a new user"""
firstname = self.initial_data['first_name']
lastname = self.initial_data['last_name']
fullname = str(firstname) +" "+ str(lastname)
email = self.initial_data['username'].lower()
try:
customer = User.create(
name=fullname,
email=email)
except Error as e:
error = {'message': e._message or 'Unknown error'}
return Response(error,status=status.HTTP_400_BAD_REQUEST)
serializers.py
class UserSerializer(serializers.ModelSerializer):
"""Serializer to serialize user model object"""
class Meta:
model = User
fields = ('id', 'username', 'password', 'first_name', 'last_name')
extra_kwargs = {'password': {'write_only': True}}
def create(self, validated_data):
"""create a new user"""
firstname = validated_data['first_name']
lastname = validated_data['last_name']
fullname = str(firstname) +" "+ str(lastname)
email = validated_data['username'].lower()
try:
customer = User.objects.create(
name=fullname,
email=email)
return customer
except Exception as e:
error = {'message': ",".join(e.args) if len(e.args) > 0 else 'Unknown Error'}
raise serializers.ValidationError(error)
So you want to change the representation of the User (the shape of the JSON response) from this view. To do this you need to change the .to_representation(self, obj) method in the serializer:
class UserSerializer(serializers.ModelSerializer):
"""Serializer to serialize user model object"""
class Meta:
model = User
fields = ('id', 'username', 'password', 'first_name', 'last_name',)
write_only_fields = ('id', 'password',)
def to_representation(self, obj):
return {
'firstname': obj.first_name,
'lastname': obj.last_name,
'fullname': obj.first_name+' '+obj.last_name,
'email': obj.username.lower()
}
This should mean that whenever a request is made that uses this serializer the user will only ever see those 4 fields in the JSON, e.g.
{
"firstname":"Salman",
"lastname": "Ahmed",
"fullname": "Salman Ahmed",
"email": "salman_ahmed#email.com"
}
More details on this is hidden in their docs here.