注释来自过滤的相关对象的值——案例、子查询或其他方法?

时间:2021-03-13 20:47:51

标签: django django-models django-queryset

我在 Django 中有一些模型:

# models.py, simplified here
class Category(models.Model):
    """The category an inventory item belongs to.  Examples: car, truck, airplane"""
    name = models.CharField(max_length=255)

class UserInterestCategory(models.Model):
    """
    How interested is a user in a given category.  `interest` can be set by any method, maybe a neural network or something like that
    """
    user = models.ForeignKey(User, on_delete=models.CASCADE) # user is the stock Django user
    category = models.ForeignKey(Category, on_delete=models.CASCADE)
    interest = models.PositiveIntegerField(default=0, validators=[MinValueValidator(0)])

class Item(models.Model):
    """This is a product that we have in stock, which we are trying to get a User to buy"""
    model_number = models.CharField(max_length=40, default="New inventory item")
    product_category = models.ForeignKey(Category, null=True, blank=True, on_delete=models.SET_NULL, verbose_name="Category")

我有一个显示项目的列表视图,我正在尝试按 user_interest_category 为当前登录的用户排序。

我尝试了几个不同的查询集,但我对它们并不满意:

primary_queryset = Item.objects.all()

# this one works, and it's fast, but only finds items the users ALREADY has an interest in -- 
primary_queryset = primary_queryset.filter(product_category__userinterestcategory__user=self.request.user).annotate(
recommended = F('product_category__userinterestcategory__interest')
)

# this one works great but the baby jesus weeps at its slowness
# probably because we are iterating through every user, item, and userinterestcategory in the db
primary_queryset = primary_queryset.annotate(
    recommended = Case(
        When(product_category__userinterestcategory__user=self.request.user, then=F('product_category__userinterestcategory__interest')),
        default=Value(0),
        output_field=IntegerField(),
        )
    )

# this one works, but it's still a bit slow -- 2-3 seconds per query:
interest = Subquery(UserInterestCategory.objects.filter(category=OuterRef('product_category'), user=self.request.user).values('interest'))
            primary_queryset = primary_queryset.annotate(interest)

第三种方法可行,但它似乎不是最有效的做事方式。没有比这更好的方法了吗?

0 个答案:

没有答案
相关问题