methuselah
methuselah

Reputation: 13216

Creating new fields in serializer that access another model's attributes

My API call to api/business-review/3abe3a1e-199c-4a4b-9d3b-e7cb522d6bed/ currently returns the following:

[
    {
        "id": "3abe3a1e-199c-4a4b-9d3b-e7cb522d6bed",
        "date_time": "2016-05-31T19:18:24Z",
        "review": "Another quality job, Anna has a no fuss approach to his job and clearly takes pride in what he does. Will continue to use again and again.",
        "rating": "4.0",
        "person": "c1cc5684-1be1-4120-9d81-05aec29f352a",
        "employee": "ecdc1f99-138c-4f9f-9e1f-b959d59209aa",
        "service": "1dfa408f-d5bc-4eb2-96ae-e07e7999a01a",
    }
]

Now I want to create three new fields:

I've tried the following so far but it doesn't create any new variables:

serializers.py

class ReviewSerializer(serializers.ModelSerializer):
    """
    Class to serialize Review objects
    """
    person_name = serializers.CharField(source='person.reviewer.first_name', read_only=True)
    employee_name = serializers.CharField(source='person.employer.first_name', read_only=True)
    service_name = serializers.CharField(source='service.title', read_only=True)

    class Meta:
        model = Review
        fields = '__all__'
        read_only_fields = 'id'

models.py

class Review(models.Model):
    """
    Review model
    """
    id = models.UUIDField(primary_key=True, default=uuid4, editable=False)
    date_time = models.DateTimeField(blank=True, null=True, default=None)
    person = models.ForeignKey(Person, null=True, default=None, related_name='reviewer')
    employee = models.ForeignKey(Person, null=True, default=None, related_name='employee')
    review = models.TextField(null=True, default=None)
    service = models.ForeignKey(Service, null=True, default=None)
    rating = models.DecimalField(max_digits=4, decimal_places=1)

class Person(models.Model):
    """
    Person entity
    """
    id = models.UUIDField(primary_key=True, default=uuid4, editable=False)
    first_name = models.CharField(max_length=255)
    last_name = models.CharField(max_length=255)

class Service(models.Model):
    """
    Service model
    """
    id = models.UUIDField(primary_key=True, default=uuid4, editable=False)
    title = models.CharField(max_length=255)

Upvotes: 1

Views: 89

Answers (2)

Rahul Gupta
Rahul Gupta

Reputation: 47866

Since you want add data to the serialized representation of your object, its better to use SerializerMethodField() for person_name, service_name and employee_name fields.

This is a read-only field. It gets its value by calling a method on the serializer class it is attached to. It can be used to add any sort of data to the serialized representation of your object.

Also, since the ForeignKey fields person, employee and service allow null values, you will have to handle the case when they are actually null. Otherwise, AttributeError exception will be raised on the serializer.

class ReviewSerializer(serializers.ModelSerializer):
    """
    Class to serialize Review objects
    """
    person_name = serializers.SerializerMethodField()
    employee_name = serializers.SerializerMethodField()
    service_name = serializers.SerializerMethodField()

    class Meta:
        model = Review
        fields = ['person', 'service', 'review', 'employee', 'person_name', 'service_name', 'employee_name', 'date_time']
        read_only_fields = 'id'

    def get_person_name(self, obj):
        try:
            person_name = obj.person.first_name + obj.person.last_name
        except AttributeError: # handle case if person is null
            return None
        else:
            return person_name

    def get_employee_name(self, obj):
        try:
            employee_name = obj.employee.first_name + obj.employee.last_name
        except AttributeError: # handle case if employee is null
            return None
        else:
            return employee_name

    def get_service_name(self, obj):
        try:
            service_name = obj.service.title
        except AttributeError: # handle case if service is null
            return None
        else:
            return service_name

Upvotes: 1

mascot6699
mascot6699

Reputation: 302

Please try adding the field name explicitly instead of using __all__ which only picks up fields which are present in model and not those defined in serializer like this

fields = ['person', 'service', 'review', 'employee', 'person_name', 'service_name', 'employee_name', 'date_time']

Upvotes: 2

Related Questions