首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Flask-Mongoengine自定义排序方式比较器

Flask-Mongoengine自定义排序方式比较器
EN

Stack Overflow用户
提问于 2020-07-04 01:41:19
回答 1查看 237关注 0票数 1

我正在使用Flask-Mongoengine作为我的flask应用程序的对象模型。我定义了一个Document来存储字符串中的唯一版本:

代码语言:javascript
复制
MyDocument(db.Document):
    version = db.StringField(primary_key=True, required=True)

存储在StringField中的值的格式如下:

代码语言:javascript
复制
a.b.c.d

在使用order_by进行查询时,我遇到了一些问题:

代码语言:javascript
复制
MyDocument.objects.order_by('version')

更准确地说,如果版本的第一部分(上面的格式示例中的a)包含多个数字,它就不能正确排序(例如:15.20.142 < 1.7.9)。而我显然可以做一些类似的事情:

代码语言:javascript
复制
tmp = Document.objects.all()
result = some_merge_sort(tmp)

然而,这需要编写、测试和维护排序算法。这就引出了我的下一个解决方案,那就是覆盖order_by中使用的比较器。问题是,我不确定如何正确地做到这一点。我是否必须定义一个自定义属性类型,或者是否有一些我应该覆盖的钩子?

在任何情况下,在我重写轮子之前,我认为我应该作为stackoverflow上的好人们。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2020-07-04 03:23:04

在深入研究了Mongoengine源代码之后,我发现它使用的是PyMongo cursor sort,它本身封装了对MongoDB所做的查询。换句话说,我的Document定义在链中太高,甚至不会影响order_by结果。

因此,我采用的解决方案是编写一个classmethod。这只是接受一个mongoengine.queryset.QuerySet实例并对version属性应用一个排序。

代码语言:javascript
复制
from mongoengine.queryset import QuerySet
from packaging import version

class MyDocument(db.Document):
    version = db.StringField(primary_key=True, required=True)

    @classmethod
    def order_by_version(_, queryset, reverse=False):
        """
            Wrapper function to order a given queryset of this classes
            version attribute.

            :params:
                - `QuerySet` :queryset: - The queryset to order the elements.
                - `bool`     :reverse:  - If the results should be reversed.

            :raises:
                - `TypeError` if the instance of the given queryset is not a `QuerySet`.

            :returns:
                - `List` containing the elements sorted by the version attribute.
       """
       # Instance check the queryset.
       if not isinstance(queryset, QuerySet):
           raise TypeError("order_by_version requires a QuerySet instance!")

       # Sort by the version attribute.
       return sorted(queryset, key=lambda obj: version.parse(obj.version), reverse=reverse)

然后,为了利用这种方法,我可以简单地执行以下操作:

代码语言:javascript
复制
MyDocument.order_by_version(MyDocument.objects)

至于我采用QuerySet实例而不是从类方法中进行查询的原因,只是为了在进行排序之前有机会调用其他Mongoengine方法。因为我使用了sorted,所以它将保持任何现有的顺序,所以我仍然可以将内置的order_by用于其他属性。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/62720357

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档