烧瓶-蒙古发动机定制按顺序比较器



我正在使用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

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

但是,这需要编写、测试和维护排序算法。这让我想到了下一个解决方案,即覆盖order_by中使用的比较器。问题是,我不确定如何正确执行此操作。我是否必须定义自定义属性类型,或者是否有一些我应该覆盖的钩子?

无论如何,我认为在我重写轮子之前,我会作为堆栈溢出的好人。

在对Mongoengine源代码进行了一些挖掘后,我发现它使用了本身包装对MongoDB的查询的PyMongocursorsort。换句话说,我的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实例而不是从classmethod中执行查询的原因,只是为了允许有机会在执行排序之前调用其他Mongoengine方法。因为我用了sorted,它会保持任何现有的顺序,所以我仍然可以将内置order_by用于其他属性。

最新更新