Using nested/embedded documents in Mongoengine with Python - python

I want to use nested values inside Mongodb and from the documentation i understand this is done through Embedded documents. If there are any other ways please tell me.
I have the current code:
class compute_instances_subtype(EmbeddedDocument):
label_name = StringField()
class Post(Document):
title = StringField(max_length=120, required=True)
author = StringField(required=True)
tags = ListField(StringField(max_length=30))
compute_instances = ListField(EmbeddedDocumentField(compute_instances_subtype))
post = Post(title="Quora rocks", author="Ross", tags=['tutorial', 'how-to'])
add_test0_label = compute_instances_subtype()
add_test0_label.title = "test0"
add_test0_label.label_name= "value"
add_test1_label= compute_instances_subtype()
add_test1_label.title = "test1"
add_test1_label.label_name= "value"
post.compute_instances.append(add_test0_label)
post.compute_instances.append(add_test1_label)
post.save()
But my issue is that the document does not have a name for the Objects of the compute_instances field, it just says 0 and 1:
id : 60fec94dbb81d98abb557523
title : Quora rocks
author : Ross
tags : compute_instances : Array
0 : Object
label_name : value
1 : Object
label_name : value
I want to have 0 named test0 and 1 named test1.
Please guide me on how to achieve that.
Best regards

It's unclear what you use to print the object, but here are a few comments that might help you:
your compute_instances_subtype class has no title field that is set, so when you set add_test0_label.title = "test0", it's just added to the python object but it's not being saved in the database when you call .save().
0 and 1 that you see in your output are the indexes of the Object in the compute_instances array
Here is a simplified example that might also be helpful:
class ComputeInstancesSubtype(EmbeddedDocument):
label_name = StringField()
title = StringField()
class Post(Document):
title = StringField(max_length=120, required=True)
compute_instances = ListField(EmbeddedDocumentField(ComputeInstancesSubtype))
nested1 = ComputeInstancesSubtype(title='something0', label_name='test0')
nested2 = ComputeInstancesSubtype(title='something1', label_name='test1')
post = Post(title="Quora rocks", compute_instances = [nested1, nested2])
post.save()
print(Post._get_collection().find_one()) # print it in its raw format
returns
{'_id': ObjectId('61071c5e3686c4066dadbc05'),
'title': 'Quora rocks',
'compute_instances': [{'label_name': 'test0', 'title': 'something0'},
{'label_name': 'test1', 'title': 'something1'}]
}

Related

Fill data from database to Word (Django Python)

I don't know how to get data and fill into my word template. It's actually a long list, and I need to fill it on my table on word document. Am I doing it right? Here is my code:
views.py
def save_sample_details(request):
sample = SampleList.objects.all()
doc = DocxTemplate("lab_management/word/sample_template.docx")
context = {
'SNAME' : sample.sample_name,
'STYPE' : sample.sample_type,
'HVER' : sample.hardware_version,
'SVER' : sample.software_version,
'CS' : sample.config_status,
'NUM' : sample.number,
'SNUM' : sample.sample_number,
}
doc.render(context)
doc.save('lab_management/word/sample.docx')
return redirect('/lab/sample/details/')
models.py
class SampleList(models.Model):
sample_name = models.CharField(max_length=32)
sample_type = models.CharField(max_length=32)
hardware_version = models.CharField(max_length=32)
software_version = models.CharField(max_length=32)
config_status = models.CharField(max_length=18)
number = models.IntegerField(default=0)
sample_number = models.CharField(max_length=17)
So if I run this, it shows
'QuerySet' object has no attribute 'sample_name' etc.
You're getting all SampleList objects when you call SampleList.objects.all() so this is returning a QuerySet of zero or more objects, rather than a single object - which is what you want.
Instead you should get the single SampleList object you want: for example sample = SampleList.objects.get(id=1) or another example - to get the first object in the QuerySet you could do sample = SampleList.objects.all()[0] (but if the QuerySet is empty you'll get an index error). You didn't specify how you want to determine which SampleList to put in the Word doc, but you can specify any filters in the .get() properties.
Django has some pretty good documentation covering querysets:
https://docs.djangoproject.com/en/4.1/ref/models/querysets/
Change your code as:
def save_sample_details(request):
sample_list = SampleList.objects.all()
doc = DocxTemplate("lab_management/word/sample_template.docx")
context_list = []
for sample in sample_list:
context = {
'SNAME' : sample.sample_name,
'STYPE' : sample.sample_type,
'HVER' : sample.hardware_version,
'SVER' : sample.software_version,
'CS' : sample.config_status,
'NUM' : sample.number,
'SNUM' : sample.sample_number,
}
context_list.append(context)
doc.render(context_list)
doc.save('lab_management/word/sample.docx')
return redirect('/lab/sample/details/')
You should be iterating in the context_list in the doc as well.
(Assuming you are using docxtpl library)
I have answered my question. Thank you for the help!
views.py
def save_sample_details(request):
sample = SampleList.objects.all()[0:15]
template = DocxTemplate("lab_management/word/sample_template.docx")
context = {
'headers' : ['SNAME', 'STYPE', 'HVER', 'SVER', 'CS', 'NUM', 'SNUM'],
'list': [],
}
alist = ['a']
for i in alist:
for samples in sample:
content= [samples.sample_name, samples.sample_type, samples.hardware_version,
samples.software_version, samples.config_status, samples.number,
samples.sample_number ]
context['list'].append(content)
template.render(context)
template.save('lab_management/word/sample.docx')
return redirect('/lab/sample/details/')
sample_template.docx

How to add index on ListField with mongoengine in python?

I want to add index on ListField.Here is my code:
class Post(Document):
meta = {"indexs":"testcomments.comment_id"}
_id = StringField()
txt = StringField()
testcomments = EmbeddedDocumentField(Comment)
comments = ListField(EmbeddedDocumentField(Comment))
class Comment(EmbeddedDocument):
comment = StringField()
comment_id = StringField()
...
...
I know how to add index on EmbeddedDocumentField (meta = {"indexs":"testcomments.comment_id"}),but how to add index on comments?
I believe it would work the same way for the list, thus
meta = {
"indexes": [
"testcomments.comment_id",
"comments.comment_id", # or simply 'comments' if you want a multikey index
]
}
Note that you can check the indexes being created with
col = Page._get_collection()
c.index_information()
If you use the dict form to define indexes e.g: meta = {'indexes': [{'fields': ['comments.comment_id']}}, you can have more granularity on the index definition (and syntax closer to pymongo/mongodb)

MongoEngine ReferenceField Text Index setup?

class Tag(db.Document):
text = db.StringField(unique=True)
class Post(db.Document):
user = db.ReferenceField(User, required=True)
pid = db.SequenceField(required=True, unique=True)
description = db.StringField()
title = db.StringField(required=True)
created = db.DateTimeField(default=utils.time_now, required=True)
updated = db.DateTimeField(default=utils.time_now, required=True)
tags = db.ListField(db.ReferenceField(Tag), default=[])
ratings = db.EmbeddedDocumentListField(Rating, default=[])
comments = db.EmbeddedDocumentListField(Comment, default=[])
url = db.URLField()
meta = {'indexes': [
{'fields': ['$title', '$description', '$tags.text'],
'default_language': 'english',
'weights': {'title': 10, 'description': 5, 'tags': 2}
}
]}
Here are my two documents. The Tag document is Referenced in a Listfield of the Post document. When I try to do a search with the text index I can successfully search on the title and description but not the tags. Does anyone know why. I couldn't find any helpful examples here http://docs.mongoengine.org/guide/text-indexes.html
A ReferenceField type is only de-referenced on access by some internal MongoEngine magic. As such you cannot use it as an element in the text index (the list saved in the mongodb document will hold only bson ObjectId references).

MongoEngine Query Optimization

I have two collections ScenarioDrivers and ModelDrivers which has One to Many relationship with each other.
class ScenarioDrivers(Document):
meta = {
'collection': 'ScenarioDrivers'
}
ScenarioId = ReferenceField('ModelScenarios')
DriverId = ReferenceField('ModelDrivers')
DriverCalibrationMethod = StringField()
SegmentName = StringField()
DriverValue = ListField()
CalibrationStatus = StringField()
AdjustedValues = ListField(default=[])
CreateDate = DateTimeField(default=ObjectId().generation_time)
LastUpdateDate = DateTimeField(default=datetime.utcnow())
class ModelDrivers(Document):
meta = {
'collection': 'ModelDrivers'
}
PortfolioModelId = ReferenceField('PortfolioModels')
DriverName = StringField()
CreateDate = DateTimeField(default=ObjectId().generation_time)
LastUpdateDate = DateTimeField(default=datetime.utcnow())
FieldFormat = StringField()
DriverData = ListField()
My query is like this.
class GetCalibratedDrivers(Resource):
def get(self, scenario_id):
scenario_drivers_list = []
scenario_drivers = ScenarioDrivers.objects(ScenarioId=scenario_id).exclude('ScenarioId').select_related(1)
for scenario_driver in scenario_drivers:
scenario_driver_dict = {
'id': str(scenario_driver.id),
'DriverId': str(scenario_driver.DriverId.id),
'SegmentName': scenario_driver.SegmentName,
'CalibrationMethod': scenario_driver.DriverCalibrationMethod,
'CalibratedValues': exchange(scenario_driver.DriverValue),
'AdjustedValues': scenario_driver.AdjustedValues,
'LastUpdateDate': formatted_date(scenario_driver.LastUpdateDate),
'FieldFormat': scenario_driver.DriverId.FieldFormat
}
scenario_drivers_list.append(scenario_driver_dict)
return {
'DriverCalibrations': scenario_drivers_list
}
The Query matches 1140 records and then I construct a dictionary and make it a list.
But this API call takes 30s to process just 1140 records. Where I am missing? Please help. I am using latest version of Pymongo and MongoEngine.
I think the problem is not with your query, it is with you looping over 1140 records. I do not see any use of referenced objects so you should consider removing select_related(1). Once you do that, if you want to convert reference object ids to string, you can use as_pymongo() which will do that by default for you. And finally if you must read some data in specific format like formatted_date or exchange, it is better to save them as part of your document. i.e. save FormattedLastUpdateDate with LastUpdateDate. In MongoDB, you have to think about your read specific logic when you save the document.

Odoo error when generating One2many field data

Given the following class for the header:
class vontatas_head(models.Model):
_name = 'vontatas.head'
display_name = fields.Char(string="Sor", compute='_compute_display_name', store=False)
plan_type_id = fields.Many2one(
comodel_name='plan.type', string='Terv típus', required=True)
year = fields.Integer(string='Év', required=True, default=lambda *a: strftime('%Y'))
version = fields.Integer(string='Verzió', required=True, default=1)
comment = fields.Char(string='Megjegyzés')
vontatas_data_ids = fields.One2many(
comodel_name='vontatas.data', inverse_name='vontatas_id', string='Adatok', default=get_default_lines)
And for the detail:
class vontatas_data(models.Model):
_name = 'vontatas.data'
vontatas_id = fields.Many2one(comodel_name="vontatas.head", string="Vontatás sor")
name = fields.Char(string="Megnevezés", required=True)
code = fields.Char(string="Kód", required=True)
type = fields.Selection([('total', 'Összesen'), ('input', 'Input')], string="Típus", default='input')
value = fields.Float(string="Várható költség")
parent_id = fields.Many2one(comodel_name="vontatas.data", ondelete='cascade', string="Összesen sor")
child_ids = fields.One2many(comodel_name="vontatas.data", inverse_name='parent_id', string='Input sorok')
I have to automatically generate details data from a template with this code:
def get_default_lines(self):
self.env.cr.execute("select name, code, type, parent_id from vontatas order by code")
sorok = self.env.cr.fetchall()
ids = []
for sor in sorok:
ids.append((0,0, { 'name': sor[0],
'code': sor[1],
'type': sor[2],
'parent_id': sor[3]
}))
return ids
Everyting is working fine, but at the creation I have an error message: "One of the documents you are trying to access has been deleted, please try again after refreshing."
I know why this error is happening: at the moment of generation there is no valid parent_id.
My question is: how to provide any valid parent_id within the function get_default_lines, knowing that the data is actually just in memory, not stored yet in the database?
Or asked otherwise: How to keep the hierarchy level defined within the template?

Categories

Resources