英文:
Django Admin select_related issue
问题
I'm trying to select_related for a bunch of assets in the Django admin.
These assets are tied to a product, which in turn has a separate Company and Category model. These are both a foreign key from the product to the respective model.
I defined the string method like so in the Product class:
def __str__(self):
    if self.company:
        return f"{self.category.name} | {self.company.name} | {self.name}"
    return f"{self.category.name} | {self.name}"
However, when I check the debug toolbar in the Django admin, I see that a bunch of extra queries are made because of this.
products\models.py in __str__(53)
  return f"{self.category.name} | {self.company.name} | {self.name}"
I have the following get_queryset method defined in the ModelAdmin:
def get_queryset(self, request):
    qs = super().get_queryset(request).select_related(
        'product', 
        'product__category', 
        'product__company')
    if request.user.is_superuser or request user.is_staff:
        return qs
    return qs.filter(user=request.user)
Is there a fix for this? Am I doing it wrong?
Edit*
I have narrowed down the issue to Django admin's list filter.
The list_filter allows filtering by product, which in turn displays its __str__ method.
I have decided to just remove the product from the list filter.
Would still be nice to have a fix provided for any future visitors.
英文:
I'm trying to select_related for a bunch of assets in the Django admin.
These assets are tied to a product, which in turn has a separate Company and Category model. These are both a foreign key from product, to the respective model.
I defined the string method like so in the Product class:
def __str__(self):
    if self.company:
        return f"{self.category.name} | {self.company.name} | {self.name}"
    return f"{self.category.name} | {self.name}"
However, when I check debug toolbar in the Django admin, I see that a bunch of extra queries are made because of this.
products\models.py in __str__(53)
  return f"{self.category.name} | {self.company.name} | {self.name}"
I have the following get_queryset method defined in the ModelAdmin:
def get_queryset(self, request):
    qs = super().get_queryset(request).select_related(
        'product', 
        'product__category', 
        'product__company')
    if request.user.is_superuser or request.user.is_staff:
        return qs
    return qs.filter(user=request.user)
Is there a fix for this? Am I doing it wrong?
Edit*
I have narrowed down the issue to Django admin's list filter.
The list_filter allows filtering by product, which in turn displays it's __str__ method.
I have decided to just remove the product from the list filter.
Would still be nice to have a fix provided for any future visitors.
答案1
得分: 1
你可以使用 prefetch_related 替代 select_related,因为它比 select_related 更灵活,可以用来预取任何深度级别的相关字段,如下所示:
def get_queryset(self, request):
    qs = super().get_queryset(request).prefetch_related(
        'product',
        'product__category',
        'product__company')
    if request.user.is_superuser or request.user.is_staff:
        return qs
    return qs.filter(user=request.user)
英文:
You can use prefetch_related instead of select_related as it is more versatile than select_related and can be used to prefetch related fields at any level of depth so:
def get_queryset(self, request):
    qs = super().get_queryset(request).prefetch_related(
        'product', 
        'product__category', 
        'product__company')
    if request.user.is_superuser or request.user.is_staff:
        return qs
    return qs.filter(user=request.user)
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。


评论