Arepo
Arepo

Reputation: 889

Using external input for a Django rest framework serializer

I have a class with a US cent value. When I serialize it I want to be able to convert it to a dynamically specified other currency. So the class looks like this:

 class Evaluation(models.Model):
   sum_in_cents = models.IntegerField()
   def converted_sum_in_cents(currency_code):
     currency_code = currency_code.upper()
     CurrencyConverter().convert(self.sum_in_cents / 100, 'USD', currency_code)
     ... #other stuff

And it has a standard serializer that currently ignores that function:

class EvaluationSerializer(serializers.ModelSerializer):
  class Meta:
    model = Evaluation
    fields = '__all__'
    depth = 1

So how, when using the serializer, should I get the currency_code argument to the converted_sum_in_cents method? (it's passed as a query string in the view)

I've got as far as learning that I can pass a context object when initialising my serialiser and that serialiser functions can access data within that, but I can't see how to include the output of those functions as a serialiser field. I've also found this thread, which is my fallback plan, but both that thread's author and I are suspicious that if that were the right way of doing something that seems like it must come up a lot, DRF would have included a lot less hacky pathway to doing it. So am I just thinking about this wrong?

Upvotes: 0

Views: 797

Answers (1)

Arepo
Arepo

Reputation: 889

I've found a way:

When instantiating the EvaluationSerializer class, I optionally pass in a context argument as mentioned in the OP, described here.

All methods of the class then have access to that object. The part I was missing is described in this StackOverflow answer:

Create a custom method field on the object, and define a method called get_<custom_field_name> to set the value. So the Evaluation class looks like this:

class EvaluationSerializer(serializers.ModelSerializer):
  converted_cost_per_output = serializers.SerializerMethodField()

  def get_converted_cost_per_output(self, evaluation):
    currency_code = self.context['currency'].upper()
    return CurrencyConverter().convert(evaluation.cents_per_output / 100, 'USD', currency_code)

(and there's no method defined on the model)

Upvotes: 1

Related Questions