【问题标题】:Django Admin Page with Inline Model Loads Very Slowly带有内联模型的 Django 管理页面加载非常缓慢
【发布时间】:2017-09-24 05:12:23
【问题描述】:

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

如何让这个页面加载得更快?

【问题讨论】:

标签: django django-admin


【解决方案1】:

您可以做两件事来加快此页面的加载速度。

  1. 设置DEBUG = False
  2. 缓存用于渲染内联模型的数据库查询。

调试 = 假

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


缓存数据库查询

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

【讨论】:

  • 我利用这个解决方案来加快我的内联速度,但现在我遇到了内联元素没有在选择中显示它们的实际值的问题。我有一个模型:Serial_Roll,它有很多标签。每个标签都有重量、风味和状态。 (这些都是外键)每卷有 1000 多个标签。我希望我的内联显示每个 FK 的当前值,但在选择列表中还有其他选择。我需要改变这个吗?
  • @AndyPoquette 所有这些都是覆盖内联 FK 的选择。它应该保留选择当前值。如果我在发布的解决方案中有错误,请告诉我
  • 我确定不是你,而是我。我为我的问题选择了不同的解决方案,但谢谢!
  • @AndyPoquette 其他解决方案是什么?
【解决方案2】:

在这里查看我的解决方案:https://stackoverflow.com/a/51391915/1496567

我的管理类如下所示:

class ItemBazarInlineAdmin(AdminInlineWithSelectRelated):
    model = ItemBazar

    list_select_related = (
        'alumno_item__alumno__estudiante__profile',
        'alumno_item__item__anio_lectivo',
        'comprobante__forma_pago',
    )


class ComprobanteAdmin(AdminWithSelectRelated):
    list_display = ('__str__', 'total', 'estado', 'fecha_generado', 'forma_pago', 'tipo', )
    list_filter = ('estado', 'forma_pago', )

    list_select_related = ('forma_pago', )
    inlines = (ItemServicioInlineAdmin, )

【讨论】:

    猜你喜欢
    • 2023-04-01
    • 1970-01-01
    • 2021-04-11
    • 1970-01-01
    • 2016-04-03
    • 2018-07-15
    • 1970-01-01
    • 2016-06-30
    • 2014-01-11
    相关资源
    最近更新 更多