2015-06-17 5 views
2

Я пытаюсь преобразовать ObjectId и ISODate в представления строк при запросе из базы данных MongoDB.Mongoengine custom queryset

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() работать на уровне класса не приемлю уровень.

Так что, когда я попытался определить пользовательский QuerySet как этот

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() генерирует ошибку, как показано ниже TraceBack (самый последний вызов последний):

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

На самом деле я не уверен, что это правильное решение, чтобы определить это как @queryset_manager причины согласно documentation

mongoengine.queryset.queryset_manager(func) Decorator, что позволяет определить пользовательские QuerySet менеджеров по классам документов. Менеджер должен быть функцией, которая принимает класс Document как его первый аргумент , а QuerySet - вторым аргументом. Функция метода должна возвращать QuerySet, возможно, тот же самый, который был передан, , но каким-то образом изменен.

Я предлагаю добавить некоторые отдельные Utils функцию, которая принимает QuerySet:

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]. Разве это не применимо?

Смежные вопросы