2015-06-17 133 views
2

我想在从MongoDB数据库查询时将ObjectIdISODate转换为字符串表示。Mongoengine自定义查询集

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

现在,当我创建一个投资组合对象这样

a = Portfolio(PortfolioName='BB Visa').save() 

,当我试图让to_dict() repressentation像a.to_dict()对象,它完美的作品。

{'_id': '5581cf9129e457241a32e8f7', 'PortfolioName': 'BB Visa', 'RecentActivity': [], 'LastUpdateDate': 1434570641000.0} 

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

所以,当我试图这样定义

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()产生像下面 回溯错误(最新最后调用):

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 Manager将类传递给函数,这就是错误的原因。如何解决这个问题。

回答

1

其实我不知道它是根据documentation

mongoengine.queryset.queryset_manager(func)装饰,让您 定义上的文档类的自定义查询集经理将此定义为@queryset_manager事业正确的决定。管理器 必须是接受Document类作为其第一个参数 ,并将QuerySet作为其第二个参数的函数。 方法函数 应该返回一个查询集,可能与传入的查询集相同, 但以某种方式修改为

我建议加入一些独立的utils的函数,它的查询集:

def convert_queryset_to_list_of_dicts(queryset): 
    return [mongo_to_dict(obj) for obj in queryset] 

或者,如果你还是希望有这个作为@queryset_manager则:

... 
@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]。这不适用吗?