I am dealing with Django Rest Framework project and the generic response for my view is not what the app client expects.
The app client expects that the filed of the related models, appears as they are in the database. Example given: model City has a foreign key to Country model, represented by a country_id column.
Is there any option to "map" the serializers default fields into a custom one? I have check the Django Rest Framework documentation but I only found "serializer_field_mapping" but I don't know if it will fit my requirements and also I don't know how to use it.
Somehow I got a close approach of it, but only in the case for fetching data --creating / updating threw some errors that I did not get how to manage. :(
Bellow I attach my models.py file, plus the actual output and the desired output. Also, if it is possible, I would like to retrieve data related with Country / Region if exists combined with the database column field_id names.
Thanks in advance,
models.py
from django.db import models
from django.contrib.postgres.fields import ArrayField
class Country(models.Model):
name = models.CharField(max_length=150, unique=True, blank=False)
class Meta:
db_table = 'countries'
class Region(models.Model):
name = models.CharField(max_length=150, unique=True, blank=False)
code = models.CharField(max_length=150, blank=True)
class Meta:
db_table = 'regions'
class City(models.Model):
country = models.ForeignKey(Country)
region = models.ForeignKey(Region, null=True, blank=True, default=None)
name = models.CharField(max_length=150, unique=True, blank=False)
postal_codes = ArrayField(models.CharField(max_length=12, blank=True), null=True, blank=True, default=None)
def __str__(self):
if not self.region:
return '%s (%s)' % (self.name, self.country.name)
return '%s, %s (%s)' % (self.name, self.region.name, self.country.name)
class Meta:
db_table = 'cities'
Actual Output:
[
{
"id": 1,
"name": "San Francisco",
"postal_codes": null,
"country": 1,
"region": 1
},
{
"id": 2,
"name": "Palo Alto",
"postal_codes": null,
"country": 1,
"region": 1
},
{
"id": 3,
"name": "New York City",
"postal_codes": null,
"country": 1,
"region": 2
},
{
"id": 4,
"name": "London",
"postal_codes": null,
"country": 2,
"region": null
}
]
Desired Output:
[
{
"id": 1,
"country_id": 1,
"region_id": 1,
"name": "San Francisco",
"postal_codes": null
},
{
"id": 2,
"country_id": 1,
"region_id": 1,
"name": "Palo Alto",
"postal_codes": null
},
{
"id": 3,
"country_id": 1,
"region_id": 2,
"name": "New York City",
"postal_codes": null
},
{
"id": 4,
"country_id": 2,
"region_id": null,
"name": "London",
"postal_codes": null
}
]
You can use the source
parameter of a field on your serializer to achieve this. For example:
from rest_framework import serializers
from .models import City
class CitySerializer(serializers.ModelSerializer):
country_id = serializers.IntegerField(source='country')
region_id = serializers.IntegerField(source='region')
class Meta:
model = City
fields = ('id', 'country_id', 'region_id', 'name', 'postal_codes')
EDIT: As Yaroslav pointed out, when doing it in this way, you don't need to include the source
. Take note, however, that simply including country_id
or region_id
in the fields
list is not sufficient. You still need to specify the field on the serializer, such as country_id = serializers.IntegerField()
and also include it in the fields
.
Thanks to all. Finally I got it. See code bellow. I answer my question due to there is no option to add large amount of lines on a answer comment.
serializers.py
from rest_framework import serializers
from .models import Country, Region, City
class CountrySerializer(serializers.ModelSerializer):
class Meta:
model = Country
fields = ('id', 'name')
class RegionSerializer(serializers.ModelSerializer):
class Meta:
model = Region
fields = ('id', 'name', 'code')
class CitySerializer(serializers.ModelSerializer):
country_id = serializers.PrimaryKeyRelatedField(
queryset=Country.objects.all(),
required=True,
source='country',
)
region_id = serializers.PrimaryKeyRelatedField(
queryset=Region.objects.all(),
allow_null=True,
required=False,
source='region',
)
country = CountrySerializer(
read_only=False,
required=False,
)
region = RegionSerializer(
required=False,
allow_null=True,
read_only=True,
)
class Meta:
model = City
fields = (
'id',
'country', 'region',
'name', 'postal_codes',
'country_id', 'region_id',
)
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