8

我的 API 中有一个模型,该模型具有指向包含数万条记录的表的外键。当我在可浏览的 UI 中浏览到该模型的详细信息页面时,页面加载需要很长时间,因为它试图用 PUT 命令的 HTML 表单的数万个条目填充外键下拉列表。

有没有办法解决这个问题?我认为我最好的解决方案是让可浏览的 UI 不显示此字段,从而防止加载缓慢。人们仍然可以通过实际的 PUT api 请求直接更新该字段。

谢谢。

4

5 回答 5

4

看看使用自动完成小部件,或下拉到使用哑文本字段小部件。

此处的自动完成文档:http: //www.django-rest-framework.org/topics/browsable-api/#autocomplete

于 2013-09-03T10:08:04.783 回答
4

请注意,您可以禁用 HTML 表单并保留原始数据 json 条目:

class BrowsableAPIRendererWithoutForms(BrowsableAPIRenderer):
    """Renders the browsable api, but excludes the forms."""
    def get_rendered_html_form(self, data, view, method, request):
        return None

在 settings.py 中:

REST_FRAMEWORK = {
    'DEFAULT_RENDERER_CLASSES': (
        'rest_framework.renderers.JSONRenderer',
        'application.api.renderers.BrowsableAPIRendererWithoutForms',
    ),
}

这将加快速度,您仍然可以从可浏览的 ui 中发布。

于 2018-07-13T23:24:14.933 回答
3

您可以通过简单的方式强制使用 TextInput:

from django.forms import widgets
...
class YourSerializer(serializers.ModelSerializer):
    param = serializers.PrimaryKeyRelatedField(
        widget=widgets.TextInput
    )

或者在正确的 autocomplete_light 配置之后:

import autocomplete_light
...
class YourSerializer(serializers.ModelSerializer):
    paramOne = serializers.PrimaryKeyRelatedField(
        widget=autocomplete_light.ChoiceWidget('RelatedModelAutocomplete')
    )
    paramMany = serializers.PrimaryKeyRelatedField(
        widget=autocomplete_light.MultipleChoiceWidget('RelatedModelAutocomplete')
    )

过滤掉 autocomplete_light 返回的结果,这部分文档

于 2013-10-04T23:18:21.083 回答
0

DRF 文档中有一个部分给出了以下建议:

author = serializers.HyperlinkedRelatedField(
    queryset=User.objects.all(),
    style={'base_template': 'input.html'}
)

如果文本字段太简单,正如@Chozabu在我写这个答案之前很久之前在评论中提到的那样,他们建议在 HTML 模板中手动添加自动完成:

另一种但更复杂的选择是将输入替换为自动完成小部件,该小部件仅根据需要加载和呈现可用选项的子集。如果你需要这样做,你需要自己做一些工作来构建一个自定义的自动完成 HTML 模板。

有多种用于自动完成小部件的包,例如 django-autocomplete-light,您可能需要参考。请注意,您不能简单地将这些组件作为标准小部件包含在内,而是需要显式编写 HTML 模板。这是因为 REST framework 3.0 不再支持 widget 关键字参数,因为它现在使用模板化 HTML 生成。

于 2022-02-15T05:22:46.510 回答
-1

对于没有明显问题的问题,这是一个非常好的问题。您在学习 Django 时陷入的错误假设,以及在阅读官方文档时与它相关的插件DRF,将创建一个根本不正确的概念模型。我在这里谈论的是,Django 明确地为关系数据库设计,并不能让它开箱即用!

问题

Django/DRF 在ORM世界中查询包含关系(例如一对多)的模型时速度慢的原因被称为N+1 问题N+1N+1),并且在 ORM 使用惰性时特别明显加载- Django 使用延迟加载!

例子

假设您有一个看起来像这样的模型:一个Reader有很多Books。现在,您想获取“硬核”阅读器阅读的所有书籍“标题”。在 Django 中,您可以通过以这种方式与 ORM 交互来执行此操作。

# First Query: Assume this one query returns 100 readers.
> readers = Reader.objects.filter(type='hardcore')

# Constitutive Queries
> titles = [reader.book.title for reader in readers]

在引擎盖下。第一条语句Reader.objects.filter(type='hardcore')将创建一个看起来与此类似的 SQL 查询。我们假设它将返回 100 条记录。

SELECT * FROM "reader" WHERE "reader"."type" = "hardcore";

接下来,您将为每个读者[reader.book.title for reader in readers]获取相关书籍。SQL 中的 this 看起来与此类似。

SELECT * FROM "book" WHERE "book"."id" = 1;
SELECT * FROM "book" WHERE "book"."id" = 2;
...
SELECT * FROM "book" WHERE "book"."id" = N;

您留下的是,1选择获取 100 位读者,N选择获取书籍 -其中N是书籍数量。因此,您总共有N+1 个针对数据库的查询。

这种行为的后果是对数据库进行101次查询,最终导致少量数据的加载时间极长,并使 Django 变慢!

解决方案

解决方案很简单,但并不明显。遵循DjangoDRF的官方文档并没有突出问题。最后,您遵循最佳实践,最终应用程序缓慢。

要解决加载缓慢的问题,您必须在 Django中急切地加载数据。通常,这意味着使用适当的prefetch_related()select_related()方法INNER JOIN在模型/表上构造 SQL,并仅在 2 个查询而不是 101 个查询中获取所有数据。

相关阅读

于 2019-03-27T13:57:16.240 回答