Convert mongodb return object to dictionary - python

I'm using the bottle framework together with mongoengine.
I have an orders model :
class OrderDetail(Option):
orderDetailsQty = FloatField()
def to_dict(self):
return mongo_to_dict_helper(self)
class Order(Document):
userName = StringField(required=True)
orderDate = DateTimeField()
orderStatus = ListField(EmbeddedDocumentField(Status))
orderDetails = ListField(EmbeddedDocumentField(OrderDetail))
orderComments = ListField(EmbeddedDocumentField(Comment))
isActive = BooleanField()
def to_dict(self):
orderObj = mongo_to_dict_helper(self)
orderDetailList = []
for orderDetail in orderObj["orderDetails"]:
orderDetailList.append(orderDetail.__dict__)
orderObj["OrderDetails"] = orderDetailList
return (self)
When mongodb is queried I get an object which is then converted in to a dict by using the following function :
def mongo_to_dict_helper(obj):
return_data = []
for field_name in obj._fields:
if field_name in ("id",):
continue
data = obj._data[field_name]
if isinstance(obj._fields[field_name], StringField):
return_data.append((field_name, str(data)))
elif isinstance(obj._fields[field_name], FloatField):
return_data.append((field_name, float(data)))
elif isinstance(obj._fields[field_name], IntField):
return_data.append((field_name, int(data)))
elif isinstance(obj._fields[field_name], ListField):
return_data.append((field_name, int(data)))
else:
# You can define your logic for returning elements
pass
return dict(return_data)
I found this function after a long search in the internet. Later found out that this function also fails while defining a member as the ListField(EmbeddedDocumentField(obj)).
I also tried writing a condition for catching the specific case of EmbeddedDocumentField :
elif isinstance(obj._fields[field_name], EmbeddedDocumentField):
return_data.append(mongo_to_dict_helper(data))
but that didn't do any good either.
Anyone have a workaround for this issue ?

What about just using to_mongo method of an object to convert it to a dict?
object.to_mongo()

Expanding on #alexvassel's and #z0r's answers, calling .to_mongo() converts the object to a SON instance. Once you have it, you can call its .to_dict() method to convert it to a dictionary.
For example... (qset is a queryset that's returned from mongoengine, after e.g. Posts.objects.all()).
sons = [ob.to_mongo() for ob in qset]
for son in sons:
print str(son.to_dict())

import json
json.loads(yourobj.to_json())

Extending on #alexvassel's answer, to_mongo() method returns SON object, which you can convert to dict by calling its to_dict() method
object.to_mongo().to_dict()

you can custom method to convert object to dict
class Order(Document):
userName = StringField(required=True)
orderDate = DateTimeField()
orderStatus = ListField(EmbeddedDocumentField(Status))
orderDetails = ListField(EmbeddedDocumentField(OrderDetail))
orderComments = ListField(EmbeddedDocumentField(Comment))
isActive = BooleanField()
def as_dict(self):
return {
"user_name": self.userName,
"order_date": self.orderDate.strftime("%Y-%m-%d %H:%M:%S"),
}
now you can use obj.as_dict() to dict
orders = Order.objects.all()
datas = [each.as_dict() for each in orders]

combining all other answers,
import json
dict = {'data':[json.loads(ob.to_json()) for ob in qset]}

There can be two scenario.
when query returns CommandCursor object
**records = list(CursorObject)**
ex - Class.objects().aggregate({...})
when query returns BaseQuerySet object
**import json**
**records = json.loads(BaseQuerySetObject.to_json())**
ex - Class.objects().filter(..)

Related

missing attribute get in datastore's object

This is my GAE datastore:
class Search(ndb.Model):
city = ndb.StringProperty()
counter = ndb.IntegerProperty(indexed = True)
date = ndb.DateTimeProperty(auto_now_add=True)
When I run this part of code:
keys = Search.query(Search.city == city).fetch()
if (len(keys)==0):
luogo = Search(city = city, counter = 1)
luogo.put()
else:
for key in keys:
luogo_1 = key.get()
luogo_1.counter = luogo_1.counter+1
luogo_1.put()
my terminal says that is missing in object Search attribute get
Do you know why?
Running
keys = Search.query(Search.city == city).fetch()
fetches a list of model instances
so
for key in keys:
luogo_1 = key.get()
fails because instances don't have a get method.
You need to do:
keys = Search.query(Search.city == city).fetch(keys_only=True)
to fetch a list of keys, or treat keys as a list of instances rather than keys, and omit the key.get() call.
Maybe because key object doesn't have get() method:
luogo_1 = key.get()
Use python dir() function, it helps me a lot

Read MongoEngine DynamicDocuments

my issue is that I am saving dict objects with MongoEngine:
class MongoRecord(DynamicDocument):
record_id = SequenceField(primary_key = True)
class SimpleMongo(object):
def __init__(self, *args, **kwargs):
"""
Very simple dict-like Mongo interface
"""
if PY_VERSION == 2:
self.iterattr = 'iteritems'
else:
self.iterattr = 'items'
self.debug = DEBUG
self.dict_type = type(dict())
self.dbname = kwargs.get('dbname', 'untitled')
self.collection_name = kwargs.get('collection', 'default')
self.ip = kwargs.get('ip', '127.0.0.1')
self.port = kwargs.get('port', 27017)
self.dbconn = connect(self.dbname, host=self.ip, port=self.port)
drop = kwargs.get('drop', False)
if drop:
self.dbconn.drop_database(self.dbname)
def put(self, data):
"""
Put dict
"""
assert type(data) == self.dict_type
record = MongoRecord()
record.switch_collection(self.collection_name)
generator = getattr(data, self.iterattr)
__res__ = [setattr(record, k, v) for k,v in generator()] # iteritems() for Python 2.x
record.save()
but when trying to access them:
def get(self):
record = MongoRecord()
record.switch_collection(self.collection_name)
return record.objects
getting
mongoengine.queryset.manager.QuerySetManager object, not an iterator.
So, what is the proper way to get my data back from Mongo being saved as DynamicDocument?
The problem isn't that MongoRecordis a DynamicDocument or that it contains a dict. You would get the same result with a regular Document. Your problem is with querying, you should change record.objects to MongoRecord.objects to get a cursor.
Regarding your usage of switch_collection()...
If MongoRecord documents will be saved to a collection with the same name, at most times, you can define this like below, and you don't have to use switch_collection() when a collection with that name is being queried.
class MongoRecord(DynamicDocument):
record_id = SequenceField(primary_key = True)
meta = {'collection': 'records'}
In case you do want to retrieve MongoRecord documents from a collection which isn't called 'records', and you want to define a function for this (which can give an UnboundLocalError), you can do it like this (source):
from mongoengine.queryset import QuerySet
def get(self):
new_group = MongoRecord.switch_collection(MongoRecord(), self.collection_name)
new_objects = QuerySet(MongoRecord, new_group._get_collection())
all = new_objects.all()
# If you would like to filter on an MongoRecord attribute:
filtered = new_objects.filter(record_id=1)
return all

get all from table django not only __str__(self)

models.py
class club(models.Model):
name = models.CharField(max_length=30)
city = models.CharField(max_length=30)
premiere_leauge = models.BooleanField(default=False)
def __str__(self):
return self.name
Views.py
...
a = request.POST['club']
b = request.POST['city']
result = club.objects.all.get(name__exact=a, city__exact=b)
....
All is fine, however I believe result returns me:
def __str__(self):
return self.name
Whatsover, I would like an equivalent of 'SELECT * FROM APP_CLUB where name='something and city='something'; so i would be able to do further manipulation in django like:
if result[3] is True:
do_something()
As suggested in the offical documentation:
club.objects.filter(name='something')
It will return exactly the same as:
'SELECT * FROM APP_CLUB where name='something';
Example:
clubs = club.objects.filter(name__exact='something')
for club in clubs:
if club.premier_league:
do_something()
If you want to get only one club, then do it like this:
club = club.objects.get(name='something')
premier_league_value_of_club = club.premier_league
Use filter instead of get.
results = club.objects.filter(name__exact=a, city__exact=b)
You can then iterate over it to access all the model attributes like below
for result in results:
print result.name, result.city, result.premier_league
Also, according to PEP-8, you should name your class name should ideally be titlecase Club instead of lowercase club.
You're nearly there, I think you're missing the filter function here. You can use it like this :
a = request.POST['club']
b = request.POST['city']
result = club.objects.filter(name__exact=a, city__exact=b)
It will return you a query set with the actual database entries.
The __str__(self) function is used in transforming your query set entry into a string, whether you string-cast it or print it.
Then about this :
if result[3] is True:
do_something()
I don't get well what you mean about this, but if 3 is the id of the entry in the database, you then can do this :
if result.get(id=3).premiere_leauge:
do_something()
But you might want to check if the entry with the id exists first to avoid errors :
if result.filter(id=3).exists() and result.get(id=3).premiere_leauge:
do_something()
You should modify you query as shown below
result = club.objects.filter(name__exact=a, city__exact=b)
Good Luck !!

Django-tables2: Provide a list of dictionary, how to generate a column for each dictionary entry

I know if we have a model class, we can make a generate table and use:
class Meta:
model = MyModel
To display every field.
Now say if I have a list of dictionaries, instead of model, is there a similar way to do so?
(Since there are so many different dictionaries, which might be dynamically created, I don't wanna create a customized one each time :-))
You can create your own class that inherits from Table and define the fields you want there.
class JsonTable(Table):
json_key_1 = Column()
json_key_2 = Column()
Also django tables2 have a fields attribute but you can't use it if your data is an array of dicts.
I've been doing this too, here's a rough sketch.
Piggy-backing on top of django_tables2 is miles ahead of rolling your own!
Plus, I hook up the results to jquery FooTable plugin.
import django_tables2 as tables
counter = 0
def generate(li_dict):
#unique classname.
global counter
counter += 1
table_classname = "MyTableClass%s" % (counter)
class Meta:
#ahhh... Bootstrap
attrs = {"class": "table table-striped"}
#generate a class dynamically
cls = type(table_classname,(tables.Table,),dict(Meta=Meta))
#grab the first dict's keys
li = li_dict[0].keys()
for colname in li:
column = tables.Column()
cls.base_columns[colname] = column
return cls
#now, to make use of it...
li_dict = [dict(a=11,b=12,c=13),dict(a=21,b=22,c=23)]
cls = generate(li_dict)
table = cls(li_dict)
# below didn't work, wanted a whole bunch of django setup done first.
# but I fairly confident it would...
print table.as_html()
>>>django.core.exceptions.ImproperlyConfigured: {% querystring %} requires django.core.context_processors.request to be in your settings.TEMPLATE_CONTEXT_PROCESSORS in order for the included template tags to function correctly.
#this did...
print "%s" % table
>>><django_tables2.tables.MyTableClass1 object at 0x1070e1090>
i am sorry for poor english :), but a think which can help, actually with this we can transforme a numpy (matrix) in a generic django table2. By the way, thanks Pyeret for your help.
def convert_array_list_dict(arr):
_list = []
for i in xrange(0, arr.shape[0]):
_list.append(dict(enumerate(arr[i,:])))
for i in xrange(0,len(_list)):
for key in _list[i].keys():
_list[i]["col_" + str(key)] = _list[i].pop(key)
return _list`
This function above convert numpy array to list of dict
counter = 0
def list_dict(dict_):
global counter
counter += 1
table_classname = "MyTableClass%s" % (counter)
class Meta:
attrs = {"class": "paleblue", 'width': '150%'}
cls = type(table_classname, (tables.Table,), dict(Meta=Meta))
list_ = dict_[0].keys()
for colname in list_:
column = tables.Column()
cls.base_columns[colname] = column
return cls
This code make a generic table...and
t = np.loadtxt(doc.document)
tab = convert_array_list_dict(t)
table = list_dict(tab)
table_content = table(tab)
RequestConfig(request, paginate={'per_page': 30}).configure(table_content)
return render(request,'app/snippets/upload_file.html',{'document':document,'table_content':table_content})
Above we can see how use all code...

Class design: Last Modified

My class:
class ManagementReview:
"""Class describing ManagementReview Object.
"""
# Class attributes
id = 0
Title = 'New Management Review Object'
fiscal_year = ''
region = ''
review_date = ''
date_completed = ''
prepared_by = ''
__goals = [] # List of <ManagementReviewGoals>.
__objectives = [] # List of <ManagementReviewObjetives>.
__actions = [] # List of <ManagementReviewActions>.
__deliverables = [] # List of <ManagementReviewDeliverable>.
__issues = [] # List of <ManagementReviewIssue>.
__created = ''
__created_by = ''
__modified = ''
__modified_by = ''
The __modified attribute is a datetime string in isoformat. I want that attribute to be automatically to be upated to datetime.now().isoformat() every time one of the other attributes is updated. For each of the other attributes I have a setter like:
def setObjectives(self,objectives):
mro = ManagementReviewObjective(args)
self.__objectives.append(mro)
So, is there an easier way to than to add a line like:
self.__modified = datetime.now().isoformat()
to every setter?
Thanks! :)
To update __modified when instance attributes are modified (as in your example of self.__objectives), you could override __setattr__.
For example, you could add this to your class:
def __setattr__(self, name, value):
# set the value like usual and then update the modified attribute too
self.__dict__[name] = value
self.__dict__['__modified'] = datetime.now().isoformat()
Perhaps adding a decorator before each setter?
If you have a method that commits the changes made to these attributes to a database (like a save() method or update_record() method. Something like that), you could just append the
self.__modified = datetime.now().isoformat()
just before its all committed, since thats the only time it really matters anyway.

Categories