0

我正在使用django rest 框架版本 3.3.2。

我们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
        ])

该查询集是与另一个表的关系,并且可以包含数十万行。对 api 的 OPTIONS 请求现在会消耗所有可用内存,因为它会尝试为关系的可用选择生成 json 响应。即使html_cutoff选项将此数字截断为 1000,问题仍然存在,因为查询集在被截断限制之前已经被使用。

我正在寻找一种非侵入式方法来禁用外键上的选择枚举。我想避免创建自定义字段类,如果可能的话,有没有办法通过其余框架 api 影响这种行为?我根本不需要choices在选项响应中看到。

4

2 回答 2

3

在当前的 DRF (v3.3.2) 中存在这个问题,OPTIONS 响应尝试评估外键的“选择”。这是一个糟糕的想法,如果您的数据库中有大量内容,那么可浏览的 API 将无法使用。

DRF 维护人员意识到了这一事实,目前计划在 3.4.0 版本中进行 PR以解决该问题。

在上游修复之前,这是我的解决方法。 注意:要覆盖该行为,您需要DEFAULT_METADATA_CLASS在. REST_FRAMEWORKsettings.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)
于 2016-02-26T21:49:13.893 回答
0

OPTIONS您可以使用元数据 API 在 Django REST 框架中修改任何请求的内容。

这涉及定义您自己的元数据类 - 请参阅此文档页面

您可以将自定义元数据类添加到导致问题的视图中。

于 2016-02-22T22:20:05.467 回答