Как получить ссылку на внешний ключ в сериализаторе, используя входное значение - PullRequest
0 голосов
/ 06 февраля 2020
class Channel(models.Model):
    name = models.CharField(max_length=20)

class Product(models.Model):
    channel = models.Foreignkey(Channel, on_delete=models.PROTECT)

id | name
-------------
1  | Channel1
2  | Channel2
3  | Channel3
4  | Channel4

Для создания Product объектов мы просто отправляем id объекта Channel, и сериализатор сможет получить указанный объект. У меня есть сервис, который предоставляет конечную точку, и клиент просто отправляет запросы на создание объектов. Клиент не знает о channel ids, он знает только имена каналов.

В этой ситуации возможно ли иметь сериализатор, где клиент все еще может отправлять имена каналов в запросе, но в базе данных они получают правильные ссылки на внешние ключи при создании Product obj? Может ли кто-нибудь указать мне какие-либо примеры или документацию, чтобы справиться с этим?

Редактировать Если бы я должен был указать id в моем запросе на публикацию, представления и сериализаторы будут выглядеть следующим образом:

class ProductsViewSet(viewsets.ModelViewSet):
    queryset = models.Product.objects.all()
    serializer_class = serializers.ProductSerializer

class ProductSerializer(serializers.ModelSerializer):
    class Meta:
        model = models.Product
        fields = "__all__"

, и тело запроса будет иметь вид,

{
    "channel": 1
}

Но я хочу отправить запрос, как показано ниже, но все же смогу использовать вышеуказанный сериализатор с небольшими изменениями,

{
    "channel": "Channel1"
}

Далее Редактировать У меня работает ответ от Саши. Я должен был предоставить один дополнительный аргумент queryset, полный сериализатор показан ниже,

class ProductSerializer(serializers.ModelSerializer):
    channel = serializers.SlugRelatedField(
        many=False,
        read_only=False,
        slug_field='name',
        queryset=models.Channel.objects.all()
    )

    class Meta:
        model = models.Product
        fields = "__all__"

Если вы хотите создать объекты ссылочной модели (если она не существует), тогда мы должны будем расширить SlugRelatedField, так как он не может создавать объекты по умолчанию. Ниже я нашел пример, который

Создание и сохранение объектов внешнего ключа с использованием SlugRelatedField

1 Ответ

1 голос
/ 07 февраля 2020

Если я правильно понял вопрос, вам следует реализовать метод .create() на сериализаторе. Затем вы можете получить доступ к validated_data, чтобы получить канал и создать продукт со ссылкой на него.

class CreateProductSerializer(serializers.Serializer):
    name = serializers.CharField(max_length=20)

    def create(self, validated_data):
        name = validated_data.get('name', False)

        # naive implementation, should still handle errors (eg. not found)
        # you need to be sure that only 1 object with that name will exist (see comment below)
        channel = Channel.objects.get(name=name)
        return Product(channel=channel)

Если вы собираетесь выполнить поиск по названию, вы должны убедиться, что * Поле 1006 * в модели Channel имеет unique=True

Для справки: https://www.django-rest-framework.org/api-guide/serializers/#saving -экземпляры

Редактировать: После редактирования вопроса Похоже, существует встроенное решение SlugRelatedField, предназначенное для чтения / записи по умолчанию. Также обратите внимание на то, что в соответствии с документацией :

При использовании SlugRelatedField в качестве поля для чтения и записи, вы обычно хотите убедиться, что поле слагов соответствует полю модели с unique=True.

class ProductSerializer(serializers.ModelSerializer):
    channel = serializers.SlugRelatedField(
        many=False,
        read_only=False,
        slug_field='name'
    )

    class Meta:
        model = models.Product
        fields = "__all__"
...