I'm trying to configure REST framework serializer to POST a Target
object by specifying the 3 field names of it's Foreign relation Market
that are unique together (symbol, exchange, type), rather than specifying the primary keys of the Market
object.
models.py
class Exchange(models.Model):
exid = models.CharField(max_length=12, unique=True)
class Market(models.Model):
symbol = models.CharField(max_length=5)
type = models.CharField(max_length=5)
exchange = models.ForeignKey(Exchange, on_delete=models.CASCADE, related_name='market')
class Meta:
unique_together = ['symbol', 'type', 'exchange']
class Target(models.Model):
weight = models.FloatField()
exchange = models.ForeignKey(Exchange, on_delete=models.CASCADE, related_name='target')
market = models.ForeignKey(Market, on_delete=models.CASCADE, related_name='target')
dt = models.DateTimeField(null=True)
Instead of this :
{
"weight": 19.23,
"market": 11,
"dt": "2022-06-09"
}
I would like to post in this form :
{
"weight": 0.1923,
"market_symbol": "ABC/USD",
"market_type": "xyz",
"market_exchange_exid": "my_exchange",
"dt": "2022-06-09"
}
To achieve this I created a class ModelSerializer
and added the 3 custom fields that uniquely specify a market, as suggested in Specifying fields explicitly.
class TargetSerializer(serializers.ModelSerializer):
market_symbol = serializers.StringRelatedField()
market_type = serializers.StringRelatedField()
market_exchange = serializers.StringRelatedField()
class Meta:
model = Target
fields = ('id', 'weight', 'dt', 'market_symbol', 'market_type', 'market_exchange')
However when I push the data it throws a Bad Request 400
. How can I tell him to use this fields as a Foreign key selector ?
CodePudding user response:
You have a couple of choices, I think the best approach might be to try overriding the create
/ update
methods in your serializer, parse the serialized data for the symbol, type and exchange. Then get the Market object with that data and use that to create the Target object.
class MarketSerializer(serializers.ModelSerializer):
class Meta:
model = Market
fields = ('id', 'symbol', 'type', 'exchange',)
class TargetSerializer(serializers.ModelSerializer):
market_symbol = serializers.CharField(max_length=200, write_only=True)
market_type = serializers.CharField(max_length=200, write_only=True)
market_exchange = serializers.CharField(max_length=200, write_only=True)
market = MarketSerializer(read_only=True)
class Meta:
model = Target
fields = ('id', 'weight', 'dt', 'market', 'market_symbol', 'market_type', 'market_exchange')
def create(self, validated_data):
market = get_object_or_404(
Market,
symbol=validated_data['market_symbol'],
type=validated_data['market_type'],
exchange=validated_data['market_exchange'],
)
return Target.objects.create(market=market, weight=validated_data['weight'], dt=validated_data['dt'])