【问题标题】:Sorting products after dateinterval and weight按日期间隔和重量对产品进行排序
【发布时间】:2009-12-13 01:12:31
【问题描述】:

我想要的是能够获得这几周/这几个月/这几年等最热门的产品。所以我有一个名为ProductStatistics 的模型,它将记录每天的每次点击和每次购买。这是我必须使用的模型:

class Product(models.Model):
    name            = models.CharField(_("Name"), max_length=200)
    slug            = models.SlugField()
    description     = models.TextField(_("Description"))

    picture         = models.ImageField(upload_to=product_upload_path, blank=True)

    category        = models.ForeignKey(ProductCategory)

    prices          = models.ManyToManyField(Store, through='Pricing')

    objects         = ProductManager()

    class Meta:
        ordering = ('name', )

    def __unicode__(self):
        return self.name

class ProductStatistic(models.Model):
    # There is only 1 `date` each day. `date` is
    # set by datetime.today().date()
    date            = models.DateTimeField(default=datetime.now)
    hits            = models.PositiveIntegerField(default=0)
    purchases       = models.PositiveIntegerField(default=0)

    product         = models.ForeignKey(Product)

    class Meta:
        ordering = ('product', 'date', 'purchases', 'hits', )

    def __unicode__(self):
        return u'%s: %s - %s hits, %s purchases' % (self.product.name, str(self.date).split(' ')[0], self.hits, self.purchases)

在最近一周(hits+(purchases*2)) 之后,您将如何对产品进行排序?

这个结构也不是一成不变的,所以如果你想以任何其他方式构建模型,请告诉!

【问题讨论】:

    标签: django django-models django-orm


    【解决方案1】:

    第一个想法:

    在视图中,您可以查询今天的ProductStatistic,然后遍历查询集并将变量ranking 添加到每个对象并将该对象添加到列表中。然后在ranking 之后排序并将列表传递给你的模板。

    第二个想法:

    创建一个归档ranking(对管理员隐藏)并在每次使用pre_save-signal 将对象保存到数据库时编写您的公式的解决方案。现在你可以做ProductStatistic.objects.filter(date=today()).order_by('ranking')

    这两种想法各有利弊,但我更喜欢第二种想法

    编辑作为对评论的回应

    • 使用想法 2

    • 编写一个视图,在其中过滤如下:ProductStatistic.objects.filter(product= aProductObject, date__gte=startdate, date__lte=enddate)

      遍历查询集并执行类似aProductObject.ranking+= qs_obj.ranking的操作

    • 将查询集的排序列表传递给模板

    基本上是两种想法的结合

    编辑成你自己的answer

    您的解决方案与我的建议相距不远——但在 sql-space 中。

    但另一种解决方案:

    制作热门模型:

    class Hit(models.Model):
        date = models.DateTimeFiles(auto_now=True)
        product = models.ForeignKey(Product)
        purchased= models.BooleanField(default=False)
        session = models.CharField(max_length=40)
    

    在您的视图中显示您检查的产品,如果会话中存在 Hit 对象,以及对象。如果没有,你保存它

    Hit(product=product,
        date=datetime.datetime.now(),
        session=request.session.session_key).save()
    

    在您的购买视图中,您将获得 Hit-object 并设置 purchased=True

    现在您可以在您的模板/DB-Tools 中进行真正的统计。

    当然,随着时间的推移,它会生成大量的 DB-Object,所以你应该考虑一个好的删除策略(比如将 3 个月后的数据相加到另一个模型MonthlyHitArchive

    如果您认为显示此统计信息会产生大量 DB-Traffic,您应该考虑使用一些缓存。

    【讨论】:

    • 问题是 ProductStatistics 每周会返回 7 个对象,我想要这个的总和,并且基本上按它来订购 Products。我猜我将不得不为此使用原始 SQL 或 .extra() 。但我不知道怎么做,因为我不太擅长 SQL。
    【解决方案2】:

    我以我不想解决的方式解决了这个问题。我将week_rankmonth_rankoverall_rank 添加到Product,然后将以下内容添加到我的ProductStatistic 模型中。

    def calculate_rank(self, days_ago=7, overall=False):
        if overall:
            return self._default_manager.all().extra(
                select = {'rank': 'SUM(hits + (clicks * 2))'}
            ).values()[0]['rank']
        else:
            return self._default_manager.filter(
                date__gte = datetime.today()-timedelta(days_ago),
                date__lte = datetime.today()
            ).extra(
                select = {'rank': 'SUM(hits + (clicks * 2))'}
            ).values()[0]['rank']
    
    def save(self, *args, **kwargs):
        super(ProductStatistic, self).save(*args, **kwargs)
        t = Product.objects.get(pk=self.product.id)
        t.week_rank = self.calculate_rank()
        t.month_rank = self.calculate_rank(30)
        t.overall_rank = self.calculate_rank(overall=True)
        t.save()
    

    如果有更好的解决方案,我将不解决。

    【讨论】:

      猜你喜欢
      • 2011-08-21
      • 2021-11-02
      • 1970-01-01
      • 1970-01-01
      • 2022-01-14
      • 2020-03-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多