I want to create a Registration API, wherein, I aim to combine the User Model and Profile Model in order to create a new user by adding the username, email, password (User Model fields) and gender, salary, company, and address (Profile Model fields). I attempted to use the source from this link. However, I am not able to POST any data in. This is my code so far:
views.py:
class RegisterAPIView(APIView):
def post(self, request, format=None):
serializer = ProfileSerializer(data=request.data)
if serializer.is_valid():
serializer.save()
return Response("Thank you for registering", status=status.HTTP_201_CREATED)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
serializers.py:
from rest_framework import serializers
from users.models import Profile
from django.contrib.auth.models import User
class ProfileSerializer(serializers.ModelSerializer):
class Meta:
model = Profile
fields = ['gender', 'company', 'salary', 'address']
class RegisterBSerializer(serializers.ModelSerializer): #User Model serializer
profile = ProfileSerializer()
class Meta:
model = User
fields = ['username', 'email', 'password']
def create(self, validated_data):
profile_data = validated_data.pop('profile')
password = validated_data.pop('password', None)
user = User.objects.create(**validated_data)
if password is not None:
user.set_password(password)
user.save()
Profile.objects.create(user = user, **profile_data)
return user
Can anyone hint me on where I am going off-track?.
I am not able to add data via DRF:
image
Usually, I should be getting a Body which states:
{"username" : "this field is required",
"email" : "this field is required",
"password" : "this field is required", (will be hashed using set_password())
"gender" : "this field is required",} etc etc...
You can do this by writing custom to_representation method like this
class RegisterBSerializer(serializers.ModelSerializer): #User Model serializer
profile = ProfileSerializer()
class Meta:
model = User
fields = ['username', 'email', 'password']
def to_representation(self, instance):
data = super().to_representation(instance)
profile = data.pop('profile', {})
data.update(profile)
return data
Related
I have a issuetracker project where a manager can assign a user to a project. The manager selects a project and a user from dropdowns, clicks submit, and an api call is called in the frontend to send that post data to my django APIView assignuser. Assignuser then takes both those values and filters for the correct project and the user, and saves that user to the project user. After checking the projects, I am unable to save a new User to a project as User comes up as null. Is there a specified way in saving foreign keys in the DRF?
assignuser
class assignuser(APIView):
serializer_class = ProjectSerializer
def post(self, request, format=None):
serializer = self.serializer_class(data=request.data)
if serializer.is_valid():
user_name = serializer.get('user')
project_name = serializer.get('project_name')
user = Users.objects.get(user=user_name)
project = Project.objects.get(name=project_name)
project.user = user
project.save()
return Response(ProjectSerializer(project).data, status=status.HTTP_201_CREATED)
else:
return HttpResponse("Incorrect Credentials")
Project Serializer
class ProjectSerializer(serializers.ModelSerializer):
user = SignUpSerializer()
class Meta:
model = Project
fields = ('name', 'description', 'user')
SignUp Serializer
class SignUpSerializer(serializers.ModelSerializer):
class Meta:
model = Users
fields = ('username', 'password', 'email', 'role')
you can do this
class assignuser(APIView):
serializer_class = ProjectSerializer
def post(self, request, format=None):
serializer = self.serializer_class(data=request.data)
if serializer.is_valid():
user_name = serializer.get('user')
project_name = serializer.get('project_name')
user = Users.objects.get(user=user_name)
project = Project.objects.get(name=project_name)
project.user = user
project.user.save()
return Response(ProjectSerializer(project).data, status=status.HTTP_201_CREATED)
else:
return HttpResponse("Incorrect Credentials")
I just started using the Django Rest Framework recently and was wondering how to use 2 models within a single serializer. I have a custom model named 'Profile' and am also using a default Django model 'User'. With these two tables, I planned to use nested representations. Finally, in order to test the RegisterAPI, I wanted to create data using the POSTMAN tool but currently, it's not working as expected.
This is what I had done so far:
models.py:
class Profile(models.Model):
user = models.OneToOneField(User, on_delete = models.CASCADE)
company = models.CharField(max_length=100, blank=True, null=True)
address = models.TextField()
views.py:
class RegisterAPI(APIView):
permission_classes = [AllowAny]
def post(self, request, format=None):
serializer = UserSerializer(data=request.data)
if serializer.is_valid():
serializer.save()
content = {
'result': 'Thanks for registering!'
}
return Response(content, status=status.HTTP_201_CREATED)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
serializers.py:
from rest_framework import serializers
from myapp.models import Profile
from django.contrib.auth.models import User
class ProfileSerializer(serializers.ModelSerializer):
class Meta:
model = Profile
fields = ['company', 'address']
class UserSerializer(serializers.ModelSerializer):
profile = ProfileSerializer(many = True)
class Meta:
model = User
fields = ['username', 'email', 'password', 'profile']
def create(self, validated_data):
profile_data = validated_data.pop('profile')
password = validated_data.pop('password', None)
# instance = self.Meta.model(**validated_data)
user = User.objects.create(**validated_data)
if password is not None:
user.set_password(password)
user.save()
Profile.objects.create(user = user, **profile_data)
return user
Within POSTMAN, I am not able to set the fields 'company' and 'address' for the Profile serializer. How can I do this?
I have a custom user model
class User(AbstractUser):
username = None
email = models.EmailField( unique=True)
phone = models.CharField( max_length=15)
is_pro = models.BooleanField(default=False)
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = ['phone']
objects = UserManager()
#property
def token(self):
"""
Allows us to get a user's token by calling `user.token` instead of
`user.generate_jwt_token().
The `#property` decorator above makes this possible. `token` is called
a "dynamic property".
"""
return self._generate_jwt_token()
def _generate_jwt_token(self):
"""
Generates a JSON Web Token that stores this user's ID and has an expiry
date set to 60 days into the future.
"""
import jwt
from datetime import datetime, timedelta
from django.conf import settings
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')
Now I try make SignIn API with Django Rest Framework using this tutorial https://thinkster.io/tutorials/django-json-api/authentication
serializer.py
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', 'phone', 'password', 'token']
def create(self, validated_data):
# Use the `create_user` method we wrote earlier to create a new user.
return User.objects.create_user(**validated_data)
views.py
class RegistrationAPIView(APIView):
# Allow any user (authenticated or not) to hit this endpoint.
permission_classes = (AllowAny,)
serializer_class = RegistrationSerializer
def post(self, request):
user = request.data.get('user', {})
serializer = self.serializer_class(data=user)
serializer.is_valid(raise_exception=True)
serializer.save()
return Response(serializer.data, status=status.HTTP_201_CREATED)
Then I create a new user an error occured "This field is required." for all my User fields, like email, phone, password.
Screenshot picture http://joxi.ru/12MOMkZt4eeBEr
This is because you set this fields not nullable and required inside User model. To fix it you can add blank=True arguments to the fields which may be blank, like phone:
class User(AbstractUser):
username = None
email = models.EmailField(unique=True)
phone = models.CharField(max_length=15, blank=True)
is_pro = models.BooleanField(default=False)
After this run makemigrations and migrate to apply changes at DB level.
UPD
In view you need to get data from request.data directly:
def post(self, request):
serializer = self.serializer_class(data=request.data)
serializer.is_valid(raise_exception=True)
serializer.save()
return Response(serializer.data, status=status.HTTP_201_CREATED)
request.data doesn't contain user key, so request.data.get('user', {}) return empty dict.
I'm trying to add a custom create method, and am using the Django REST FRAMEWORK. Once a user is created, I want to create an auth token and then return a JSON response with this user AND an auth token.
UPDATE: I was able to update the below to create the user, but now I am getting Cannot assign "<User: User object>": "Token.user" must be a "User" instance What am i doing wrong?
How can I modify the below so when POST to users/, I create a user, create an auth token, and return both?
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = ('first_name', 'last_name', 'email', 's3_link', 'phone_confirmed', 'agreed_to_tos', 'phone_number', 'facebook_id', 'stripe_id', 'phone_verification_code')
class UserViewSet(viewsets.ModelViewSet):
queryset = User.objects.all()
serializer_class = UserSerializer
##ISSUE WITH CODE STARTS HERE
user = serializer.save()
token = Token.objects.create(user=user)
You could use a custom Response to add the token to the user data:
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = ('first_name', 'last_name', 'email', 's3_link', 'phone_confirmed', 'agreed_to_tos', 'phone_number', 'facebook_id', 'stripe_id', 'phone_verification_code')
class UserViewSet(viewsets.ModelViewSet):
queryset = User.objects.all()
serializer_class = UserSerializer
# Customized rest_framework.mixins.CreateModelMixin.create():
def create(self, request, *args, **kwargs):
serializer = self.get_serializer(data=request.data)
serializer.is_valid(raise_exception=True)
# Your code
user = serializer.save()
token = Token.objects.create(user=user)
# Create custom response
data = serializer.data
# You may need to serialize your token:
# token = token.your_token_string_field
data.update({'token': token})
headers = self.get_success_headers(serializer.data)
return Response(data, status=status.HTTP_201_CREATED, headers=headers)
If you want to create a user, I would recommend following this format:
serializers.py:
class AccountCreateSerializer(serializers.ModelSerializer):
class Meta:
model = User
# You will need to check accuracy of fields, but this is for demo purposes
fields = ['username', 'email', 'password']
extra_kwargs = {'password': {'write_only': True}}
def create(self, validated_data):
user = User(
username=validated_data['username'],
email=validated_data['email']
)
user.set_password(validated_data['password'])
user.save()
return user
views.py:
from rest_framework import generics
from serializers.py import AccountCreateSerializer
class AccountCreateAPIView(generics.CreateAPIView):
serializer_class = AccountCreateSerializer
Had implemented a basic authentication system using function based views in django.
Trying to upgrade it to class based views.
Creating a UserProfile by inheriting from a django User model.
Need to serialize UserProfile and return to client side
User model :
from django.contrib.auth.models import User
UserProfile model :
class UserProfile(models.Model):
id = models.AutoField(primary_key=True)
user = models.OneToOneField(User)
profile_picture = models.ImageField(upload_to='documents', blank=True)
def __str__(self):
return self.user.username
UserSerializer:
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = ('username','password', 'first_name', 'last_name', 'email',)
write_only_fields = ('password',)
read_only_fields = ('is_staff', 'is_superuser', 'is_active', 'date_joined',)
def restore_object(self, attrs, instance=None):
user = super(UserSerializer, self).restore_object(attrs, instance)
user.set_password(attrs['password'])
return user
UserProfileSerializer:
class UserProfileSerializer(serializers.ModelSerializer):
user = UserSerializer()
class Meta:
model = UserProfile
fields = ('id','user','profile_picture',)
views.py:
class AuthView(APIView):
authentication_classes = (BasicAuthentication,)
def post(self, request, *args, **kwargs):
login(request, request.user)
content={ 'user':UserProfileSerializer(request.user).data,'token':csrf.get_token(request)}
return Response(content)
UserProfileSerializer(request.user).data in views.py is not working.
but instead if i use:
UserSerializer(request.user).data, it gives me result(as expected) :
{'first_name': '', 'username': 'admin', 'email': 'a#a.com', 'last_name': '', 'password': 'pbkdf2_'}
But i also want additional attributes to the user also serialized like profile_picture, hence something like
UserProfileSerializer(request.user).data
should work for me.
Questions:
Is it possible to serialize a model containing FileField ?
How to serialize a nested object and return its data ?
Kinda beginner here.
yes it is possible to serialize a FileField. The problem is that your profile serializer needs a UserProfile model and not a User model. Try this:
content={ 'user':UserProfileSerializer(request.user.user_profile).data,'token':csrf.get_token(request)}