models.py
class UserProfile(models.Model):
contact_no = models.CharField(max_length=20, name='contact_no')
token_key = models.CharField(max_length=128, blank=True, null=True)
user = models.OneToOneField(User, on_delete=models.CASCADE)
role = models.CharField(max_length=128, blank=True, null=True, name='role')
class Meta:
db_table = 'user_profile'
serializers.py
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = ('id', 'first_name', 'last_name', 'email', 'password',)
extra_kwargs = {'password': {'write_only': True}}
class UserProfileSerializer(serializers.ModelSerializer):
user = UserSerializer(required=True)
class Meta:
model = UserProfile
fields = ('user', 'contact_no', 'role',)
def create(self, validated_data):
"""
Overriding the default create method of the Model serializer.
:param validated_data: data containing all the details of profile
:return: returns a successfully created profile record
"""
user_data = validated_data.pop('user')
user = UserSerializer.create(UserSerializer(),validated_data=user_data)
profile, created = UserProfile.objects.update_or_create(user=user, contact_no=validated_data.pop('contact_no'),
role=validated_data.pop('role'))
return profile
views.py
class UserRecordsView(APIView):
"""
A class based view for creating and fetching profile records
"""
def get(self, request):
"""
Get all the student records
:param format: Format of the profile records to return to
:return: Returns a list of profile records
"""
profiles = UserProfile.objects.all()
serializer_context = {
'request': request,
}
serializer = UserProfileSerializer(profiles, many=True, context=serializer_context)
return Response(serializer.data)
def post(self, request):
"""
:User and User Profile Creation .
:param request:
:return:
"""
serializer = UserProfileSerializer(data=request.data)
if serializer.is_valid(raise_exception=ValueError):
serializer.create(validated_data=request.data)
return Response(serializer.data, status=status.HTTP_201_CREATED)
return Response(serializer.error_messages,
status=status.HTTP_400_BAD_REQUEST)
Here password is in the form of text ,i want encrypted form of password.here one to one relation is there between user and userprofile table.i want to create user and userprofile data by only one method, that's why i need to encrypt password also at the same time only.
I got the answer.
class UserProfileSerializer(serializers.ModelSerializer):
user = UserSerializer(required=True)
class Meta:
model = UserProfile
fields = ('user', 'contact_no', 'role',)
def create(self, validated_data):
"""
Overriding the default create method of the Model serializer.
:param validated_data: data containing all the details of profile
:return: returns a successfully created profile record
"""
user_data = validated_data.pop('user')
user = UserSerializer.create(UserSerializer(),validated_data=user_data)
user.set_password(user.password)
user.save()
profile, created = UserProfile.objects.update_or_create(user=user, contact_no=validated_data.pop('contact_no'),
role=validated_data.pop('role'))
return profile
we need to add only two lines to get the encrypted password here.
user.set_password(user.password)
user.save()
Related
I have multiple users and I designed two models for two users and the rest is super user.
And I have the model User that holds common data for all users.
I want to save the patient post request to two different models: User and Patient; I tried these codes but, didn't work.
This is my Signup view
class PatientSignupView(generics.GenericAPIView):
serializer_class=PatientSignupSerializer
permission_classes = [
permissions.AllowAny
]
def post(self, request, *args, **kwargs):
user_serializer=self.get_serializer(data=request.data)
user_serializer.is_valid(raise_exception=True)
user=user_serializer.save()
return Response({
"user":UserSerializer(user, context=self.get_serializer_context()).data,
"patient":PatientSerializer(patient, context=self.get_serializer_context()).data,
"token":Token.objects.get(user=user).key,
"message":"account created successfully",
})
And here is my Signup Serializer class
class PatientSignupSerializer(serializers.ModelSerializer):
password_confirm = serializers.CharField(style={"input_type":"password"}, write_only=True)
class Meta:
model = User
fields = ['username', 'email', 'is_doctor', 'is_patient', 'password',
'password_confirm']
extra_fields = {
'password': {'write_only': True},
}
def save(self, **kwargs):
user=User(
username=self.validated_data['username'],
email=self.validated_data['email']
)
password=self.validated_data['password']
password_confirm=self.validated_data['password_confirm']
if password !=password_confirm:
raise serializers.ValidationError({"error":"password do not match"})
user.set_password(password)
user.is_patient=True
user.is_doctor=False
user.save()
PatientSerializer.serialized_data(user)
return user
Here is the PatientSerializer and UserSerializer class
from rest_framework import serializers
from .models import Patient, User
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = ['username','email','is_doctor','is_patient']
class PatientSerializer(serializers.ModelSerializer):
class Meta:
model = Patient
fields = ['first_name', 'middle_name', 'last_name', 'address', 'phone_number', 'birth_date', 'gender']
def serialized_data(self, user, **kwargs):
patient = Patient.objects.create(
user = user,
first_name=self.validated_data['first_name'],
middle_name = self.validated_data['middle_name'],
last_name = self.validated_data['last_name'],
address = self.validated_data['address'],
phone_number = self.validated_data['phone_number'],
birth_date = self.validated_data['birthh_date'],
gender = self.validated_data['gender']
)
return patient
Thank you!
It is solved like this
The signup view is:
class PatientSignupView(generics.GenericAPIView):
serializer_class=PatientSignupSerializer
def post(self, request, *args, **kwargs):
user_serializer=self.get_serializer(data=request.data)
user_serializer.is_valid(raise_exception=True)
user=user_serializer.save()
return Response({
"user":UserSerializer(user, context=self.get_serializer_context()).data,
"token":Token.objects.get(user=user).key,
"message":"account created successfully",
})
The serializer class will looks like:
class PatientSignupSerializer(serializers.ModelSerializer):
password_confirm = serializers.CharField(style={"input_type":"password"}, write_only=True)
first_name = serializers.CharField()
middle_name = serializers.CharField()
last_name = serializers.CharField()
address = serializers.CharField()
phone_number= serializers.CharField()
birth_date = serializers.DateTimeField()
gender = serializers.CharField()
class Meta:
model = User
fields = '__all__'
extra_fields = {'password': {'write_only': True},}
def save(self, **kwargs):
user=User(
username=self.validated_data['username'],
email=self.validated_data['email']
)
password=self.validated_data['password']
password_confirm=self.validated_data['password_confirm']
if password !=password_confirm:
raise serializers.ValidationError({"error":"password do not match"})
user.set_password(password)
user.is_patient=True
user.is_doctor=False
user.save()
Patient.objects.create(user=user,
first_name=self.validated_data['first_name'],
middle_name=self.validated_data['middle_name'],
last_name=self.validated_data['last_name'],
address=self.validated_data['address'],
phone_number=self.validated_data['phone_number'],
birth_date=self.validated_data['birth_date'],
gender=self.validated_data['gender'])
return user
In my project I have created a custom User object with a one to one relation to a Profile object in order to isolate authentication fields.
Profile
class Profile(models.Model):
first_name = models.CharField(max_length=50)
last_name = models.CharField(max_length=50)
image = models.ImageField(default='/user_images/default.png', upload_to='user_images', blank=True, null=True)
def __str__(self):
return self.first_name + " " + self.last_name
User
class User(AbstractBaseUser, PermissionsMixin):
email = models.EmailField(unique=True)
profile = models.OneToOneField(Profile, related_name="user" ,on_delete=models.CASCADE, default=None, blank=True, null=True)
is_visible = models.BooleanField(default=True)
is_staff = models.BooleanField(default=False)
is_active = models.BooleanField(default=True)
date_joined = models.DateTimeField(default=timezone.now)
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = []
objects = CustomUserManager()
def __str__(self):
return self.email
My problem now is that i want to create the Profile object with the same request of the User object
View
class CustomView(APIView):
permission_classes = (permissions.AllowAny,)
def post(self, request, format='json'):
serializer = CustomSerializer(data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status=status.HTTP_201_CREATED)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
Serializer
class CustomSerializer(serializers.Serializer):
# User
email = serializers.EmailField(required=True)
password = serializers.CharField(min_length=8, write_only=True)
# Profile
first_name = serializers.CharField(max_length=50)
last_name = serializers.CharField(max_length=50)
image = serializers.ImageField(allow_null=True, max_length=100, required=False)
def create(self, validated_data):
profile = Profile.objects.create(
first_name = validated_data['first_name'],
last_name = validated_data['first_name'],
image = validated_data['image'],
)
user = User.objects.create(
email = validated_data['email'],
profile = profile
)
user.set_password(validated_data['password'])
user.save()
return user
Now in the database everything is created correctly but i receive this error
Got AttributeError when attempting to get a value for field
first_name on serializer CustomSerializer. The serializer field
might be named incorrectly and not match any attribute or key on the
User instance. Original exception text was: 'User' object has no
attribute 'first_name'.
I suppose this means that a serializer can only handle the creation of one model so i'm supposed to handle my case?
Thanks
I assume that your error comes from to_representation() and what you can do is to set write_only=True on first_name, last_name and image fields like this:
first_name = serializers.CharField(max_length=50, write_only=True)
However, a more clean solution would be to use ModelSerialzier for both User and Profile models. If you do so, you'll have something like:
class ProfileSerializer(serializers.ModelSerializer):
class Meta:
model = Profile
fields = ("id", "first_name", "last_name", "image")
class UserSerializer(serializers.ModelSerializer):
profile = ProfileSerializer()
class Meta:
model = User
fields = ("id", "email", "profile", [...])
def create(self, validated_data):
...
i extending a user model and creating a serializer that can register a user but i think i have a problem with the Register serializer
i have tried changing the input but i cant tell where the problem is
class Register(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
address = models.CharField(max_length=70)
phone = models.IntegerField()
register_as = models.CharField(max_length=20)
# register serializer
class RegisterSerializer(serializers.ModelSerializer):
model = Register
fields = ('id', 'username', 'email', 'address', 'phone', 'register_as', 'password')
extra_kwargs = {'password': {'write_only':True}}
def create(self, validated_data):
user = User.objects.create_user(validated_data['username'], validated_data['email'], validated_data['password'])
return user
#register API
class RegisterAPI(generics.GenericAPIView):
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()
return Response({
'user': UserSerializer(user,
context=self.get_serializer_context()).data,
'token': AuthToken.objects.create(user)[1]
})
i expect it to return the fields in the user model plus the ones i added in the model
Models.py
class CustomTarget(models.Model):
target_red = models.CharField(max_length=64, blank=True, null=True)
target_amber = models.CharField(max_length=64, blank=True, null=True)
target_green = models.CharField(max_length=64, blank=True, null=True)
remarks = models.CharField(max_length=256, blank=True, null=True)
flag = models.BooleanField(default=False)
user = models.ForeignKey(User, on_delete=models.CASCADE)
project = models.ForeignKey(ProjectsMaster, on_delete=models.CASCADE)
metric = models.ForeignKey(MetricsMaster, on_delete=models.CASCADE)
class Meta:
db_table = 'custom_target'
unique_together = (('user', 'project', 'metric'),)
Serializers.py
class CustomTargetSerializer(serializers.ModelSerializer):
"""
"""
logger.info("Control entered into CustomTargetSerializer class")
class Meta:
model = CustomTarget
fields = ('id', 'target_red', 'flag', 'user', 'project', 'target_amber', 'target_green','remarks', 'metric')
def create(self, validated_data):
"""
:param validated_data:
:return:
"""
data = CustomTarget(target_red=validated_data["target_red"],
user=User(validated_data["user"]),
project=ProjectsMaster(validated_data["project"]),
target_amber=validated_data["target_amber"],
target_green=validated_data["target_green"],
remarks=validated_data["remarks"],
metric=MetricsMaster(validated_data["metric"]),
flag=True, )
data.save()
return data
views.py
#api_view(["PUT"])
#renderer_classes((JSONRenderer,))
def custom_target(request):
"""
To add new data and update existing data in custom_target table.
:param request:
:return:
"""
logger.info("Control entered into custom_target")
return_dict = dict()
try:
metric_data = request.data
metric_config_obj = matrix_config_filter(metric_data)
if metric_config_obj.exists() is True:
if metric_config_obj[0].flag is True:
custom_serializer = CustomTargetSerializer(data=request.data)
custom_tar_obj = CustomTarget.objects.filter(metric=request.data['metric'])
if custom_tar_obj.exists():
custom_serializer.update(validated_data=request.data, instance=custom_tar_obj)
else:
if custom_serializer.is_valid(raise_exception=ValueError):
custom_serializer.create(validated_data=request.data)
return_dict["msg"] = "success"
status_msg = status.HTTP_200_OK
except Exception as e:
logger.error("Error from custom_target: %s" % e)
return_dict["msg"] = "failed"
status_msg = status.HTTP_400_BAD_REQUEST
return Response(return_dict, status=status_msg)
here,now i am giving hard coded user id,but i want to save user id of the login user in the create() of Serializer.
here user is saved in auth_user table and have foreign key relation with Custom_target table.
I tried so many things but i am not getting the request.user in Serializer.
You could use PrimaryKeyRelatedField along with CurrentUserDefault as
class CustomTargetSerializer(serializers.ModelSerializer):
user = serializers.PrimaryKeyRelatedField(queryset=User.objects.all(), default=serializers.CurrentUserDefault())
# your code
UPDATE-1 : Complete Serializer
class CustomTargetSerializer(serializers.ModelSerializer):
user = serializers.PrimaryKeyRelatedField(queryset=User.objects.all(), default=serializers.CurrentUserDefault())
class Meta:
model = CustomTarget
fields = ('id', 'target_red', 'flag', 'user', 'project', 'target_amber', 'target_green', 'remarks', 'metric')
def create(self, validated_data):
user = validated_data.pop('user')
project = validated_data.po('project')
metric = validated_data.pop('metric')
instance = CustomTarget.objects.create(
user=user,
project=project,
metric=metric,
**validated_data
)
return instance
I'm trying to create an object (called Post) in DRF where one of the fields is user, which should represent the user that created the object. I'm using Token-authentication, and I want to make sure that the request.user matches the user passed to the object. However, I'm using HyperLinkedModelSerializers so I pass the url of the user to the PostSerializer.
How do I get the url of the request.user? Do I have to create a url field in my user?
Here's the serializer classes:
class UserSerializer(serializers.HyperlinkedModelSerializer):
User = get_user_model()
password = serializers.CharField(write_only=True)
class Meta:
model = User
fields = ('username', 'password')
def create(self, validated_data):
user = User.objects.create_user(**validated_data)
return user
class PostSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = Post
fields = ('id', 'user', 'caption', 'video_link')
def create(self, validated_data):
return Post(**validated_data)
and here's the viewset
class PostViewSet(viewsets.ModelViewSet):
serializer_class = PostSerializer
queryset = Post.objects.all()
permission_classes = (IsAuthenticated, IsOwnerOrReadOnly)
If the user logged in system, you can rewrite PostSerializer like following:
class PostSerializer(serializers.ModelSerializer):
class Meta:
model = Post
fields = ('caption', 'video_link')
def create(self, validated_data):
post = Post(user=self.request.user, caption=validated_data['caption'], video_link=validated_data['video_link'])
post.save()
return validated_data