Django REST Framework вложенный ключ ресурса "id" недоступен
Поэтому у меня есть следующая структура:
Клиентский файл принадлежит владельцу (имя класса = Контакт). Я пытаюсь создать клиентский файл с помощью API. Запрос содержит следующие данные:
{
name: "Hello!"
owner: {
id: 1,
first_name: "Charlie",
last_name: "Watson"
}
}
Я создал сериализатор в соответствии с моей структурой. Надеясь, что этот вызов API создаст клиентский файл с именем "Hello!" и контакт id 1 как владелец:
class ContactSerializer(serializers.ModelSerializer):
class Meta:
model = Contact
fields = (
'id',
'first_name',
'last_name',
)
class ClientfileSerializer(serializers.ModelSerializer):
owner = ContactSerializer(read_only=False)
class Meta():
model = Clientfile
fields = (
'id',
'name',
'owner',
)
def create(self, validated_data):
owner = Contact.objects.get(pk=validated_data['owner']['id'])
Я вхожу в метод create. Однако единственное поле, которое мне нужно (['owner']['id'])
недоступно. Если я print ['owner']['first_name']
он вернет "Charlie". Но идентификатор по некоторым причинам не кажется доступным...
Любые причины, по которым это может произойти? Я что-то упускаю? (Я новичок в Django)
РЕШЕНИЕ: Просто выяснилось, что причина, по которой идентификатор не показывалась в первую очередь, заключалась в том, что я должен был объявить ее в полях следующим образом: Надеюсь, это поможет.
class ContactSerializer(serializers.ModelSerializer):
id = serializers.IntegerField() # ← Here
class Meta:
model = Contact
fields = (
'id',
'first_name',
'last_name',
)
Ответы
Ответ 1
Хорошо, поэтому я нашел другой подход, который работает. Я добавил сериализатор IntegerField для отношения владельца. Мне также пришлось установить отношение владельца к read_only = True.
Это json, который я отправляю через POST:
{
name: "Hello!"
owner_id: 1
}
Это мой сериализатор:
class ClientfileSerializer(serializers.ModelSerializer):
owner_id = serializers.IntegerField()
owner = ContactSerializer(read_only=True)
class Meta():
model = Clientfile
fields = (
'id',
'owner_id',
'owner',
)
Это кажется менее крутым, чем первый способ, но он выполняет эту работу. Кроме того, я не хочу создавать нового владельца, но просто выберите тот, который уже находится в базе данных. Так что, возможно, это более семантический, чтобы иметь только идентификатор, а не полный набор информации, отправленный через Json.
Ответ 2
В полях Django REST Framework AutoField
(автоматически создаваемые) по умолчанию используются только для чтения. Из документов:
read_only
Установите для этого значение " True
чтобы гарантировать, что это поле используется при сериализации представления, но не используется при создании или обновлении экземпляра во время десериализации.
По умолчанию False
Вы можете увидеть это, проверив свой сериализатор, напечатав представление в своей оболочке:
serializer = ClientfileSerializer()
print repr(serializer)
Вы можете переопределить это, установив read_only=False
в поле id в extra_kwargs
:
class ContactSerializer(serializers.ModelSerializer):
class Meta:
model = Contact
fields = (
'id',
'first_name',
'last_name',
)
extra_kwargs = {'id': {'read_only': False}}
class ClientfileSerializer(serializers.ModelSerializer):
owner = ContactSerializer(read_only=False)
class Meta():
model = Clientfile
fields = (
'id',
'name',
'owner',
)
extra_kwargs = {'id': {'read_only': False}}
Ответ 3
Вы можете попробовать что-то вроде этого:
class YourModelSerializer(serializers.ModelSerializer):
class Meta:
model = YourModel
fields = ('id', 'field1', 'field2')
def to_internal_value(self, data):
"""
Dict of native values <- Dict of primitive datatypes.
Add instance key to values if 'id' present in primitive dict
:param data:
"""
obj = super(YourModelSerializer, self).to_internal_value(data)
instance_id = data.get('id', None)
if instance_id:
obj['instance'] = YourModel.objects.get(id=instance_id)
return obj
Затем в валидированных данных с сериализатором вы должны иметь ключ "instance", если request.data имеет ключ "id".
Также вы можете добавить только "id" вместо полного экземпляра/объекта.