Фреймворк Django rest; как вы используете идентификатор внешнего ключа для создания экземпляра через сериализатор?

#django #django-rest-framework

#django #django-rest-framework

Вопрос:

У меня есть два сериализатора, один для Country и один для моей модели Foo, я хочу сохранить объект, используя внешний ключ для этой модели, но он выдает ошибку всякий раз, когда я пытаюсь выполнить проверку.

У меня есть это

 class Actor(TLPWrappedModel, CommentableModel):
    label = models.CharField(max_length=56, unique=True)
    country_of_origin = models.ForeignKey(Country, on_delete=models.CASCADE)



class FooSerializer(serializers.ModelSerializer):
    country_of_origin = CountrySerializer()

    class Meta:
        model = Actor
        fields = [
            'id',
            'country_of_origin',
            'label',
       ]


class Country(models.Model):
    label = models.CharField(max_length=56, unique=True)
    iso_code = models.CharField(max_length=3, unique=True)

class CountrySerializer(serializers.ModelSerializer):
    class Meta:
        model = Country
        fields = [
            'iso_code',
            'label',
        ]
 

И это то, что я пытаюсь сделать

     serializers = FooSerializer(data={'label': 'Foobar',
                                        'country_of_origin': self.country.id})
    serializers.is_valid()
    print(serializers.errors)
    print(serializers.validated_data)
    serializers.save()
 

Но я получаю эту ошибку {'country_of_origin': {'non_field_errors': [ErrorDetail(string='Invalid data. Expected a dictionary, but got int.', code='invalid')]}}

можно ли использовать идентификатор внешнего ключа для проверки и создания объекта с помощью сериализатора?

Ответ №1:

Мы можем обновить to_represent FooSerializer, чтобы получить желаемый результат

Попробуйте

 class FooSerializer(serializers.ModelSerializer):

    class Meta:
        model = Actor
        fields = [
            'id',
            'country_of_origin',
            'label',
       ]
    
    def to_representation(self, instance):
        data = super().to_representation(instance)
        data['country_of_origin'] = CountrySerializer(instance.country_of_origin)
        return data

 
  serializers = FooSerializer(data={'label': 'Foobar', 'country_of_origin': self.country})
 serializers.is_valid(raise_expection=True)
 serializers.save()
 

В этом я обновил код, чтобы назначить self.country as country_of_origin . Кроме того, я использую метод raise_expection in is_valid . Этот метод вернет ошибки в виде ответа 400.

Комментарии:

1. Это не совсем решает проблему. FooSerializer сериализует объект в json, подобный этому {‘label’: ‘Foobar’, ‘country_of_origin’: 1}, когда я хочу {‘label’: ‘Foobar’: ‘country_of_origin’: {‘label’: ‘usa’}} в качестве примера. Или я что-то недопонимаю?

2. о, я обновил ответ. Пожалуйста, попробуйте это и дайте мне знать, если это решит проблему

Ответ №2:

Попробуйте

 class FooSerializer(serializers.ModelSerializer):
    

    class Meta:
        model = Actor
        fields = [
            'id',
            'country_of_origin',
            'label',
       ]

 

Вы можете безопасно отказаться от определения «страны происхождения` в FooSerializer

Комментарии:

1. Является ли единственным способом заставить это работать, сохраняя при этом сериализованный json расширенным, чтобы использовать два разных класса сериализатора?

2. Абсолютно нет! есть и другие способы. Я добавляю другой ответ с другим подходом

Ответ №3:

contry_of_origin будет объектом, и вы передаете для него идентификатор.

Вам нужен вложенный сериализатор? : country_of_origin = CountrySerializer() Для примера, который вы привели, я бы посоветовал вам изменить его на PrimaryKeyRelatedField()

Ваш сериализатор будет выглядеть так:

 class FooSerializer(serializers.ModelSerializer):
    country_of_origin = serializers.PrimaryKeyRelatedField()

    class Meta:
        model = Actor
        fields = [
            'id',
            'country_of_origin',
            'label',
       ]
 

Комментарии:

1. Является ли единственным способом заставить это работать, сохраняя при этом сериализованный json расширенным, чтобы использовать два разных класса сериализатора?

2. Вам не понадобится CountrySerializer, если вы передаете идентификатор в primarykeyrelatedfield . Серализаторы необходимы, только если вы планируете просматривать / создавать / редактировать этот пространственный набор данных (модель)

3. Мне нужно, чтобы CountrySerializer видел фактическое содержимое объекта, когда он сериализуется в json.

4. Я думаю, что есть некоторая путаница с требованием. Давайте обсудим это в чате