【问题标题】:Significant performance issue with Django Admin - foreign key labelsDjango Admin 的重大性能问题 - 外键标签
【发布时间】:2019-02-05 23:29:23
【问题描述】:

我在使用 Django Admin 时遇到了严重的性能问题。

我有一个映射模型,我在其中映射其他 2 种模式的主键

在我的 FundManagerMappingAdmin 中,我尝试使用来自外键模型的标签来表示 2 个表的外键。

底层模型约4000行

我在管理员中检索列表时遇到性能缓慢的问题,然后在编辑和更新时也遇到了问题

有人能指出这段代码的低效率吗?

请问有更好的方法吗?

Admin.py

@admin.register(ChampDwDimFundManagerMapping)
class FundManagerMappingAdmin(admin.ModelAdmin):

list_display = ['get_champ_fund_manager_id', 'get_evestment_name', 'get_sharepoint_name', ]

def get_champ_fund_manager_id(self, obj):
    return obj.fund_manager_id
get_champ_fund_manager_id.short_description = 'CHAMP Manager ID'

def get_evestment_name(self, obj):
    return obj.evestment_fund_manager_id.manager_name
get_evestment_name.short_description = 'Evestment Manager Name'

def get_sharepoint_name(self, obj):
    return obj.sharepoint_fund_manager_id.manager_name
get_sharepoint_name.short_description = 'Sharepoint Manager Name'

def get_form(self, request, obj=None, **kwargs):
    form = super(ChampFundManagerMappingAdmin, self).get_form(request, obj, **kwargs)
    form.base_fields['sharepoint_fund_manager_id'].label_from_instance = lambda obj: "{} {}".format(obj.final_publications_fund_manager_id, obj.manager_name)
    form.base_fields['evestment_fund_manager_id'].label_from_instance = lambda obj: "{} {}".format(obj.evestment_fundmanager_id_bk, obj.manager_name)
    return form

Models.py

class FundManagerMapping(models.Model):
    fund_manager_id = models.AutoField(db_column='FundManagerId', primary_key=True)  
    sharepoint_fund_manager_id = models.ForeignKey(SharePointFundManager, models.DO_NOTHING, db_column='SharePointFundManagerId')  
    evestment_fund_manager_id = models.ForeignKey(EvestmentFundManager, models.DO_NOTHING, db_column='eVestmentFundManagerId')  

class EvestmentFundManager(models.Model):
    evestment_fund_manager_id = models.AutoField(db_column='eVestmentFundManagerId', primary_key=True)  
    package_execution_id = models.IntegerField(db_column='PackageExecutionId')  
    evestment_fund_manager_id_bk = models.CharField(db_column='eVestmentFundManagerId_BK', max_length=50)  
    manager_name = models.CharField(db_column='ManagerName', max_length=255)  

class SharePointFundManager(models.Model):
    sharepoint_fund_manager_id = models.AutoField(db_column='SharePointFundManagerId', primary_key=True)  
    package_execution_id = models.IntegerField(db_column='PackageExecutionId')  
    research_fund_manager_id = models.CharField(db_column='ResearchFundManagerId', max_length=50, blank=True, null=True)  
    final_publications_fund_manager_id = models.CharField(db_column='FinalPublicationsFundManagerId', max_length=50, blank=True, null=True)  
    manager_name = models.CharField(db_column='ManagerName', max_length=255)  

【问题讨论】:

    标签: python django django-models django-admin


    【解决方案1】:

    您正在显示相关实体的name(因为get_evestment_nameget_sharepoint_name),而无需加入/预取它们。这意味着对于您显示的每一行以及相关实体的每个名称,它都需要 django 进行数据库查询。您需要覆盖 ModelAdminget_queryset() 并使用 select_related 告诉 django 从一开始就加入这些实体,这样它就不需要任何额外的查询来获取这些名称:

    @admin.register(ChampDwDimFundManagerMapping)
    class FundManagerMappingAdmin(admin.ModelAdmin):
        def get_queryset(self, request):
            return super().get_queryset(request).select_related(
                'sharepoint_fund_manager_id', 
                'evestment_fund_manager_id',
            )
    

    您也没有将ForeignKey 字段命名为something_id。它只是sharepoint_fund_manager,因为当你调用fund_manager.sharepoint_fund_manager_id 时得到的不是一个id,而是SharePointFundManager 的一个实例。打电话给sharepoint_fund_manager_id.name 很奇怪。 id 没有 name 属性。一位基金经理。

    此外,如果您调用字段sharepoint_fund_manager 来访问普通外键,Django 会自动为您创建一个属性sharepoint_fund_manager_id

    【讨论】:

    • 感谢推出了推荐的更改和设计缺陷并且运行良好,注意到性能改进
    • @RachOdwyer 很高兴它有帮助。如果你想调试某个视图是否产生重复或相似的查询,你可以安装Django Debug Toolbar。这是一个小工具,可帮助您检查浏览器中的不同指标,其中包括向您显示正在执行的每个查询并突出显示重复项。
    猜你喜欢
    • 1970-01-01
    • 2013-09-13
    • 2010-11-23
    • 1970-01-01
    • 2012-11-28
    • 1970-01-01
    • 2011-01-23
    • 2011-02-01
    相关资源
    最近更新 更多