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

#python #django #django-rest-framework #django-forms #django-templates

#python #django #django-rest-framework #django-forms #django-шаблоны

Вопрос:

При отображении таблицы элементов, если значение для поля X не определено, оно отображается как элемент выбора.

Django выполняет запрос для каждого выбранного элемента, и они могут накапливаться и вызывать задержки в больших таблицах.

Каков наилучший способ уменьшить количество запросов?

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(item), "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)
  

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="{{ item.url }}" 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 %}
  

Если есть три элемента, для каждого будет сделано по одному запросу, чтобы получить serializer.bought_by. Я думал, что Django / DRF просто повторно использует значение, но оно запрашивает для каждого цикла.

Пытаясь передать "serializer-bought-by": self.get_serializer().bought_by в ответ, я получаю AttributeError: 'ItemSerializer' object has no attribute'bought_by'

Печать сериализатора, который я вижу:

 >>>print(self.get_serializer())
ItemSerializer(context={'request': <rest_framework.request.Request object>, 'format': None, 'view': <myapp.views.ItemViewSet object>}):
    url = HyperlinkedIdentityField(view_name='myapp:item-detail')
    name= CharField(unique=True, max_length=50)
    active = BooleanField(required=False)
    bought_by = SlugRelatedField(allow_null=True, queryset=<QuerySet [<Buyer: James>, <Buyer: John>, ...]>, required=False, slug_field='name')
  

Есть ли способ передать bught_by в шаблон?
Или я должен использовать JS; отображать поле формы вне цикла и каким-то образом клонировать / дублировать?

—Правки—

Согласно запросу Endre: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",)
  

Ответ №1:

Вы не можете получить доступ к значению полей непосредственно в сериализаторе. Вместо этого вы должны использовать serializer.data['bought_by'] . Лучше не передавать сериализатор шаблону, вместо этого передайте serializer.data . Что касается запросов в шаблоне, запрос к БД не выполняется для получения bought_by , поскольку он уже включен в данные сериализатора. Вы просто показываете одно имя поля из bought_by , которое уже предварительно загружено в данные сериализатора. select_related Примененное вами также гарантирует, что несколько запросов не будут выполнены для извлечения bought_by во время сериализации.

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

1. Извините, мой первоначальный вопрос содержал нерабочий код из более ранней версии. Если я использую serializer.data, я получаю сообщение AttributeError: "noneType" object has no atribute '_field' Проблема не в товарах, где покупатель уже определен, а в тех, у которых его нет. Мне нужен HTML select, который позволил бы пользователю определить его.

2. Это трудно понять только из этого комментария. Опубликуйте новый вопрос с подробным описанием новой проблемы