Can not delete document object using mongoengine - python

I am working with mongoDB 4.2 using python 3.7 and library mongoengine 0.18.2.
So, I want to delete a document but I got lookup error.
ODM:
from mongoengine import Document
from mongoengine.fields import *
class Myparent(Document):
fieldfoo = IntField()
fieldbar = IntField()
class Mychild(Document):
fieldfoo = StringField()
myparent = ReferenceField('Myparent')
Now, when I want to delete a child:
item = Mychild.objects.get(id=123456)
item.delete()
I got this error:
site-packages/mongoengine/queryset/transform.py", line 60, in query
fields = _doc_cls._lookup_field(parts)
site-packages/mongoengine/base/document.py", line 1032, in _lookup_field
raise LookUpError('Cannot resolve field "%s"' % field_name)
mongoengine.errors.LookUpError: Cannot resolve field "myparent"
Any clue? Thanks

The id you are providing is not a valid id. Mongo supports 12 byte binary BSON type format which is definitely not 123456. If your id is correct then you can do the following :
item=Mychild.objects(pk='some_id')
Whatever is returned in item will be a list but id is unique so you can write it as:
item=Mychild.objects(pk='some_id').first()
item.delete()

Related

Can't use "gte" in mongoengine filter query

I have a MongoEngine Document class Student..
class Student(Document):
db_id = StringField()
name = StringField()
score = IntField()
deleted = BooleanField(default=False, required=True)
I would like to query as
Student.objects.filter(score__gte=30)
But I'm getting a error like AttributeError: 'int' object has no attribute 'get'
Can someone please help me in how I can do this? Thank you!
The following (minimal) snippet works fine
from mongoengine import *
connect()
class Student(Document):
name = StringField()
score = IntField()
Student(name='Bob', score=35).save()
print(Student.objects(score__gte=30))
# output: [<Student: Student object>]
I don't have any problem to run your code, perhaps start from mine and build on top until you identify the culprit. I would also recommend to drop the existing mongo collection before you test this.
In fact, depending on where the error is fired (we don't have the stack trace so we can't tell), it could be that it fails when loading the existing mongo document (returned by your query) into the Student constructor

Dealing with import of foreignKeys in django-import-export

I don't understand how django-import-export module deals with ForeignKeys.
Here is a simple exemple :
models.py
class TFamilies(models.Model):
id_fam = models.AutoField(primary_key=True, unique=True)
name_fam = models.CharField(max_length=1024, blank=True,verbose_name='Famille')
class TGenus(models.Model):
id_genus = models.AutoField(primary_key=True, unique=True)
name_genus = models.CharField(max_length=1024,verbose_name='nom de genre')
id_fam = models.ForeignKey(TFamilies, null=True, db_column='id_fam', blank=True, verbose_name='Famille')
I would like to allow people adding genus with family associated ! A CSV/XLS with only name_genus and name_fam... (and id left blank).
Family already exist in DB most of the time, Django juste have to find the right id number...
admin.py
class TGenusResource(resources.ModelResource):
name_fam = fields.Field(widget=widgets.ForeignKeyWidget(TFamilies, 'name_fam'))
class Meta:
model = TGenus
import_id_fields = ['id_genus']
class TGenusAdmin(ImportExportActionModelAdmin):
form = TGenusAdminForm
resource_class = TGenusResource
pass
This configuration lead to error in import interface :
Line number: 1 - 'NoneType' object has no attribute 'name_fam'
Traceback (most recent call last):
File "/....../lib/python2.7/site-packages/import_export/resources.py", line 348, in import_data
row_result.object_repr = force_text(instance)
File "......./lib/python2.7/site-packages/django/utils/encoding.py", line 85, in force_text
s = six.text_type(s)
AttributeError: 'NoneType' object has no attribute 'name_fam'
I don't understand...
I also tried answer there : django-import-export resource definition for foreignkey field?
and sort of like there : Foreign Key in django migration using django-import-export
Do I have to use before_import to find myself the match ?
I figured out that you have to find yourself the match ! It's impossible to alterate values in a tablib dataset so you have to take entries make changes and put them back in a new line then erase the old one.
My excel template contains columns id_genus (empty), name_genus and id_fam filled by the name of the family !
For anyone who landed here I post my way :
def before_import(self, dataset, dry_run):
"""
Make standard corrections to the dataset before displaying to user
"""
i = 0
last = dataset.height - 1
# for all lines, search for id of family given and add a new line at the bottom with it then delete the first one
while i <= last:
# Check if the Genus exist in DB
if (TGenus.objects.filter(name_genus=dataset.get_col(2)[0].capitalize())):
id_genus = TGenus.objects.filter(name_genus=dataset.get_col(2)[0].capitalize())[0].id_genus
else :
id_genus = ''
# Check if the family exists in DB
try:
TFamilies.objects.get(name_fam=dataset.get_col(2)[0].capitalize())
except TFamilies.DoesNotExist:
raise Exception("Family not in DB !")
except TFamilies.MultipleObjectsReturned:
pass
# use of "filter" instead of "get" to prevent duplicate values, select the first one in all cases
dataset.rpush((id_genus,
dataset.get_col(1)[0],
TFamilies.objects.filter(name_fam=dataset.get_col(2)[0].capitalize())[0].id_fam))
dataset.lpop()
i = i + 1
My django admin can be used by non sys-admin so, they can and duplicate genus or families that aren't in DB...
If someone have an idea to deal with errors better, I would like to read it !
Also, I would like to keep the name of the family in the preview, not only her id... If you know how, I have posted another question about that : Is-it possible to customize the template of preview in django import-export?
I believe you need to rename according to field name in model TGenus:
id_fam = fields.Field(widget=widgets.ForeignKeyWidget(TFamilies, 'name_fam'))
instead of:
name_fam = fields.Field(widget=widgets.ForeignKeyWidget(TFamilies, 'name_fam'))

How to change the name of the document=True field of Haystack in Django?

I want to use haystack, but all my models have "body" as their text-field name. it is the same on all models though.
Now I get this error:
All 'SearchIndex' classes must use the same 'text' fieldname for the 'document=True' field. Offending index is '<qna.search_indexes.QuestionIndex object at 0x2435328>'.
That's the index file:
import datetime
from haystack import indexes
from qna.models import Question
class QuestionIndex(indexes.SearchIndex, indexes.Indexable):
subject = indexes.CharField(document=False, use_template=False)
body = indexes.CharField(document=True, use_template=True, model_attr='user')
pub_date = indexes.DateTimeField(model_attr='pub_date')
def get_model(self):
return Question
def index_queryset(self, using=None):
"""Used when the entire index for model is updated."""
return self.get_model().objects.filter(pub_date__lte=datetime.datetime.now())
It is the ONLY one! With what is it offending? As far as I understand the field name doesn't have to be "text" it only has to be the same on every field. But it's the only field! Do I have to change some config? What might be the cause of this... ??
I saw your error in the haystack source. It looks like there is a setting for the name of this field (https://github.com/toastdriven/django-haystack/blob/master/haystack/utils/loading.py#L154):
self.document_field = getattr(settings, 'HAYSTACK_DOCUMENT_FIELD', 'text')
Later in that file (https://github.com/toastdriven/django-haystack/blob/master/haystack/utils/loading.py#L222) it checks to make sure that your index name matches and blows up with the error you saw if they don't agree:
if field_object.index_fieldname != self.document_field:
raise SearchFieldError("All 'SearchIndex' classes must use the same '%s' fieldname for the 'document=True' field. Offending index is '%s'." % (self.document_field, index))
If you set HAYSTACK_DOCUMENT_FIELD to "body" in your settings, it looks like that should do it.

Dumping SQLAlchemy output to JSON

I have written a small python script that uses SQLAlchemy to read all records of the db. Here is some of the code
Base=declarative_base()
Session = sessionmaker(bind=engine)
cess=Session()
class Test(Base):
__tablename__ = 'test'
my_id = Column(Integer, primary_key=True)
name = Column(String)
def __init__(self, id, name):
self.my_id = id
self.name = name
def __repr__(self):
return "<User('%d','%s')>" % (self.id, self.name)
query= cess.query(Test.my_id, Test.name).order_by(Test.my_id).all()
Now the query object i want to convert to a json string. How can i do this ? using json.dumps(query) throws an exception ?
Kind Regards
json.dumps will convert object according to its conversion table.
Since you have rows of type Test, these cannot be directly serialized. Probably the quickest approach is to convert each returned row to a Python dict and then pass this through to json.dumps.
This answer describes how you might go about converting a table row to a dict.
Or, perhaps the _asdict() method from row object can be utilised directly.
query = cess.query(Test.my_id, Test.name).order_by(Test.my_id).all()
json.dumps([ row._asdict() for row in query ])
An alternative might be to access the __dict__ attribute directly on each row, although you should check the output to ensure that there are no internal state variables in row.__dict__.
query = cess.query(Test.my_id, Test.name).order_by(Test.my_id).all()
json.dumps([ row.__dict__ for row in query ])
How I did it:
fe = SomeClass.query.get(int(1))
fe_dict = fe.__dict__
del fe_dict['_sa_instance_state']
return flask.jsonify(fe_dict)
Basically, given the object you've retrieved, grab the dict for the class instance, remove the sqlalchemy object that can't be json serialized and convert to json. I'm using flask to do this but I think json.dumps() would work the same.

MongoEngine with Flask - Error 'NoneType' object has no attribute 'choices'

I'm trying to get MongoEngine with the Flask-Mongoengine extension working, however whenever I use a ListField I get the error below:
if field.field.choices:
AttributeError: 'NoneType' object has no attribute 'choices'
Here is my code:
class Business(db.Document):
name = db.StringField(required=True)
address = db.StringField()
location = db.GeoPointField()
tags = db.ListField()
area = db.ReferenceField(Area, dbref=True)
contact = db.EmbeddedDocumentField(Contact)
details = db.EmbeddedDocumentField(details)
I had the same problem. What fixed it for me was passing a Field object to the ListField() call in the ListField declarations, example:
tags = db.ListField(db.StringField())
I faced the same issue but for the DictField while update. I was trying to save file name as lable and the details of the as its value object e.g. The class structure is
class Folder(Document):
name = StringField(required=True)
fileList = DictField()
class File(EmbeddedDocument):
name = StringField(required=True)
size = IntField()
...
fld = Folder(name="fld1")
fl = File(name="fl1.txt",size=10)
fld.fileList["fl1.txt"] = fl
It was working while save but failing when I tried to update the record.
After couple of permutation, I realized that "." in lable used for assigning file object to fileList was problem. Below change in the last line of code worked
fld.fileList["fl1_txt"] = fl

Categories

Resources