Фреймворк отдыха Django: serializers.ReadOnlyField() не отображает поле в доступных для просмотра API

Среда отдыха Django: Как я могу отобразить поле только для чтения в доступном для просмотра API?

Когда я добавлю result = serializers.CharField(read_only=True) для моего сериализатора модели форма больше не отображает поле результатов.

Я понимаю проблемы безопасности пользователя, удаляющего disabled атрибут на входе формы (хотя я удивлен, что django не обрабатывает это изначально), так как я могу реализовать поле только для чтения в шаблоне api.html из result?

serializers.py

class SnippetSerializer(serializers.HyperlinkedModelSerializer):
owner = serializers.ReadOnlyField(source='owner.username')
result = serializers.CharField(read_only=True)

class Meta:
    model = Snippet
    fields = ('title', 'code', 'owner', 'url', 'result')

Я новичок в Django-Rest Framework, поэтому любая помощь будет оценена!

1 ответ

Решение

У вас есть 2 варианта:

  1. либо рассчитать результат в модели

  2. или добавить поле в сериализации

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

Когда вы хотите рассчитать результат в модели

Следуйте примеру полученного полного имени Джанго, где-то рядом: https://github.com/django/django/blob/master/django/contrib/auth/models.py

Или объясните здесь в документе: https://docs.djangoproject.com/en/dev/topics/db/models/

Это будет действовать как поле только для чтения для DRF автоматически.

Вы можете увидеть использование в коде ниже (get_full_name).

Когда вы хотите добавить поле в сериализации

У вас есть ответ в документации DRF: http://www.django-rest-framework.org/api-guide/fields/

SerializerMethodField Это поле только для чтения... Его можно использовать для добавления любых данных в сериализованное представление вашего объекта.

Пример hours_since_joined в serializers.py:

from django.contrib.auth.models import User, Group
from rest_framework import serializers
from django.utils.timezone import now

class UserSerializer(serializers.HyperlinkedModelSerializer):
    hours_since_joined = serializers.SerializerMethodField()
    class Meta:
        model = User
        fields = ('url', 'username', 'email', 'groups', 'hours_since_joined', 'first_name', 'last_name', 'get_full_name' )

    def get_hours_since_joined(self, obj):
        return (now() - obj.date_joined).total_seconds() // 3600

class GroupSerializer(serializers.HyperlinkedModelSerializer):
    class Meta:
        model = Group
        fields = ('url', 'name', 'user_set')

Для вашего случая:

class SnippetSerializer(serializers.HyperlinkedModelSerializer):
    owner = serializers.ReadOnlyField(source='owner.username')
    result = serializers.SerializerMethodField()

    class Meta:
        model = Snippet
        fields = ('title', 'code', 'owner', 'url', 'result')

    def get_result(self, obj):
        # code here to calculate the result
        # or return obj.calc_result() if you have that calculation in the model
        return "some result"

Чтобы показать добавленные поля в браузере API DRF

Вы должны перечислить их в полях Меты - см. Пример выше. Это представит, что в доступном для просмотра выводе по запросам. Однако он не будет отображать их в HTML-форме DRF. Причина в том, что форма HTML используется только для отправки информации, поэтому шаблон restframework пропускает поле только для чтения при рендеринге.

Как вы видите, полное имя и часы с момента присоединения не отображаются в форме, но доступны для API:

Если вы хотите отобразить поля только для чтения также на форме

вам нужно переопределить шаблоны restframework.

  • убедитесь, что ваши шаблоны загружены до работы restframework (т.е. ваше приложение находится выше restframework в settings.py)
  • используйте dir шаблонов под вашим приложением
  • создать subdir в ваших шаблонах dir: restframework/ горизонтальный
  • скопируйте form.html и input.html из библиотеки Python \site-packages\rest_framework\templates\rest_framework\ Horizontal\

  • изменить form.html

{% load rest_framework %}
{% for field in form %}
    {% render_field field style=style %}
{% endfor %}
  • изменить строку ввода в input.html (добавив отключенный атрибут)

    <input name="{{ field.name }}"  {% if field.read_only %}disabled{% endif %} {% if style.input_type != "file" %}class="form-control"{% endif %} type="{{ style.input_type }}" {% if style.placeholder %}placeholder="{{ style.placeholder }}"{% endif %} {% if field.value %}value="{{ field.value }}"{% endif %}>
    

Результат:

Для людей, которые не могут сделать его видимым в Browsable API, папка шаблона должна быть названа: rest_framework

Другие вопросы по тегам