【问题标题】:Reduce Postgresql queries in Django ManyToMany TabularAdminInline减少 Django ManyToMany TabularAdminInline 中的 Postgresql 查询
【发布时间】:2018-01-08 17:52:03
【问题描述】:

我在 Django 的管理界面和 Postgres 中遇到了一些性能问题。我已将其缩小为针对我的 RecipeControl 模型中的每个成分内联执行的查询。配方中存在的成分越多,加载页面所需的时间就越长,因为它似乎想要多次加载成分内联的查询集(几乎 2,000 条记录)。

我确信解决方案是在加载页面之前以某种方式预先缓存查询集,但我对它的工作原理感到困惑,不知道这可能会导致什么样的问题。我研究了prefetch_related vs select_related 之间的区别,并尝试同时使用两者,但两者的性能似乎都没有任何变化。我也found this question,但我使用的是管理界面,而不是编写我自己的视图。那么我应该如何/哪个管理模块正确覆盖以产生预期的效果?感谢您的帮助。

我有一个模型如下:

class RecipeControl(models.Model):
    #recipe_name choice field needs to be a query set of all records containing "FG-Finished Goods"
    recipe_name = models.ForeignKey(items.IngredientList, related_name='recipe_name', limit_choices_to={'category': 'FG'})
    customer_recipe = models.ForeignKey(custmods.CustomerProfile, verbose_name='customer', related_name='customer_recipe')
    ingredients = models.ManyToManyField(items.IngredientList, through='RecipeIngredients')
    active_recipe = models.BooleanField(default=False)
    active_by = models.CharField(max_length=64, editable=False)
    revision = models.IntegerField(default=0)
    last_updated = models.DateTimeField(auto_now_add=True, editable=False)
    mixer_volume = models.DecimalField(verbose_name='Mixer Volume(L)', max_digits=16,decimal_places=3, blank=True, null=True)
    fill_factor = models.DecimalField(verbose_name='Fill %', max_digits=6,decimal_places=2,blank=True,null=True)
    def __str__(self):
        return "%s" % (self.recipe_name)

class RecipeIngredients(models.Model):
    recipe = models.ForeignKey(RecipeControl, related_name='recipe')
    ingredient = models.ForeignKey(items.IngredientList, related_name='ingredient')
    weight_tolerance = models.DecimalField(verbose_name="PPH Tolerance",max_digits=8, decimal_places=3, blank=True, null=False)
    recipe_weight = models.DecimalField(verbose_name="PPH",max_digits=16, decimal_places=3, blank=True, null=True)

    def __str__(self):
        return "%s" % (self.ingredient)

我的 admin.py 文件:

class IngredientInline(admin.TabularInline):
    model = RecipeIngredients
    #prefetch_related = ('ingredient',)
    readonly_fields = ('percentage', 'item_price','ext_price','SPG')
    fieldsets = [(None,{'fields':[('ingredient','item_price','ext_price','SPG','percentage','weight_tolerance','recipe_weight')]})]
    extra = 0
    template = 'admin/recipes/recipeingredients/edit_inline/tabular.html'

class RecipeView(admin.ModelAdmin):
    def save_model(self, request, obj, form, change): 
        obj.active_by = request.user.username
        obj.save()

    list_select_related = ['recipe_name', 'customer_recipe']
    list_display = ['recipe_name','customer_recipe','active_recipe','last_updated','active_by']
    list_display_links = ['recipe_name']
    list_filter = ['active_recipe']
    search_fields = ['recipe_name__name', 'recipe_name__item_code','customer_recipe__name']
    readonly_fields = ('last_updated','active_by','batch_weight','calculated_batch', 'recipe_gravity')

    fieldsets = [
        ('Recipe Information',{'fields': [('recipe_name','customer_recipe','active_recipe')]}),
        ('Audit Trail', {'fields': [('active_by','revision','last_updated')]}),
        ('Batch Weight Info',{'fields': [('batch_weight', 'mixer_volume', 'fill_factor','recipe_gravity', 'calculated_batch')]})
    ]
    inlines = [IngredientInline]

【问题讨论】:

    标签: python django postgresql django-admin


    【解决方案1】:

    UI 并不理想,但最快的解决方法是将raw_id_fields 用于具有多种可能性的任何外键。

    class IngredientInline(admin.TabularInline):
        model = RecipeIngredients
        raw_id_fields = ['ingredients']
    

    如果您需要更好的 UI,可以寻找外部包,例如 django-select2

    【讨论】:

    • 这是可能的解决方案 =D 希望用户同意!下周我将为他们做一个小型演示,并将由他们主持。感谢您的意见!
    • 除了上面 Alasdair 的出色回答之外,我后来通过将 Django 升级到现在支持 Select2 小部件的 v2.0 找到了解决上述问题的一个很好的方法。 Check it out
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-03-25
    • 2011-09-24
    • 1970-01-01
    • 2016-07-10
    • 1970-01-01
    • 2015-06-23
    • 1970-01-01
    相关资源
    最近更新 更多