首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >Mongoengine自定义查询集

Mongoengine自定义查询集
EN

Stack Overflow用户
提问于 2015-06-17 20:01:14
回答 2查看 4.6K关注 0票数 4

在从ObjectId数据库查询时,我试图将ISODate和MongoDB转换为字符串表示。

代码语言:javascript
运行
复制
def mongo_to_dict(obj, exclude_fields):
    return_data = []

    if obj is None:
        return None

    if isinstance(obj, Document):
        return_data.append(("_id", str(obj.id)))

    for field_name in obj._fields:

        if field_name in exclude_fields:
            continue

        if field_name in ("id",):
            continue

        data = obj._data[field_name]

        if isinstance(obj._fields[field_name], ListField):
            return_data.append((field_name, list_field_to_dict(data)))
        elif isinstance(obj._fields[field_name], EmbeddedDocumentField):
            return_data.append((field_name, mongo_to_dict(data, [])))
        elif isinstance(obj._fields[field_name], DictField):
            return_data.append((field_name, data))
        else:
            return_data.append((field_name, mongo_to_python_type(obj._fields[field_name], data)))

    return dict(return_data)


def list_field_to_dict(list_field):
    return_data = []

    for item in list_field:
        if isinstance(item, EmbeddedDocument):
            return_data.append(mongo_to_dict(item, []))
        else:
            return_data.append(mongo_to_python_type(item, item))

    return return_data


def mongo_to_python_type(field, data):
    if isinstance(field, DateTimeField):
        return time.mktime(data.timetuple()) * 1000
    elif isinstance(field, ComplexDateTimeField):
        return field.to_python(data).isoformat()
    elif isinstance(field, StringField):
        return str(data)
    elif isinstance(field, FloatField):
        return float(data)
    elif isinstance(field, IntField):
        return int(data)
    elif isinstance(field, BooleanField):
        return bool(data)
    elif isinstance(field, ObjectIdField):
        return str(data)
    elif isinstance(field, DecimalField):
        return data
    else:
        return str(data)


class Portfolio(Document):
    meta = {'collection': 'Portfolios'}
    PortfolioName = StringField()
    LastUpdateDate = DateTimeField(default=datetime.datetime.now())
    RecentActivity = ListField(default=[])


    def to_dict(self):
        return mongo_to_dict(self, [])

现在,当我创建这样一个Portfolio对象时

代码语言:javascript
运行
复制
a = Portfolio(PortfolioName='BB Visa').save()

当我试图得到像a.to_dict()这样的对象的a.to_dict()约束时,它工作得很好。

代码语言:javascript
运行
复制
{'_id': '5581cf9129e457241a32e8f7', 'PortfolioName': 'BB Visa', 'RecentActivity': [], 'LastUpdateDate': 1434570641000.0}

但问题是我希望to_dict()在类级别上操作,而不是在对象级别上操作。

所以当我试图定义这样的自定义查询集时

代码语言:javascript
运行
复制
class Portfolio(Document):
    meta = {'collection': 'Portfolios'}
    PortfolioName = StringField()
    LastUpdateDate = DateTimeField(default=datetime.datetime.now())
    RecentActivity = ListField(default=[])

    @queryset_manager
    def to_dict(self, queryset):
        return mongo_to_dict(self, [])

现在,运行以下命令Portfolio.to_dict()将生成如下所示的错误(最近一次调用是最后一次):

代码语言:javascript
运行
复制
  File "/home/ajay/PycharmProjects/solveit/test.py", line 102, in <module>
    print(Portfolio.to_dict())
  File "/home/ajay/.pyenv/versions/3.4.3/lib/python3.4/site-packages/mongoengine/queryset/manager.py", line 43, in __get__
    queryset = self.get_queryset(owner, queryset)
  File "/home/ajay/PycharmProjects/solveit/test.py", line 83, in to_dict
    return mongo_to_dict(self, [])
  File "/home/ajay/PycharmProjects/solveit/test.py", line 28, in mongo_to_dict
    data = obj._data[field_name]
TypeError: 'member_descriptor' object is not subscriptable

我理解QuerySet管理器将类传递到函数中,这就是错误的原因。如何解决这个问题。

EN

回答 2

Stack Overflow用户

发布于 2015-06-18 20:32:27

实际上,我不确定按照文档的说法,把这个定义为文档原因是正确的。

mongoengine.queryset.queryset_manager(func)装饰器,允许您在文档类上定义自定义QuerySet管理器。管理器必须是接受文档类作为其第一个参数的函数,而接受QuerySet作为其第二个参数的函数。方法函数应该返回一个QuerySet,可能与传入的相同,但以某种方式修改了

我建议添加使用queryset的一些单独的utils函数:

代码语言:javascript
运行
复制
def convert_queryset_to_list_of_dicts(queryset):
    return [mongo_to_dict(obj) for obj in queryset]

或者,如果您仍然希望将它作为@queryset_manager,那么:

代码语言:javascript
运行
复制
...
@queryset_manager
def to_dict(self, queryset):
    return [mongo_to_dict(obj) for obj in queryset]
...

此外,还有一个mongoengine to_mongo的现成方法。您可以这样做:[obj.to_mongo() for obj in queryset]。不适用吗?

票数 3
EN

Stack Overflow用户

发布于 2020-02-17 08:14:31

这是一个古老的问题,但很有趣,这里仍然没有好的答案。这就是我的答案。

简介

您在定制queryset方面是正确的,但是您不应该为您的目的定义另一个queryset_manager。正如@bellum所提到的,@queryset_manager应该返回QuerySet。相反,您应该在QuerySet中定义方法。您可以在您的queryset_manager中这样做,但是它仍然不能与filterorder_byskiplimit等一起工作。相反,您应该定义自定义QuerSet,并将其设置为模型的默认设置。

回答

代码语言:javascript
运行
复制
from mongoengine.queryset import QuerySet


class CustomQuerySet(QuerySet):

    # define your custom method here
    def print_ids(self):
        for doc in self:
            print(doc.id)


class Product(DynamicDocument):
    # set your CustomQuerySet as default queryset_class
    meta = {'queryset_class': CustomQuerySet}

实际上,您的模型将使用基本QuerySet,但现在它将包含您的自定义方法。

示例

代码语言:javascript
运行
复制
>>> Product.objects.print_ids()
5e46433c943478954eef837d
5e46623705f1fa6c78e3fdbc
5e46627b05f1fa6c78e403a3

您可以与过滤器一起使用它:

代码语言:javascript
运行
复制
>>> Product.objects.filter(id='5e46433c943478954eef837d').print_ids()
5e46433c943478954eef837d

您可以使用排序、跳过、限制和其他东西:

代码语言:javascript
运行
复制
>>> Product.objects.all().limit(2).print_ids()
5e46433c943478954eef837d
5e46623705f1fa6c78e3fdbc
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/30901274

复制
相关文章

相似问题

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