swor
swor

Reputation: 901

Can't serialize foreignKey object data

I have one-to-many relation Developer and Constructions I want to serialize all Developer field when I serialize Construction object

For request

{
    "developer": 1,
    "name": "as2",
    "address": "ZZZZZZZZZZZZZsdf",
    "deadline": "2020-05-13 14:26:58",
    "coordinates": { "latitude": 49.8782482189424, "longitude": 24.452545489 }
    
}

I have an error:

{
    "developer_data": [
        "This field is required."
    ]
}

It's strange for me because developer_data marked as read_only

How can I fix the error? I thin that problem deals with serializer

models.py

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

def name_image(instance, filename):
    return '/'.join(['images', str(instance.name), filename])

class Construction(models.Model):
    developer = models.ForeignKey(
        Developer, related_name="constructions", on_delete=models.CASCADE
    )
    name = models.CharField(max_length=100)
    image = models.ImageField(upload_to=name_image, blank=True, null=True)
    ...

serializers.py (UPDATED)

class DeveloperSerializer(serializers.ModelSerializer):
    constructions_number = serializers.SerializerMethodField()
    workers_number = serializers.SerializerMethodField()
    machines_number = serializers.SerializerMethodField()

    class Meta:
        model = Developer
        fields = ('id', 'name', 'constructions_number', 'workers_number', 'machines_number')
    
    def create(self, validated_data):
        instance = super().create(validated_data=validated_data)
        return instance
    
    def get_constructions_number(self, obj):
        return obj.constructions.count()
    
    def get_workers_number(self, obj):
        res = obj.constructions.aggregate(Sum('workers_number'))['workers_number__sum']
        if res:
            return res
        return 0

    def get_machines_number(self, obj):
        res = obj.constructions.aggregate(Sum('machines_number'))[ "machines_number__sum"]
        if res:
            return res
        return 0
    


class ConstructionSerializer(serializers.ModelSerializer):
    coordinates = PointField()
    deadline = serializers.DateTimeField(format=TIME_FORMAT)
    cameras_number = serializers.SerializerMethodField()
    developer = DeveloperSerializer()

    class Meta:
        model = Construction
        fields = (
            'id', 'developer', 'name', 'image', 'address', 'coordinates', 'deadline',
            'workers_number', 'machines_number', 'cameras_number',
        )
        read_only_fields = ('workers_number', 'machines_number', 'cameras_number')
    
    def create(self, validated_data):
        instance = super().create(validated_data=validated_data)
        return instance
    
    def get_cameras_number(self, obj):
        return obj.cameras.count()

I use standard ModelViewSet for the models in views.py and i think that problem in serializers.py

Upvotes: 0

Views: 42

Answers (1)

Jimmar
Jimmar

Reputation: 4449

You are using the developer serializer wrong, change the ConstructionSerializer to this

class ConstructionSerializer(serializers.ModelSerializer):
    coordinates = PointField()
    deadline = serializers.DateTimeField(format=TIME_FORMAT)
    cameras_number = serializers.SerializerMethodField()
    developer = DeveloperSerializer()

    class Meta:
        model = Construction
        fields = (
            'id', 'developer', 'name', 'image', 'address', 'coordinates', 'deadline',
            'workers_number', 'machines_number', 'cameras_number',
        )
        read_only_fields = ('workers_number', 'machines_number', 'cameras_number', 'developer') # if you don't want developer to be read only then remove it from there
    
    def create(self, validated_data):
        instance = super().create(validated_data=validated_data)
        return instance
    
    def get_cameras_number(self, obj):
        return obj.cameras.count()

Upvotes: 1

Related Questions