如何在相关的one_to_many字段上正确使用order_by和nulls_last?

时间:2020-04-28 11:17:40

标签: python django django-models

我正在尝试通过相关模型的存在对对象进行过滤和排序,最后强制为空。

示例模型:

class ModelA(models.Model):
    name = models.CharField(max_length=255)
    ...


class ModelB(models.Model):
    model_a = models.ForeignKey(ModelA, related_name=model_b)
    date = models.DateField()
    time = models.TimeField()
    ...

现在,我需要按某些kwargs(正常操作)过滤ModelA,但是我还需要按最近的ModelB日期和时间(以后,而不是过去)升序或无论使用升序还是降序,都必须使用单个查询参数降序 NULL放在最后

我已经得出结论,我需要覆盖默认的QuerySet order_by:

class ModelAQuerySet(models.QuerySet):
    def order_by(self, *field_names):
        if 'model_a_date' in field_names or '-model_a_date' in field_names:
            field_names = list(field_names)
            if 'model_a_date' in field_names:
                field_names.remove('model_a_date')
                return super().order_by(
                    'model_b__date',
                    'model_b_time',
                    *field_names
                )
            else:
                field_names.remove('-model_a_date')
                return super().order_by(
                    '-model_b__date',
                    '-model_b__time',
                    *field_names
                )
        else:
            return super().order_by(*field_names)

当我对降序('-model_a_date')进行排序时,效果很好,因为NULL是最后一个,但是我很难将空值以升序放置在最后。我已经尝试过:

return super().order_by(
    F('model_b').asc(nulls_last=True),
    'model_b__date',
    'model_b__time',
    *field_names
)

####

return super().order_by(
    F('model_b').asc(nulls_last=True)
).order_by(
    'model_b__date',
    'model_b_time',
    *field_names
)

####

return super().order_by(
    'model_b__date',
    'model_b_time',
    *field_names
).order_by(
    F('model_b').asc(nulls_last=True),
)

但这根本不起作用。在我将order_by连同其他参数一起放入时,或者在上面的order_by之前或之后作为单独的order_by。

有什么想法吗?有没有人碰到过这样的问题?我在这里泡菜,老实说我没主意了。预先感谢。

编辑

我也这样尝试过.union:

ModelA.objects.annotate(
    modelbs=Count('modelb')
).filter(
    modelbs__gt=0
).union(
    ModelA.objects.annotate(
        modelbs=Count('model_b')
    ).filter(
        modelbs=0
    )
)

但这会出现错误:

ORDER BY term does not match any column in the result set.

1 个答案:

答案 0 :(得分:1)

如果您使用链条,则可以:

  • 首先过滤不为null的元素,然后按升序或降序对其进行排序
  • 第二次选择空值
  • 最终,您将能够将您所拥有的qs链式连接(最后为空)并返回

这有意义吗?

相关问题