title: Reduce Postgresql queries in Django ManyToMany TabularAdminInline
body: <p>I'm experiencing some performance issues within Django's Admin interface &amp; Postgres. I've narrowed it down to a query that's preformed for each IngredientInline in my RecipeControl model. The more ingredients that exist within a Recipe the longer the page takes to load because is seems to want to load the queryset (Almost 2,000 records) for the IngredientInline multiple times.</p>
  
  <p>I'm convinced the solution is to somehow pre-cache the queryset prior to loading the page, but I'm confused at how this works and don't know what kind of problems this could cause down the road. I've looked into the difference between <a href="https://stackoverflow.com/questions/31237042/whats-the-difference-between-select-related-and-prefetch-related-in-django-orm">prefetch_related vs select_related</a> and have tried to use both but there doesn't seem to be any change in performance when doing either. I <a href="https://stackoverflow.com/questions/1694537/reducing-queries-for-manytomany-models-in-django">found this question</a> also but I'm using the admin interface, not writing my own view. So how/which admin module do I properly override to produce the desired effect? Thanks for any help.</p>
  
  <p>I have a model as follows:</p>
  
  <pre><code>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)
  </code></pre>
  
  <p>My admin.py file:</p>
  
  <pre><code>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]
  </code></pre>