Десериализация вложенного объекта в 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",
}
Вернуться на верх