Flask-Mongoengine自定义排序比较器

播种

我正在将Flask-Mongoengine烧瓶应用程序用作ORM。我定义了一个Document以字符串形式存储唯一版本:

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

存储在中的值StringField采用以下格式:

a.b.c.d

order_by用于查询时,我遇到了一些问题

MyDocument.objects.order_by('version')

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

tmp = Document.objects.all()
result = some_merge_sort(tmp)

但是,这需要编写,测试和维护排序算法。然后,这使我进入下一个解决方案,即覆盖中使用的比较器order_by问题是,我不确定如何正确执行此操作。我必须定义一个自定义属性类型,还是应该覆盖一些挂钩?

无论如何,在重新编写轮子之前,我想我会像stackoverflow上的好伙伴一样。

播种

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

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

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)

然后,要使用此方法,我可以简单地执行以下操作:

MyDocument.order_by_version(MyDocument.objects)

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

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章