Django queryset自定义顺序,指定位置上有一些对象

时间:2018-04-23 09:27:01

标签: python django django-models django-queryset

我有模特:

class Article(models.Model):
    site = models.ForeignKey('Site')
    published_at = models.DateTimeField(_('Published at'))
    promoted = models.BooleanField(_('Promoted'))
    position = models.PositiveSmallIntegerField(
        _('Position'),
        null=True,
        blank=True,
    )
    valid_from = models.DateTimeField(_('Valid from'))
    valid_to = models.DateTimeField(_('Valid to'))
    // (...)

我希望查询集在指定的时间范围内具有某些对象的指定位置。其余部分应按published日期订购。

我这样做的方式现在有效,但速度慢且效率不高,这是一个问题,因为我想在主页上使用它。

def get_articles_list(site):
    articles = Article.objects.filter(
        site=site,
        published_at__lte=now(),
    ).order_by(
        '-published_at',
    )

    promoted_articles = Article.objects.filter(
        site=site,
        promoted=True,
        valid_from__lte=now(),
        valid_to__gte=now(),  
        position__isull=False,
    )

    // create a list with no promoted articles on it (to avoid duplicates)
    articles_list = list(articles.exclude(id__in=promoted_articles))

    // put promoted articles on the specific positions of the list
    if promoted_articles:
        for promoted in promoted_articles:
            articles_list.insert(promoted.position - 1, promoted)
    return articles_list

有没有办法优化流程?

更新

例如,我有五个Article个对象:

article_1
    site: 1
    published_at: 2018-04-01
    promoted: True
    position: 4
    valid_from: 2018-04-01
    valid_to: <tomorrow>
article_2
    site: 1
    published_at: 2018-04-02 
    promoted: False
    position: -
    valid_from: -
    valid_to: -
article_3
    site: 1
    published_at: 2018-04-03 
    promoted: False
    position: -
    valid_from: -
    valid_to: -
article_4
    site: 1
    published_at: 2018-04-04 
    promoted: False
    position: -
    valid_from: -
    valid_to: -
article_5
    site: 1
    published_at: 2018-04-05
    promoted: True
    position: 2
    valid_from: 2018-04-05
    valid_to: <tomorrow>

我想要达到的顺序是: [article_4, article_5, article_3, article_1, article_2]

3 个答案:

答案 0 :(得分:1)

我建议你添加一些中间件方法,根据一些自定义逻辑计算每个条目的权重 - 你需要定义什么参数将使列表前面的条目更加提升,哪些是中性的。

我认为这就是(或多或少)像Algolia这样的搜索服务(或者只是他们功能的一部分)的工作方式,在这里你可以定义什么样的分数&#39;乘数有你数据库中的一些参数。

(抱歉没有实际的Python代码,但我不是每天都使用它 - 只是想帮助解决一般的解决方案概念)

答案 1 :(得分:0)

尝试这样的事情:

from django.db.models import Q


filters = Q(published_at_lte=now(), promoted=False)
filters.add(
    Q(promoted=True,
      valid_from__lte=now(),
      valid_to__gte=now(),  
      position__isnull=False),
    Q.OR
)

articles = (
    Article.objects
    .filter(site=site)
    .filter(filters)
    .order_by(
        '-promoted',
        'position',
        '-published_at'
    )
)

答案 2 :(得分:0)

首先获取promoted,然后按降序排列published_at

Article.objects.filter(site=site).order_by('promoted', 'position', '-published_at')

https://docs.djangoproject.com/en/2.0/ref/models/querysets/#order-by