I needed to extend User model to add things like address, score, more user_types, etc. There are 2 possible ways to achieve that, extend the User model or create a new model that will be connected with the target User with OneToOneField
. I decided to go with a new model because It seemed easier and It is recommended in this stack overflow question. But now I cannot create Serializer without nested profile field which is moreover undocumented because default rest_framwork documentation generator cannot generate documentation for nested serializers.
My UserSerializer
looks like this:
class UserSerializer(serializers.ModelSerializer):
# This creates a nested profile field
profile = ProfileSerializer(required=True)
def create(self, validated_data):
profile_data = validated_data.pop('profile')
user = User.objects.create_user(**validate_data)
profile, created = Profile.objects.upodate_or_creeate(user=user, defaults=profile_data)
return user
class Meta:
model = User
fields = ('id', 'username', 'email', 'password', 'buckelists', 'profile')
read_only_fields = ('id',)
extra_kwargs = {'password':{'write_only': True}}
This Serializer takes following JSON format:
{
'name': ...,
'email': ...,
'password': ...,
'profile': {
'address': ...,
'score': ...,
'user_type': ...,
'achievements': ...,
'country': ...,
'trusted': ...,
}
This looks weird and documentation generated with rest_framework.documentation.include_docs_urls
shows just following:
{
'username': ...,
'email': ...,
'password': ...,
'field': ...,
}
So it's not clear what should be included in the profile field. I'd like to create Serializer that would accepted following format:
{
'name': ...,
'email': ...,
'password': ...,
'address': ...,
'score': ...,
'user_type': ...,
'achievements': ...,
'country': ...,
'trusted': ...,
}
Is it possible without creating custom Serializer from scratch? Or at least is it possible to generate documentation for nested serializers.
PS: I use python3.6 and Django 2.1
EDIT: Here is a relevant part of my models.py:
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
trusted = models.BooleanField(default=False)
address = models.CharField(max_length=100, default="")
COUNTRIES = (
('CZ', 'Czech Republic'),
('EN', 'England'),
)
country = models.CharField(max_length=2, choices=COUNTRIES, default="CZ")
score = models.BigIntegerField(default=0)
achievements = models.ManyToManyField(Achievement, blank=True)
USER_TYPES = (
('N', 'Normal'),
('C', 'Contributor'),
('A', 'Admin'),
)
user_type = models.CharField(max_length=1, choices=USER_TYPES, default='N')
@receiver(post_save, sender=settings.AUTH_USER_MODEL)
def create_auth_token(sender, instance=None, created=False, **kwargs):
if created:
Token.objects.create(user=instance)
@receiver(post_save, sender=User)
def create_user_profile(sender, instance, created=False, **kwargs):
if created:
profile, created = Profile.objects.get_or_create(user=instance)
profile.save()
EDIT:
Mohammad Ali's answers solves this for GET, but I'd also like to use POST, UPDATE and PATCH methods. I have found that I have to use source
parameter but this is relative to serializer I don't know how to reference profile wihtout having profile field.