Django 管理界面 select_related 问题

huangapple go评论62阅读模式
英文:

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)

huangapple
  • 本文由 发表于 2023年2月14日 01:16:47
  • 转载请务必保留本文链接:https://go.coder-hub.com/75439152.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定