Ozgur Akcali
Ozgur Akcali

Reputation: 5482

DRF Serializer readable - writeable non-model field

On a project with Django / DRF; I have the following model structure:

class City(models.Model):
    name = models.CharField(max_length=100)

class Company(models.Model):
    city = models.ForeignKey(City)
    .
    .

And following serializer structure for Company model:

class CompanySerializer(serializers.ModelSerializer):    
    city_name = serializers.CharField(write_only=True)
    .
    .

    class Meta:
        model = Company
        fields = ('city_name',)

    def create(self, validated_data):

        # Get city
        city_name = validated_data.pop('city_name')
        try: 
            city = City.objects.get(name__iexact=city_name)
        except City.DoesNotExist:
            city = City.objects.create(name=city_name.title())

        company = Company.objects.create(city=city, **validated_data)

        return company

While creating a company through the serializer, user provides a city_name, I create a new city with that name if not exists or use an existing entry if exists. In this structure, I want to be able to return city_name field while returning companies. It is not a field on the model, so I could use SerializerMethodField normally, but I also want this field to be writable as well. Do I have any options here?

Upvotes: 5

Views: 1498

Answers (2)

Sabyasachi
Sabyasachi

Reputation: 1554

A better approach is to create two serializer

class CitySerializer(serializers.ModelSerializer):
    class Meta:
        model = City
        fields = ('name')

class CompanySerializer(serializers.ModelSerializer):
    city = CitySerializer(write_only=True)

    class Meta:
        model = Company
        fields = ('city',)

    def create(self, validated_data):

        # Get city
        city = validated_data.pop('city')
        try:
            city = City.objects.get(name__iexact=city)
        except City.DoesNotExist:
            city = City.objects.create(name=city.title())

        company = Company.objects.create(city=city, **validated_data)

        return company

Upvotes: 0

user8060120
user8060120

Reputation:

i think, your solution is simple to add source and remove write_only:

city_name = serializers.CharField(source='city.name')

After changing to this approach, you can get city name in create or update methods as follows:

city_data = validated_data.pop('city')
city_name = city_data.get('name')

Upvotes: 1

Related Questions