具有内联模型的Django管理页面加载速度非常慢 [英] Django Admin Page with Inline Model Loads Very Slowly

查看:409
本文介绍了具有内联模型的Django管理页面加载速度非常慢的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个带有单个内联模型的模型的Django管理页面。当内联模型包含许多项(例如75)时,页面加载非常缓慢(大约30秒)。即使我将内联模型上的所有字段都排除在外,让它只是呈现名称也是如此。删除内联模型会导致页面加载非常快(以秒为单位)。

I have a Django admin page for a model with a single inline model. When the inline model has many items (like 75), the page loads very slowly (on the order of 30 seconds). This is true even if I exclude all of the fields on the inline model, having it just render the name. Removing the inline model causes the page to load very quickly (in seconds).

如何使该页面加载更快?

How can I have this page load faster?

推荐答案

您可以执行两项操作来加快此页面的加载速度。

There are two things you can do to speed up the loading of this page.


  1. 设置 DEBUG = False

  2. 缓存用于内联模型呈现的数据库查询。






DEBUG = False



该页面加载缓慢是因为Django管理员正在为内联模型的每个实例渲染一个子模板。使用75个内联模型实例,即使它们中包含的内容很少,您仍将呈现75个额外的模板。虽然渲染模板通常非常快,但是如果您具有 DEBUG = True ,则将为您渲染的每个模板带来额外的开销,因为Django正在为其调试模式错误注入额外的上下文页(这是我系统上每个模板的大约0.4秒)。通常,这种额外的开销不会引起注意,因为您通常只为单个页面呈现少数模板。但是,当渲染75个模板时,这将导致明显的延迟(75 * 0.4秒= 30秒)。


DEBUG = False

The reason that the page loads slowly is that the Django admin is rendering a subtemplate for every instance of the inline model. With 75 instances of the inline model, you are rendering 75 extra templates, even if there is minimal content in them. While rendering a template is normally very fast, if you have DEBUG = True, you incur extra overhead for every template you render because Django is injecting extra context for its debug-mode error page (this is about 0.4 seconds per template on my system). This extra overhead is normally not noticeable because you are normally only rendering a handful of templates for a single page. When you render 75 templates, however, this adds up to a noticeable delay (75 * 0.4 seconds = 30 seconds).

至少从Django 1.10开始,内联模型将进行任何必要的数据库查询,以为每个实例内联模型。如果您的内联模型在内联模型上有任何外键,那么如果您的数据库连接速度很慢,则效率可能非常低。该技术是在初始化内联类的实例(使用 get_formsets_with_inlines )时为这些外键的选择运行数据库查询,然后替换上这些字段的选择。内联缓存值以防止重复此数据库查询(使用 formfield_for_foreignkey )。

At least as of Django 1.10, the inline model will make any necessary database queries to render it for each instance of the inline model. If your inline model has any foreign keys on the inline model, this can pretty inefficient if you have a slow database connection. The technique is to run database queries for the choices of these foreign keys when you initialize the instance of the inline class (using get_formsets_with_inlines), and then replace the choices of these fields on the inline with the cached values to prevent repeating this database query (using formfield_for_foreignkey).

class Manufacturer(models.Model):
    ...

class OperatingSystem(models.Model):
    ...

class Computer(models.Model):
    manufacturer = models.ForeignKey(Manufarturer)
    owner = models.ForeignKey(User)
    operating_system = models.ForeignKey(OperatingSystem)
    ...


class ComputerAdmin(admin.StackedInline):
    model = Computer

    def formfield_for_foreignkey(self, db_field, request, **kwargs):
        field = super(ComputerAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)
        if db_field.name == "owner" and hasattr(self, "cached_owners"):
            field.choices = self.cached_owners
        elif db_field.name == "manufacturer" and hasattr(self, "cached_manufacturers"):
            field.choices = self.cached_manufacturers
        elif db_field.name == "operating_system" and hasattr(self, "cached_operating_systems"):
            field.choices = self.cached_operating_systems
        return field


class ManufacturerAdmin(admin.ModelAdmin):
    inlines = (ComputerAdmin,)

    def get_formsets_with_inlines(self, request, obj=None):
        for inline in self.get_inline_instances(request, obj):
            inline.cached_owners = [(i.pk, str(i)) for i in User.objects.all()]
            inline.cached_manufacturers = [(i.pk, str(i)) for i in Manufacturer.objects.all()]
            inline.cached_operating_systems = [(i.pk, str(i)) for i in OperatingSystem.objects.all()]
            yield inline.get_formset(request, obj), inline

这篇关于具有内联模型的Django管理页面加载速度非常慢的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆