0

Я использую версию django rest framework 3.3.2.Отключение выбора на Связанном объекте rest_framework

Мы используем HyperlinkedRelatedField в сотнях разных мест, и моя проблема в том, что это наследует метод choices через RelatedField, который выполняет следующие действия:

class RelatedField(Field): 

    ... 

    @property 
    def choices(self): 
     queryset = self.get_queryset() 
     if queryset is None: 
      # Ensure that field.choices returns something sensible 
      # even when accessed with a read-only field. 
      return {} 

     return OrderedDict([ 
      (
       six.text_type(self.to_representation(item)), 
       self.display_value(item) 
      ) 
      for item in queryset 
     ]) 

Это QuerySet есть отношение к другому столу, и могут содержать сотни из тысяч строк. Запрос OPTIONS на api теперь потребляет всю доступную память, поскольку он пытается сгенерировать ответ json для доступных вариантов отношения. Несмотря на то, что опция html_cutoff обрезает это число до 1000, проблема остается, потому что набор запросов уже был использован до того, как он будет ограничен отсечением.

Я ищу неинтрузивный способ отключить перечисление вариантов по внешним ключам. Я хотел бы избежать создания настраиваемого класса полей, если это возможно, есть ли способ повлиять на это поведение через остальную структуру api? Мне вообще не нужно видеть choices в ответе параметров.

ответ

2

В текущем DRF (v3.3.2) есть this problem, ответ OPTIONS пытается оценить «выбор» для внешних ключей. Это ужасная идея и делает API-интерфейс, доступный для просмотра, непригодным для использования, если у вас есть нетривиальное количество контента в вашей базе данных.

Хранители DRF знают об этом и there is a PR currently scheduled for the 3.4.0 release для решения проблемы.

До тех пор, пока он не будет установлен вверх, это мое обходное решение. Примечание: чтобы отменить поведение, вам необходимо установить DEFAULT_METADATA_CLASS под параметрами REST_FRAMEWORK в settings.py.

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

from copy import copy 
from functools import wraps 

from rest_framework.metadata import SimpleMetadata 
from rest_framework.relations import RelatedField 


class MyMetadata(SimpleMetadata): 

    def get_field_info(self, field): 

     if isinstance(field, RelatedField): 
      def kill_queryset(f): 
       @wraps(f) 
       def wrapped(*args, **kwargs): 
        qs = f(*args, **kwargs) 
        if qs is not None: 
         qs = qs.none() 
        return qs 
       return wrapped 

      field = copy(field) 
      field.get_queryset = kill_queryset(field.get_queryset) 

     result = super(MyMetadata, self).get_field_info(field) 

     if not result.get('choices'): 
      result.pop('choices', None) 
0

Вы можете изменить содержимое любого запроса OPTIONS в рамках Django REST с помощью API метаданных.

Это включает определение собственного класса метаданных - см. this documentation page.

Вы можете добавить свой собственный класс метаданных в представление, вызывающее проблемы.

+0

Действительно, я рассматриваю пользовательский класс метаданных как возможно лучшее место для атаки этого. Но, похоже, нет подходящего метода для переопределения для него, последний шанс перед тем, как перейти к сериализатору, и поля находятся в 'get_field_info' (что делает много других важных вещей). – wim

+0

@wim Я создал новый класс метаданных, который перегружает 'get_field_info'. Я начал с 'SimpleMetadata.get_field_info' в качестве шаблона. Я знаю, что это не супер чисто, но это единственный способ найти! – Kieran

+0

Если вы используете 'SimpleMetadata.get_field_info', то вы уже потребляли запрос, так что это не хорошо .. – wim