我的API中有一个模型,它有一个包含数万条记录的表的外键。当我在可浏览的UI中浏览到该模型的详细信息页面时,页面加载将永远占用,因为它正在尝试使用PUT命令的HTML表单的数万个条目填充外键下拉列表。
有没有解决这个问题?我认为我最好的解决方案是让可浏览的UI不显示此字段,从而防止缓慢加载。人们仍然可以通过实际的PUT api请求直接更新字段。
感谢。
答案 0 :(得分:4)
查看使用自动填充小部件,或者使用简单的文本字段小部件。
此处的自动填充文档:http://www.django-rest-framework.org/topics/browsable-api/#autocomplete
答案 1 :(得分:1)
您可以使用简单的强制使用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 this part of documentation返回的结果。
答案 2 :(得分:1)
请注意,您可以禁用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中发布。
答案 3 :(得分:0)
这是一个很好的问题,没有明显的问题。您在学习Django时会迷上的错误假设,以及在阅读官方文档时与之相关的插件DRF的错误假设,将创建一个概念模型,但这并不是真的。我在这里谈论的是,Django是为关系数据库显式设计的,并不能立即使用!
在ORM世界中查询包含关系(例如一对多)的模型时,Django / DRF变慢的原因被称为 N + 1问题(N+1,N+1),当ORM使用lazy loading时,它的特殊性很明显-Django使用延迟加载!!!
我们假设您的模型如下所示:阅读器具有许多书籍。现在,您想获取所有由'hardcore'读者阅读的书籍'title'。在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中看起来与此类似。
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变慢的结果!
解决方案很简单,但并不明显。遵循Django或DRF的官方文档并不能突出问题。最后,您将遵循最佳实践,最终会导致应用缓慢。
要解决加载缓慢的问题,您将必须eager load在Django中使用数据。通常,这意味着使用适当的prefetch_related()或select_related()方法在模型/表上构造SQL INNER JOIN
,并仅在2个查询中而不是101中获取所有数据。