Десериализация вложенного объекта в Django-Rest-Framework
Добрый день,
Я пытаюсь выполнить запрос PUT, содержащий вложенный объект, и не могу заставить провинцию правильно обновляться. В документации django-rest-framework не было ничего очевидного, чтобы помочь с этим, и я исследовал решения нескольких других подобных проблем, но ни одно не помогло (установить many=false
, изменить на ModelSerializer
, специализированные сериализаторы и т.д.).
Все остальное, что касается адрес, обновляется корректно и возвращает ответ 200 (ошибок в логах django тоже нет). Ошибаюсь ли я, полагая, что django-rest-framework обрабатывает все это для меня бесплатно? Должен ли я переопределить методы update и create в сериализаторе для проверки и сохранения вложенного объекта?
Я думаю, что это происходит потому, что у меня сериализатор province установлен на read_only
внутри сериализатора address. Однако, если я удалю модификатор read_only
на сериализаторе province, он выдает ошибку о том, что province уже существует:
{
"province": {
"province": [
"valid province with this province already exists."
]
}
}
Это поведение, которого я не ожидаю и не знаю, как его решить. Я не пытаюсь добавить или обновить провинцию. Я просто хочу изменить код провинции в поле address.province, и я не могу использовать строку "MB", потому что она ожидает объект. Я фактически хочу такого поведения:
UPDATE agent_business_address
SET province = 'MB'
WHERE agent_id = 12345;
-- agent_business_address.province has a foreign key constraint on valid_province.province
-- valid_province is populated with all the 2-letter abbreviations for provinces(
Я делаю этот PUT запрос к /api/agent-business-address/
{
"address": "123 Fake St",
"agent_id": 12345,
"city": "Calgary",
"dlc": "2021-10-11 14:03:03",
"operator_id": 4,
"postal_code": "A1B 2C3",
"province": {
"description": "Manitoba",
"province": "MB"
},
"valid_address": "N"
}
Что получено этим ViewSet:
class AgentBusinessAddressViewSet(viewsets.ModelViewSet):
queryset = AgentBusinessAddress.objects.all()
serializer_class = AgentBusinessAddressSerializer
Соответствующие сериализаторы:
class AgentBusinessAddressSerializer(serializers.HyperlinkedModelSerializer):
province = ValidProvinceSerializer(read_only=True) # Removing the read_only causes the error above.
class Meta:
model = AgentBusinessAddress
fields = ('agent_id', 'operator_id', 'dlc', 'address', 'city', 'province', 'postal_code', 'valid_address')
class ValidProvinceSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = ValidProvince
read_only_fields = ('operator_id', 'dlc')
fields = ('province', 'description')
Релевантные модели:
class AgentBusinessAddress(models.Model):
agent = models.OneToOneField(Agent, models.DO_NOTHING, primary_key=True)
operator_id = models.SmallIntegerField()
dlc = models.DateTimeField()
address = models.CharField(max_length=100)
city = models.CharField(max_length=80)
province = models.ForeignKey('ValidProvince', models.DO_NOTHING, db_column='province')
postal_code = models.CharField(max_length=7)
valid_address = models.CharField(max_length=1)
class Meta:
managed = False
db_table = 'agent_business_address'
class ValidProvince(models.Model):
province = models.CharField(primary_key=True, max_length=2)
operator_id = models.SmallIntegerField()
dlc = models.DateTimeField()
description = models.CharField(max_length=30, blank=True, null=True)
class Meta:
managed = False
db_table = 'valid_province'
Любая помощь будет принята с благодарностью.
Решил это с помощью поста specialized serializers после нескольких перечитываний.
Я обновил сериализаторы следующим образом:
# This gets called for non-GET requests.
class AgentBusinessAddressSerializer(serializers.ModelSerializer):
class Meta:
model = AgentBusinessAddress
fields = ('__all__')
# This get called for GET requests.
class AgentBusinessAddressReadSerializer(AgentBusinessAddressSerializer):
province = ValidProvinceSerializer(read_only=True)
class Meta:
model = AgentBusinessAddress
fields = ('__all__')
Я обновил набор представлений следующим образом:
class AgentBusinessAddressViewSet(viewsets.ModelViewSet):
queryset = AgentBusinessAddress.objects.all()
def get_serializer_class(self):
if self.request.method in ['GET']:
return AgentBusinessAddressReadSerializer
return AgentBusinessAddressSerializer
Теперь я просто отправляю первичный ключ для провинции в запросе PUT:
{
"address": "123 Fake St",
"agent": 10000003,
"city": "Calgary",
"dlc": "2021-10-11 19:47:38",
"operator_id": 4,
"postal_code": "A1B 2C3",
"province": "NS",
"valid_address": "N"
}
Я получаю ответ PUT 200 и проверяю в БД, что провинция теперь 'NS'.
{
"agent": 10000003,
"operator_id": 4,
"dlc": "2021-10-11T19:47:38",
"address": "123 Fake St",
"city": "Calgary",
"postal_code": "A1B 2C3",
"valid_address": "N",
"province": "NS",
}