I am done with the registration as you can see. Now I want to send email verification so users can confirm. So once a user register, he/she gets a mail for confirmation.
how do I send email verification using "ListCreateAPIView"?
Do I need a third party package?
Can someone help me out? Thanks
Here is my view
class UserList(generics.ListCreateAPIView):
queryset = User.objects.all()
serializer_class = UserSerializer
class UserDetail(generics.RetrieveAPIView):
queryset = User.objects.all()
serializer_class = UserSerializer
My serializer.py
class UserSerializer(serializers.ModelSerializer):
email = serializers.EmailField(required=True, validators=[UniqueValidator(queryset=User.objects.all())])
username = serializers.CharField(required=True, validators=[UniqueValidator(queryset=User.objects.all())])
password = serializers.CharField(min_length=8, style={'input_type': 'password', 'placeholder': 'Password'})
def create(self, validated_data):
user = User.objects.create_user(validated_data['username'], validated_data['email'], validated_data['password'])
return user
class Meta:
model = User
fields = ('id', 'username', 'email', 'password')
from django.core.mail import send_mail
class UserList(generics.ListCreateAPIView):
queryset = User.objects.all()
serializer_class = UserSerializer
def perform_create(self, serializer):
created_object = serializer.save()
send_mail('Subject here','Here is the message.','from#example.com',
[created_object.email], fail_silently=False,)
send email when object has been created
for create a link and verify follow this tutorial doc
You can try django-djoser link.
Related
So I can't figure out how to make this registration view can only accept registrations from my react app. Currently, anybody can put values in my fields and then my API will accept it. I would like to make it restricted in some way so that it only accepts values through the apps that I allow.
serializers.py
# Serializer for user info for the registration API
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = User # for the User model, use get_user_model for custom
fields = ('id', 'username', 'password', 'email', 'first_name', 'last_name',)
extra_kwargs = {'password': {'write_only': True}}
read_only_fields = ('id',)
# override create method
def create(self, validated_data):
user = User.objects.create(
username=validated_data['username'],
email=validated_data['email'],
first_name=validated_data['first_name'],
last_name=validated_data['last_name']
)
user.set_password(validated_data['password'])
user.save()
return user
views.py
class RegisterUserView(generics.CreateAPIView):
model = User
permission_classes = [permissions.AllowAny, ]
serializer_class = UserSerializer
queryset = ''
As stated in DRF documentation http://www.django-rest-framework.org/api-guide/parsers/#multipartparser, in order to parse multipart/form-data, the MultiPart and form parser must be used. I have a supiscion this is a problem in the Django Rest Framework because I saw a solution on their github issue saying it work using APIView.
from django.contrib.auth.models import User
from rest_framework import viewsets
from api.serializers import UserSerializer,
from rest_framework.parsers import MultiPartParser, FormParser
from rest_framework.response import Response
from rest_framework import status
class UserViewSet(viewsets.ModelViewSet):
"""
API endpoint that allows users to be viewed or edited.
"""
queryset = User.objects.all()
parser_classes = (MultiPartParser, FormParser)
serializer_class = UserSerializer
Picture of me sending request to Postman with result:
Edit: Adding UserSerializer class
class UserSerializer(serializers.HyperlinkedModelSerializer):
snapcapsules = SnapCapsuleSerializer(
many=True,
read_only=True,
allow_null=True,
)
class Meta:
model = User
fields = ('snapcapsules', 'url', 'username', 'email', 'password', )
write_only_fields = ('password',)
def create(self, validated_data):
user = User.objects.create(
username=validated_data['username'],
email=validated_data['email'],
)
user.set_password(validated_data['password'])
user.save()
return user
def update(self, instance, validated_data):
capsules_data = validated_data.pop('snapcapsules')
for capsule in capsules_data:
SnapCapsule.objects.create(user=instance, **capsule)
return instance
This is might not the issue with the ContentType. The error response says that,the UserSerializer excpect a payloadordata which include username and password field
So, Please try to add those fields to the request body and try again
UPDATE
The problem with the Orginal Post was, he added extra headers in POSTMAN (see the pic below) .
Postman will add appropriate Headers aromatically for you. So, you don't have to explicitly mention it
I removed one line and then it worked!
class UserViewSet(viewsets.ModelViewSet):
"""
API endpoint that allows users to be viewed or edited.
"""
queryset = User.objects.all()
serializer_class = UserSerializer
Also, the serializer can be rewrite as follows:
class UserSerializer(serializers.HyperlinkedModelSerializer):
...
def create(self, validated_data):
return User.objects.create_user(
username=validated_data['username'],
email=validated_data['email'],
password=validated_data['password']
)
...
i'm using Django 1.11 and the Django Rest Framework in order to create an API, where a user can create and update an employee which is related to the django user model.
The stripped down code i've got looks like this:
I've got this model:
class Employee(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE, related_name='employee')
uuid = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
these two viewsets:
class UserViewSet(viewsets.ModelViewSet):
serializer_class = serializers.UserSerializer
permission_classes = [permissions.IsAuthenticated]
and
class EmployeeViewSet(viewsets.ModelViewSet):
serializer_class = serializers.EmployeeSerializer
permission_classes = [permissions.IsAuthenticated]
and these two serializers:
class UserSerializer(serializers.HyperlinkedModelSerializer)
class Meta
models = User
fields = ('url', 'id', 'username', 'email', 'is_staff', 'first_name', 'last_name', 'password')
read_only_field = ('id',)
def validate(self, data)
# ... Check if data is valid and if so...
return data
and
class EmplyoeeSerializer(serializers.HyperlinkedModelSerializer):
user = UserSerializer()
class Meta:
model = Employee
field = ('url', 'uuid', 'user')
read_only_field = ('uuid')
def validate(self, data):
return data
def create(self, validated_data):
user = User(**validated_data['user'])
user.save()
employee = Employee(user=user)
employee.save()
return employee
def update(self, employee, user):
employee.user.username = user.username
employee.user.email = user.email
employee.user.first_name = user.first_name
employee.user.last_name = user.last_name
employee.user.is_staff = user.is_staff
# ... Check if password has changed, and if so...
employee.user.set_password(user.password)
employee.user.save()
employee.save()
return employee
also i've got these two routers in my urls.py
router = routers.DefaultRouter()
router.register(r'api/user', views.UserViewSet, base_name='user')
router.register(r'api/employee', views.UserViewSet, base_name='employee')
Creating and updating an instance of user is no problem.
I can also create an employee which in return will create an user and then an employee assigend to that user.
I can even update the username of the employee and the user will get updated too,
but i can't update first_name, last_name, email, is_staff and password.
DRF keeps telling me that the username is already taken, but when i change the username and other information like first_name and last_name and then send a PUT request to the server, the employee and associated user instance are getting updated properly.
What am i missing?
Why can't i update the employees user instance like i can update the normal user instance when i'm at the user api endpoint? :/
Thanks in advance,
any help would be appreciated.
Finally i found out what i was missing.
The UserSerializers adds django.contrib.auth.validators.UnicodeUsernameValidator and UniqueValidator to the field username which gets checked every time i do a put request.
Adding validators = [] to the Meta Class of UserSerializer solved my problem.
I'm trying to add user registration functionality to my Django REST application.
Here is my serializer:
from django.contrib.auth.models import User
from rest_framework import serializers
class UserSerializer(serializers.HyperlinkedModelSerializer):
snippets = serializers.HyperlinkedRelatedField(many=True, view_name='snippet-detail', read_only=True)
class Meta:
model = User
fields = ('url', 'id', 'username', 'password', 'email', 'snippets')
Here is my views:
from snippets.serializers import UserSerializer
from django.contrib.auth.models import User
from rest_framework import viewsets
class UserViewSet(viewsets.ModelViewSet):
"""
This viewset automatically provides `list` and `detail` actions.
"""
queryset = User.objects.all()
serializer_class = UserSerializer
Right now it's storing the password in plain text. How can I encode the password?
I would prefer to continue using the ViewSet classes as they're very clean and convenient.
class UserCreateSerializer(ModelSerializer):
def create(self, validated_data):
instance = User.objects.create_user(**validated_data)
return instance
class Meta:
model = User
fields = ('username', 'email', 'password')
class UserViewSet(ModelViewSet):
queryset = User.objects.all()
serializer_class = UserCreateSerializer
permission_classes = (IsAuthenticated)
def get_permissions(self):
if self.action in ('create',):
self.permission_classes = [AllowAny, ]
return super(self.__class__, self).get_permissions()
def create(self, request, *args, **kwargs):
serializer = UserCreateSerializer(data=request.data)
if serializer.is_valid():
user = serializer.create(serializer.validated_data)
return Response('success')
else:
return Response(serializer.errors)
User.objects.create_user() will encode your password with django default encryption algorithm(PBKDF2).And you can use make_password to change your origin password to encoded one,or you can use user.set_password(request.data['pwd_new'])
from django.contrib.auth.hashers import make_password
more info here
I'm trying to create an API for my user registration using Django Rest Framework. I created a serializer by following the step from the api-guide
class CreateUserSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = ('email', 'username', 'password')
extra_kwargs = {'password': {'write_only': True}}
def create(self, validated_data):
user = User(
email=validated_data['email'],
username=validated_data['username']
)
user.set_password(validated_data['password'])
user.save()
return user
However, I keep getting the Invalid password format or unknown hashing algorithm. for my newly created user. I've tried to use make_password from django.contrib.auth.hashers, but I still can't resolve this issue.
Thanks
You can try it in this way
from django.contrib.auth.hashers import make_password
user = User.objects.create(
email=validated_data['email'],
username=validated_data['username'],
password = make_password(validated_data['password'])
)
You can overwrite the perform_create method in CreateAPIView
from rest_framework.generics import CreateAPIView
class SignUpView(CreateAPIView):
serializer_class = SignUpSerializers
def perform_create(self, serializer):
instance = serializer.save()
instance.set_password(instance.password)
instance.save()
You could also use a field validation function for the password field by adding a validate_password method to your serializer and make it return the hash.
from rest_framework.serializers import ModelSerializer
from django.contrib.auth.hashers import make_password
class UserSerializer(ModelSerializer):
class Meta:
model = backend.models.User
fields = ('username', 'email', 'password',)
validate_password = make_password
In the serializer redefine the function create with this:
from django.contrib.auth.hashers import make_password
class UserSerializer(ModelSerializer):
def create(self, validated_data):
validated_data['password'] = make_password(validated_data['password'])
return super(UserSerializer, self).create(validated_data)
And this all! :D
You can do this in the views perform_create method:
from django.contrib.auth.hashers import make_password
def perform_create(self, instance):
current_user = self.request.user
user_exists = CustomUser.objects.filter(
email=self.request.data['email']).first()
if user_exists:
raise MethodNotAllowed
else:
instance.save(is_active=False, is_confirmed=False,
password=make_password(self.request.data['password']))
Another simple solution is to use User.objects.create_user() in your create method like below
def create(self, validated_data):
user = User.objects.create_user(**validated_data)
return user
I know it's an old thread but i got this question today and i like to share my solution here.
You can define your serializer simple and like below:
class CreateUserSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = ('email', 'username', 'password')
extra_kwargs = {'password': {'write_only': True}}
on the other hand in your view you can override perform_create method as below:
class UserView(ViewSets.ModelViewSet):
queryset = User.objects.all()
serializer_class = UserCreateSerializer
def perform_create(self , serializer):
new_user =
User.objects.create(username=self.request.data.get("username"))
new_user.set_password(self.request.data.get("password"))
serializer.save(password=user.password)
in this way, you can pass extra information to serializer to save.