7

I have two serializers... MyRegisterSerializer inherits and extends a popular app/package, django-rest-auth, which connects to a fairly standard user table. I also have a Model and serializer for a custom app, TeamSerializer (a one-to-many relationship with users). When a user signs up, I would like them to be able to join a team at the same time, so I somehow need to create a team, return the team ID and then pass that ID to the RegisterSerializer, so that the ID of the team can be stored in the User table. I know I could make two calls, first to create the team and return the value, and then pass it to the register serializer, but is there a way to do this all in one serializer? I am a n00b at python, and cant find a great example of this, considering I have to return the get_cleaned_data() function as it is. Thank you!

class TeamSerializer(serializers.ModelSerializer):

  class Meta:
    model = Team
    fields = ('id', 'name', 'logo', 'user')

class MyRegisterSerializer(RegisterSerializer):
  first_name = serializers.CharField()
  last_name = serializers.CharField()

  def get_cleaned_data(self):
    super(MyRegisterSerializer, self).get_cleaned_data()
    return {
        'team_id': <How do I get this value>
        'username': self.validated_data.get('username', ''),
        'position': self.validated_data.get('password1', ''),
        'email': self.validated_data.get('email', ''),
        'first_name': self.validated_data.get('first_name', ''),
        'last_name': self.validated_data.get('last_name', '')
    }
ambe5960
  • 1,870
  • 2
  • 19
  • 47

1 Answers1

5

It depends on how you want to create the team:

1. The team is created by some other information:

You should be able to use this custom field:

from rest_framework.relations import PrimaryKeyRelatedField

class TeamPrimaryKeyRelatedField(PrimaryKeyRelatedField):
    def to_internal_value(self, data):
        if self.pk_field is not None:
            data = self.pk_field.to_internal_value(data)
        try:
            obj, created = self.get_queryset().get_or_create(
                pk=data,
                defaults=get_team_data(),
            )
            return obj
        except (TypeError, ValueError):
            self.fail('incorrect_type', data_type=type(data).__name__)

And use it in your Serializer:

class MyRegisterSerializer(RegisterSerializer):
    team = TeamPrimaryKeyRelatedField()
    # ...

2. Use extra user input to create the team:

This looks like a perfect use case for writable nested serializers:

class TeamSerializer(serializers.ModelSerializer):
    class Meta:
        model = Team
        fields = ('id', 'name', 'logo', 'user')

class MyRegisterSerializer(RegisterSerializer):
  first_name = serializers.CharField()
  last_name = serializers.CharField()
  team = TeamSerializer()

    def create(self, validated_data):
        team_data = validated_data.pop('team')
        # You could do this if the user is not necessary in the team object:
        team = Team.objects.create(**team_data)
        user = super().create(team=team, **validated_data)

        # Otherwise:
        user = super().create(**validated_data)
        # Should this be a many-to-many relationship?
        team = Team.objects.create(user=user, **team_data)
        # I don't know if this works/you need it:
        self.team = team
        # Or it should be like this?
        self.validated_data['team'] = team
        return user

I'm not sure what exactly you need. Let me know if you need further help.

yofee
  • 1,287
  • 12
  • 25
  • 1
    My answer would have looked very similar to your second approach, I believe that is what the OP was looking for. – A. J. Parr Jul 19 '19 at 01:37