I Have a UserModelSerializer:
class UserModelSerializer(ModelSerializer):
class Meta:
model = User
fields = ['id', 'username', 'email', 'date_joined', 'is_active', 'is_verified', 'is_superuser', 'is_staff', 'is_hidden', 'created_date']
read_only_fields = ['id', 'date_joined', 'is_active', 'is_verified', 'is_superuser', 'is_staff', 'is_hidden', 'created_date']
and a UserBanModelSerializer:
class UserBanModelSerializer(ModelSerializer):
user = UserModelSerializer()
class Meta:
model = UserBan
fields = ['id', 'user', 'until', 'reason', 'description', 'created_date']
read_only_fields = ['id', 'created_date']
def create(self, validated_data):
user_data = validated_data.pop('user')
user, created = User.objects.get_or_create(**user_data)
user_ban = UserBan.objects.create(user=user, **validated_data)
return user_ban
I want my representation to have complete User data and also i want the frontend developer to be able to send the represented data back to server without any problem(if I only add UserModelSerialzer to to_representation method of UserBanModelSerializer frontend developer needs to send user id instead of the whole user data
But when I use is_valid method on serializer I get this exceptions:
"username": [
"A user with that username already exists."
],
"email": [
"A user with that email already exists."
]
and I'm aware that I can remove validators from username and email like this:
extra_kwargs = {
'email': {'validators': []},
'username': {'validators': []},
}
but I dont want to remove validators form username and let the database decide to unique constraint
I dont want to create a User when I want to create a UserBan I only want it to be created if the User is not found
I ended up using this style which suites my needs
class UserModelSerializer(ModelSerializer):
class Meta:
model = User
fields = ['id', 'username', 'email', 'date_joined', 'is_active', 'is_verified', 'is_superuser', 'is_staff', 'is_hidden', 'created_date']
read_only_fields = ['id', 'date_joined', 'is_active', 'is_verified', 'is_superuser', 'is_staff', 'is_hidden', 'created_date']
class UserBanModelSerializer(ModelSerializer):
user = UserModelSerializer(read_only=True)
class Meta:
model = UserBan
fields = ['id', 'user', 'until', 'reason', 'description', 'created_date']
read_only_fields = ['id', 'created_date']
def create(self, validated_data):
user_data = self.initial_data.pop('user')
user, created = User.objects.get_or_create(**user_data)
response = UserBan.objects.create(user=user, **validated_data)
return response
Reponse has serialized data of user and the passed data to create method also has the the same data and then user is created or get from the database
For more robust way you can alternatively use this style:
class UserBanModelSerializer(ModelSerializer):
user = UserModelSerializer(read_only=True)
class Meta:
model = UserBan
fields = ['id', 'user', 'until', 'reason', 'description', 'created_date']
read_only_fields = ['id', 'created_date']
def create(self, validated_data):
user_data = self.initial_data.pop('user')
try:
user = User.objects.get(id=user_data.get('id'))
except User.DoesNotExist:
raise EntityNotFoundException(message='User not Found!')
response = UserBan.objects.create(user=user, **validated_data)
return response
which incorrect user id results in an exception.