简体   繁体   English

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

[英]How to properly use order_by with nulls_last on a related one_to_many field?

I'm trying to filter and order objects by existance of a related model with forcing nulls as last.我正在尝试通过相关 model 的存在来过滤和排序对象,最后强制为空。

Example 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()
    ...

Now, I need to filter ModelA by some kwargs (normal operations), but I also need to order ModelA by nearest ModelB date and time (in future, not past) ascending or descending WITH A SINGLE QUERY PARAM and also NULLS need to be placed last regardless of ascending or descending order.现在,我需要通过一些 kwargs(正常操作)过滤 ModelA,但我还需要通过最近的 ModelB 日期和时间(将来,而不是过去)对 ModelA 进行排序,使用单个查询参数升序或降序,还需要放置 NULL最后不管升序还是降序。

I already came to a conclusion that I need to overwrite default QuerySet order_by:我已经得出结论,我需要覆盖默认的 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)

It works fine when I'm ordering descending ( '-model_a_date' ), since NULLS are last, but I'm having a hard time placing nulls last in ascending order.当我按降序( '-model_a_date' )排序时它工作正常,因为 NULLS 是最后一个,但我很难将空值按升序排列在最后。 I already tried:我已经尝试过:

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),
)

but that does not work at all.但这根本行不通。 Either when I put inside order_by along with other arguments, or as a separate order_by in front or after the above order_by.当我将 order_by 与其他 arguments 一起放入 order_by 时,或者作为单独的 order_by 在上述 order_by 之前或之后。

Any ideas on that?对此有什么想法吗? Has anyone bumped into such problem?有没有人遇到过这样的问题? I'm in a pickle here and honestly I ran out of ideas.我在这里陷入困境,老实说,我已经没有想法了。 Thanks in advance.提前致谢。

EDIT编辑

I also tried.union like so:我也试过.union 像这样:

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

But this comes out with an error:但这会出现错误:

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

If you use chain you can:如果你使用链,你可以:

  • first filter the elements that are not null order them by ascending or descending order首先过滤不是 null 的元素按升序或降序排列
  • second select the nulls第二个 select 空值
  • finally you will be able to chain the to qs that you have (with nulls at the end) and return it最后,您将能够将您拥有的 to qs 链接起来(最后带有空值)并返回它

Does that make sense?那有意义吗?

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM