Unable to add a new customer to the database.. I made a class Named customer that has a one-to-one relationship with a class named User that is an AbstractUser
I want to send the data through rest API so that I can create a new customer in the customer table and a new user that is One To One Related to the customer from the same view. User Model
class User(AbstractUser):
# Add additional fields here
id = None
email = models.EmailField(max_length=254, primary_key=True)
name = models.CharField(max_length=100)
password = models.CharField(max_length=100)
is_patient = models.BooleanField(default=False)
is_doctor = models.BooleanField(default=False)
is_homesampler = models.BooleanField(default=False)
is_pathologist = models.BooleanField(default=False)
is_admin = models.BooleanField(default=False)
is_staff = models.BooleanField(default=False)
is_active = models.BooleanField(default=False)
date_joined = models.DateTimeField(auto_now_add=True)
last_login = models.DateTimeField(auto_now=True)
first_name = None
last_name = None
username = None
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = ['name', 'password']
objects = CustomUserManager()
def __str__(self):
return self.email
# Ensure that the password is hashed before saving it to the database
def save(self, *args, **kwargs):
self.password = make_password(self.password)
super(User, self).save(*args, **kwargs)
def has_perm(self, perm, obj=None):
return self.is_superuser
User Serializer
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = get_user_model()
# fields = (['id', 'username', 'email', 'name'])
fields = '__all__'
customer Model
class customer(models.Model):
user = models.OneToOneField(
get_user_model(), on_delete=models.CASCADE, primary_key=True)
real = models.BooleanField(default=False)
def __str__(self):
return self.user.name
Customer Serializer
class CustomerSerializer(serializers.ModelSerializer):
userdata = UserSerializer(read_only=True, source='user')
class Meta:
model = customer
fields = '__all__'
def create(self, validated_data):
user_data = validated_data.pop('user')
user = get_user_model().objects.create(**user_data)
user.is_Patient = True
customer = customer.objects.create(user=user, **validated_data)
return customer
Create Customer View
# Create add customer API
@api_view(['POST'])
def addCustomer(request):
customer_serializer = CustomerSerializer(data=request.data)
if(customer_serializer.is_valid()):
customer_serializer.save()
print(customer_serializer.errors)
return Response({'message': 'okay'})
Body of API Call
{
"email" : "[email protected]",
"password": "Abc"
}
So the question is how can I create a view so that I can create a new user and a customer using just one API Call
CodePudding user response:
Your call body doesn't match CustomerSerializer.
CustomerSerializer fields are "user" and "rest", so you only can pass these two unless you do something like these:
class CustomerSerializer(serializers.ModelSerializer):
userdata = UserSerializer(read_only=True, source='user')
email = serializers.EmailField(write_only=True)
password = serializers.CharField(write_only=True)
class Meta:
model = customer
fields = ["userdata", "email", "password", "id", "real"]
def create(self, validated_data):
email = validated_data.pop("email")
password = validated_data.pop("password")
user = get_user_model().objects.create(**{
"email": email,
"password": password
})
user.is_Patient = True
customer = customer.objects.create(user=user, **validated_data)
return customer
About the create method, it won't function correctly:
Because:
- We shouldn't use
createto create a new user instead we should usecreate_userMore - I noticed that you removed the username so this method would be useless :)
- After
user.is_Patient = True, you forgot to save the user
The correct code would be:
class CustomerSerializer(serializers.ModelSerializer):
userdata = UserSerializer(read_only=True, source='user')
email = serializers.EmailField(write_only=True)
password = serializers.CharField(write_only=True)
class Meta:
model = customer
fields = ["userdata", "email", "password", "id", "real"]
def create(self, validated_data):
email = validated_data.pop("email")
password = validated_data.pop("password")
user = get_user_model().objects.create(email=email)
user.set_password(password)
user.is_Patient = True
user.save()
customer = customer.objects.create(user=user, **validated_data)
return customer
NOTE 1:
# Ensure that the password is hashed before saving it to the database
def save(self, *args, **kwargs):
self.password = make_password(self.password)
super(User, self).save(*args, **kwargs)
It is the wrong approach to make_password here because whenever you make a change in your user, it would run.
the ideal approach would be using user.set_password("new_pass") whenever you get a new password from the user.
NOTE 2:
When you pass read_only to a serializer, this means would be ignored if you passed it as data to the serializer.
About write_only, it's the opposite of read_only. It would not be returned if you called serializer.data. For example, we only want to write to the password, and we won't want to read it from the serializer, so we made it write_only.
