Как создать модель, указав имена полей внешнего ключа, которые являются уникальными вместе, а не его pk?
Я пытаюсь настроить сериализатор REST-фреймворка на POST объекта Target
, указав имена трех полей его Foreign relation Market
, которые уникальны вместе (символ, обмен, тип), вместо того, чтобы указывать первичные ключи объекта Market
.
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)
Вместо этого :
{
"weight": 19.23,
"market": 11,
"dt": "2022-06-09"
}
Я хотел бы разместить сообщение в этой форме :
{
"weight": 0.1923,
"market_symbol": "ABC/USD",
"market_type": "xyz",
"market_exchange_exid": "my_exchange",
"dt": "2022-06-09"
}
Для этого я создал класс ModelSerializer
и добавил 3 пользовательских поля, которые однозначно определяют рынок, как было предложено в Указание полей явно.
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')
Однако когда я проталкиваю данные, он выбрасывает ошибку Bad Request 400
. Как я могу сказать ему, чтобы он использовал это поле в качестве селектора внешнего ключа?
У вас есть несколько вариантов, я думаю, что лучшим подходом может быть попытка переопределить методы create
/ update
в вашем сериализаторе, разобрать сериализованные данные для символа, типа и обмена. Затем получить объект Market с этими данными и использовать его для создания объекта Target.
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'])