Django REST Framework: отображение элементов формы в ответе списка - PullRequest
0 голосов
/ 17 апреля 2019

Как можно использовать Django REST Framework для отображения списка экземпляров модели с конкретными полями, редактируемыми пользователем?

Я несколько месяцев в Джанго, и всего пару дней в ДРФ.Я пробовал несколько разных подходов, но просто не могу обойти это.

До использования DRF мой рабочий процесс состоял бы в том, чтобы настроить представление (и связанный URL), которое: queriedмоя модель, выбрала мою собственную форму из forms.py (открывая только нужные мне поля), поместила их в словарь и отправила их в шаблон.

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

Затем я могу вызвать этот шаблон с помощью запроса на получение AJAX.

models.py

class Buyer(models.Model):
  name = models.CharField(unique=True, max_length = 20)

class Item(models.Model):
  name = models.CharField(unique=True, max_length = 50)
  active = models.BooleanField(default=True)
  bought_by = models.ForeignKey(Buyer, null=True, blank=True, to_field="name",)

views.py

class ItemViewSet(viewsets.ModelViewSet):
  queryset = models.Item.objects.select_related("bought_by")
  serializer_class= serializers.ItemSerializer
  filterset_fields = ("bought_by")

serializers.py

class ItemSerializer(serializers.HyperlinkedModelSerializer):
  class Meta:
    model = models.Item
    fields = "__all__"
    extra_kwargs = {"url": {"view_name: "myapp:item-detail"}}

urls.py

router = routers.DefaultRouter()
router.register(r"items", views.ItemViewSet)

template.html

{% load static %}
{% load rest_framework %}

<table id="item_table" class="table">
  <thead>
    <tr>
      <th scope="col">Name</th>
      <th scope="col">Active</th>
      <th scope="col">Buyer</th>
    </tr>
  </thead>

  <tbody>
    {% for item in data %}
      <tr scope="row">
        <td>{{ item.name }}</td>
        <td>{{ item.active }}</td>
        <td>{{ item.bought_by }}</td>
      </tr>
    {% endfor %}
  </tbody>
</table>

Некоторые файлы Js

function getData(){
  updateRequest = $.ajax({
    type: "GET",
    url: "myapp/items/",
    success: function(data) {
      //....
    }
  });
}

Первый подход: настройте ListModelMixin для ItemViewSet, чтобы он отображал шаблон и передавал сериализатор.Что-то вроде:

def list(self,request, *args, **kwargs):
  ...
  return Response ({'data': queryset, 'serializer': serializer}, template_name = "myapp/template.html")

, затем в template.html измените {{item.active}} на:

<form action="{{ item.url }}" method="post">
  {% csrf_token %}
  {{ render_form serializer }}
</form>

Ошибка: сериализатор не повторяется.Имеет смысл.Изменено:

{{ render_field item.bought_by }}

Ошибка: нужен стиль, добавлено.продолжал получать другие ошибки

Второй подход: попробуйте изменить ListModelMixin для сбора словаря экземпляров сериализованной модели, например:

items= dict()
        for item in queryset:
            items[item] = serializers.ItemSerializer(item, data=request.data)

Никогда не понимал это как serializers.ItemSerializer (itemdata = request.data) не представляется элементом словаря и поэтому не может использовать data.items () для его просмотра в шаблоне.

Извинения за долгую запись, но яЯ немного в море и не совсем уверен, как действовать.

Какой самый элегантный способ DRF - вернуть список всех экземпляров модели с некоторыми редактируемыми полями (аналогично тому, как вы это делали в django admin суказан list_editable)?

Я всегда мог бы использовать более старый метод, но мне кажется, что я упускаю что-то очевидное с DRF здесь.

Ссылки:

https://www.django -rest-framework.org / themes / html-and-forms /

Сериализаторы Django Rest Framework визуализируют форму индивидуально

Отображение формыс Джанго отдыхом framewoКласс ModelViewSet рк внутри APIView

1 Ответ

0 голосов
/ 18 апреля 2019

Решено

Второй подход был наиболее близким: условно выберите средство визуализации и перезапишите стандартный .list ().

views.py:

from rest_framework import renderers
from rest_framework.response import Response

class ItemViewSet(viewsets.ModelViewSet):
  queryset = models.Item.objects.select_related("bought_by")
  serializer_class= serializers.ItemSerializer
  filterset_fields = ("bought_by")
  renderer_classes = [renderers.JSONRenderer, renderers.BrowsableAPIRenderer, renderers.TemplateHTMLRenderer]

  def list(self, request, *args, **kwargs):
    queryset = self.filter_queryset(self.get_queryset())

    if request.accepted_renderer.format == "html":
      items = list()

      for item in queryset:
        items.append({"serializer": self.get_serializer(ticket), "item": item})

      return Response(
        {
          "items_info": items,
          "style": {"template_pack": "rest_framework/inline/"},
        },
        template_name="myapp/items_list.html",
      )
    else:
     page = self.paginate_queryset(queryset)
     if page is not None:
       serializer = self.get_serializer(page, many=True)
       return self.get_paginated_response(serializer.data)

      serializer = self.get_serializer(queryset, many=True)

    return Response(serializer.data)

Это проверит, имеет ли запрашивающий URL /? Format = html суффикс .Если это так, он будет сериализовать каждый элемент в наборе запросов и включить список словарей {serializer: item} в словарь (контекст), отправленный на items_list.html.

Для того, чтобы отобразить поле, DRF требуется определен стиль .

Если суффикс формата не является html или не указан, он будет иметь приоритет для средства визуализации JSON или средства просмотра BrowsableAPI ( средства визуализации по умолчанию ).Таким образом, наши API с возможностью просмотра и API-интерфейс JSON по-прежнему легко работают.

Чтобы сделать это с помощью поля buy_by, редактируемого для каждого экземпляра, измените свой шаблон (в данном случае items_list.html) по следующим строкам:

{% load static %}
{% load rest_framework %}

{% if items_info %}
  {% csrf_token %}

  <table id="Items_Table" class="table">
    <thead>
      <tr>
       <th scope="col">Name</th>
       <th scope="col">Active</th>
       <th scope="col">Bought By</th>
      </tr>
    </thead>

    <tbody>
      {% for pair in items_info %}

        <tr scope="row">
          <td>{{ pair.item.name }}</td>
          <td>{{  pair.item.active  }}</td>
          <td>
            <form action="{% url "myapp:item-detail" pair.item.pk %}" method="PATCH">
            {% render_field pair.serializer.bought_by style=style %}
            </form>
          </td>
        </tr>

      {% endfor %}
    </tbody>
  </table>

{% else %}
  <p class="text-center">No items to show.</p>
{% endif %}

Теперь в своем запросе GET просто добавьте "/? Format = html" к URL.

Если вы используете AJAX, при отправке POST / PUT / PATCH / и т.д.запрос включает токен csrf, как описано в документации Django .

...