Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Combining serializer and model functions

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', '')
    }
like image 794
ambe5960 Avatar asked Jul 11 '19 04:07

ambe5960


People also ask

What is the difference between serializer and model serializer?

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.

Is it necessary to use Serializers in Django?

If you work with Django rest API. So serializer is a good option to convert data into JSON format. If you don't want to use a serializer you can use Django form rather than serializer.

When would you use a serializer?

Serialization is the process of transforming data into a format that can be stored or transmitted and then reconstructing it. It's used all the time when developing applications or storing data in databases, in memory, or converting it into files.

What does serializer Is_valid do?

is_valid perform validation of input data and confirm that this data contain all required fields and all fields have correct types. If validation process succeded is_valid set validated_data dictionary which is used for creation or updating data in DB.


1 Answers

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.

like image 105
yofee Avatar answered Oct 14 '22 06:10

yofee