2016-12-20 7 views
1

Я не могу заставить DRF разрешить предоставление read_only версии вложенных данных и записываемой версии только идентификаторов в списке в одном сериализаторе. Мне кажется, что это ошибка, но обычно это просто означает, что я недостаточно хорошо разбираюсь в структуре и ошибаюсь в сообщении об ошибке.Django Rest Framework не отвечает на read_only на вложенные данные

class Individual(models.Model): 
    household = models.ForeignKey(
     'household.Household', 
     null=True, 
     related_name="individuals") 
    name = models.CharField(
     max_length=100, default='') 

class Household(models.Model): 
    address_line1 = models.CharField(max_length=64, default='') 

class IndividualListSerializer(serializers.ModelSerializer): 
    class Meta: 
     model = Individual 
     depth = 0 
     fields = ('url', 'id', 'name', 'household') 
     read_only_fields = fields 

class HouseholdUpdateSerializer(serializers.ModelSerializer): 
    individuals_details = IndividualListSerializer(many=True, source='individuals', read_only=True) 
    class Meta: 
     model = Household 
     fields = ('id', 'address_line1', 'individuals', 'individuals_details') 
     read_only_fields = ('id', 'individuals_details') 

ошибка возвращается как

AssertionError: The `.update()` method does not support writable nested fields by default. Write an explicit `.update()` method for serializer `household.serializers.HouseholdUpdateSerializer`, or set `read_only=True` on nested serializer fields. // Werkzeug Debugger</title> 

Я использовал read_only на вложенном поле (которое необходимо в ответ на обновление). Однако ошибка все еще указывает на то, что я этого не делаю.

Если я полностью удаляю поле individuals, individuals_details возвращает считанные данные без ошибок, но поскольку он игнорирует отправленные данные individuals, он не обновляет этот список.

Если я удалю поле individuals_details, DRF принимает список individuals и выполняет обновление по модели. Но тогда необходимых данных возврата нет.

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

Это кажется довольно распространенной областью людей, застрявших, и кажется, что ответы this SO question стали лучшей практикой для картины. Но по какой-то причине это не работает в моем коде. Возможно, из-за ManyToOne в моих моделях.

Возможно, я обойду это, изменив клиент для выполнения PUT для обновления, проигнорировав ответ, а затем сделайте отдельное GET, но это неряшливо и не нужно, если обновление DRF можно сделать работайте, как ожидалось.

Что мне недостает в этом?

+0

Я не уверен, что 'read_only_fields' предназначен для работы с явно определенными полями. Как насчет удаления individual_details из 'read_only_fields'? Он исправляет? – Linovia

+0

Также обратите внимание, что это анти-шаблон для использования как реляционного поля И вложенного сериализатора в ту же модель. – Linovia

+0

Не моя цель - использовать как реляционные, так и вложенные. Но DRF не позволяет мне обновлять только идентификатор вложенных данных. Итак, каков хороший шаблон для получения информации о дочерних записях после изменения идентификаторов? – shanemgrey

ответ

1

Вы задаете несколько вопросов, поэтому я начну с представления. На самом деле вам не нужно отдельное поле для полного просмотра Individual, которое вы могли бы просто ovveride to_representation метод.

class HouseholdUpdateSerializer(serializers.ModelSerializer): 

    class Meta: 
     model = Household 
     fields = ('id', 'address_line1', 'individuals') 

    def to_representation(self, instance): 
     representation = super(HouseholdUpdateSerializer, self).to_representation(instance) 
     representation['individuals'] = IndividualListSerializer(instance.individuals.all(), many=True).data 
     return representation 

Обычно, когда вы хотите, связанные с обновлением полеми вашей модели, вы должны переопределить create и update методы Serializer.

class HouseholdUpdateSerializer(serializers.ModelSerializer): 
    .... 
    def update(instance, validated_data): 
     # get and remove individuals from validated_data 
     individuals = validated_data.pop('individuals') 
     # delete all related links to individuals 
     # You could provide some validation before clear, check if provided pks exists in db table 
     instance.individuals.clear() 
     # update related links with new individuals 
     instance.individuals.add(*individuals) 
     # call super to provide update for other fields 
     return super(HouseholdUpdateSerializer, self).update(validated_data) 

create, вероятно, хорошо работает в вашем случае не перекрывая. Если это не просто написать его, аналогично update.

+0

Переопределение представления искалось для того, что мне было нужно. Я не понимаю, что делает вторая часть переопределения метода обновления. Я предполагаю, что мне также понадобится специальный валидатор для человека? – shanemgrey

+0

@shanemgrey уверен, что вы можете проверить, существуют ли ключи 'individual' в db, прежде чем очистить ссылки между ними. Если какой-то ключ ошибочен, вы выбросите исключение, а затем поймаете его на уровне представления с помощью 'if serializer.is_valid(): ..' выражение или с 'serializer.save (raise_exception = True)'. Вы можете проверить свои ключи с помощью 'queryset.exists()' для каждого ключа или проверить 'len' вас ключи и считать ключи в db, например' if len (individual) == Individuals.objects.filter (pk__in = особи) .count() '. –

Смежные вопросы