I am using the default User model and am also extending it with a UserExtended model:
class Country(models.Model):
countryName = models.CharField(max_length=50, unique=True)
countryCode = models.CharField(max_length=10, unique=True)
class UserExtended(models.Model):
user = models.OneToOneField(User, related_name="userextended")
country = models.ForeignKey(Country)
I am trying to follow what is documented here: http://www.django-rest-framework.org/api-guide/relations/#reverse-relations
This is my UserSerializer:
class UserSerializer(serializers.ModelSerializer):
def __init__(self, *args, **kwargs):
super(UserSerializer, self).__init__(*args, **kwargs) # call the super()
for field in self.fields: # iterate over the serializer fields
self.fields[field].error_messages['required'] = 'Enter a valid %s.'%field # set the custom error message
class Meta:
model = User
fields = ('username', 'password', 'email', 'userextended')
extra_kwargs = {
'password': {
'write_only': True,
}
}
def create(self, validated_data):
user = User.objects.create_user(
email = validated_data['email'],
username = validated_data['username'],
password = validated_data['password'],
)
return user
My issue is, if the end user does not fill out the "Country" section of the form before submitting it, Django sends an error message to the front end saying "Enter a valid userextended". "userextended" is the name of the reverse relationship, and every user object is linked to a userextended object and vise-versa. "userextended" is mandatory, but the end user does not have to specify a "userextended" field when creating a user object because that is already a given (the moment the end user creates a user object, the user object will have a reverse relationship with a UserExtended object by default).
The end user has to fill out a "Country" section in the form because Country is what is required from the end user. With that said, how do I get Django to say "Enter a valid Country" rather than "Enter a valid userextended"?
If the end user successfully saves a user object, and submits "Canada" in the "Country" section in the form, how does DRF know to save "Canada" as the country? Because currently, it looks like DRF thinks the "Country" section in the form refers to the "userextended" reverse relationship field.
What I'd expect is, in the "fields" array for the user serializer, I use dot notation? Something like this?:
fields = ('username', 'password', 'email', 'userextended.country')
Edit: I just created a UserExtended serializer as well, like so:
class UserExtendedSerializer(serializers.ModelSerializer):
class Meta:
model = UserExtended
fields = ('country')
but I don't know how to "merge" this serializer with the original UserSerializer.
In function-based views, we can pass extra context to serializer with “context” parameter with a dictionary. To access the extra context data inside the serializer we can simply access it with “self. context”. From example, to get “exclude_email_list” we just used code 'exclude_email_list = self.
The ModelSerializer class is the same as a regular Serializer class, except that: It will automatically generate a set of fields for you, based on the model. It will automatically generate validators for the serializer, such as unique_together validators. It includes simple default implementations of .
HyperlinkedModelSerializer is a layer of abstraction over the default serializer that allows to quickly create a serializer for a model in Django. Django REST Framework is a wrapper over default Django Framework, basically used to create APIs of various kinds.
Solution given by Igor works only when you want to fetch the details of users because of read_only field. Serializer doesn't support nested write by default. To write a nested object you should override the create method of UserSerializer.
class UserSerializer(serializers.ModelSerializer):
def __init__(self, *args, **kwargs):
super(UserSerializer, self).__init__(*args, **kwargs) # call the super()
for field in self.fields: # iterate over the serializer fields
self.fields[field].error_messages['required'] = 'Enter a valid %s.'%field # set the custom error message
country = serializers.RelatedField(source='userextended.country')
class Meta:
model = User
fields = ('username', 'password', 'email', 'country')
extra_kwargs = {
'password': {
'write_only': True,
}
}
def create(self, validated_data):
user = User.objects.create_user(
email = validated_data['email'],
username = validated_data['username'],
password = validated_data['password'],
)
country=Country.objects.get(pk=validated_data['country'])
UserExtended.objects.create(user=user, country=country)
return user
Data to send when creating:
{'username':'sachin', 'email': '[email protected]', 'password': 'abc', 'country':2}
You should do the next:
userextended
field.Something like this:
class UserExtendedSerializer(serializers.ModelSerializer):
# define serializer here...
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = ('username', 'password', 'email', 'userextended')
userextended = UserExtendedSerializer(read_only=True)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With