Open oraix opened 4 years ago
As a workaround, I fall back the version to djongo 1.2.38 with rest_meets_djongo 0.0.11 with a patch for lookup to resolve filter issue
from django.db.models import Model
from django.db.models.lookups import PatternLookup, IExact
from djongo.models import fields
from djongo.models.fields import useful_field
# replace original lookup.py the method of PatternLookup.process_rhs
# def process_rhs(self, qn, connection):
# rhs, params = super().process_rhs(qn, connection)
# if self.rhs_is_direct_value() and params and not self.bilateral_transforms:
# params[0] = self.param_pattern % connection.ops.prep_for_like_query(params[0])
# return rhs, params
def process_rhs_pattern(self, qn, connection):
rhs, params = super(PatternLookup, self).process_rhs(qn, connection)
if self.rhs_is_direct_value() and params and not self.bilateral_transforms:
if isinstance(params[0], dict):
# Prevent Django's PatternLookup from casting our query dict {'field': 'to_match'}
# to a str "%{'field': 'to_match'}%"
field, to_match = next(iter(params[0].items()))
params[0] = {field: self.param_pattern % connection.ops.prep_for_like_query(to_match)}
connection.ops.prep_for_like_query(to_match)
else:
params[0] = self.param_pattern % connection.ops.prep_for_like_query(params[0])
return rhs, params
def process_rhs_iexact(self, qn, connection):
rhs, params = super(IExact, self).process_rhs(qn, connection)
if params:
if isinstance(params[0], dict):
# Prevent Django's PatternLookup from casting our query dict {'field': 'to_match'}
# to a str "%{'field': 'to_match'}%"
field, to_match = next(iter(params[0].items()))
params[0] = {field: connection.ops.prep_for_iexact_query(to_match)}
connection.ops.prep_for_like_query(to_match)
else:
params[0] = connection.ops.prep_for_iexact_query(params[0])
return rhs, params
class MyArrayModelField(fields.ArrayModelField):
def get_db_prep_value(self, value, connection, prepared=False):
if prepared:
return value
if value is None and self.blank:
return None
if not isinstance(value, list):
raise ValueError(
'Expected value to be type list,'
f'Got type {type(value)} instead'
)
ret = []
for a_mdl in value:
mdl_ob = {}
if not isinstance(a_mdl, Model):
raise ValueError('Array items must be Model instances')
for fld in a_mdl._meta.get_fields():
if not useful_field(fld):
continue
fld_value = getattr(a_mdl, fld.attname)
mdl_ob[fld.attname] = fld.get_db_prep_value(fld_value, connection, prepared)
ret.append(mdl_ob)
return ret
def get_lookup(self, lookup_name):
"""
Make django use our `get_lookup` method
when building the lookup class for an EmbeddedModelField instance.
"""
lookup = super(self.__class__, self).get_lookup(lookup_name)
if issubclass(lookup, PatternLookup):
lookup = type('Djongo' + lookup.__name__, (lookup,), {'process_rhs': process_rhs_pattern})
elif issubclass(lookup, IExact):
lookup = type('Djongo' + lookup.__name__, (lookup,), {'process_rhs': process_rhs_iexact})
return lookup
class MyEmbeddedModelField(fields.EmbeddedModelField):
def get_lookup(self, lookup_name):
"""
Make django use our `get_lookup` method
when building the lookup class for an EmbeddedModelField instance.
"""
lookup = super(self.__class__, self).get_lookup(lookup_name)
if issubclass(lookup, PatternLookup):
lookup = type('Djongo' + lookup.__name__, (lookup,), {'process_rhs': process_rhs_pattern})
elif issubclass(lookup, IExact):
lookup = type('Djongo' + lookup.__name__, (lookup,), {'process_rhs': process_rhs_iexact})
return lookup
Can you please give us the use-case that raises said error (is it an update, creation, or retrieval)? I suspect that whats happening is you're trying to update the value to null; I'm currently patching that into rest-meets-djongo, as its not yet supported (slight oversight, my apologies). If its something else, please let us know so we can make a more representative test cases.
Update; changes allowing null updates have been made, and are available in v0.0.13 of rest-meets-djongo. Hopefully that fixes the issue
the issue was triggered when insert data for nested model.
File "D:\dev\virtualenvs\apienv\lib\site-packages\djongo\models\fields.py", line 139, in _value_thru_fields
field_value = value[field.attname]
TypeError: 'Note' object is not subscriptable
Value is assigned as a Note object, the expression is not valid for it. I guess it should be a OrderedDict.
Are you passing in a Note without wrapping it in a list? Seems like the most likely culprit here. (I'll look into adding a more informative error message for that case)
EDIT: Doing some quick testing with 1.3.1, that doesn't seem to be the case either (and my error messages report it as such, regardless of initially submitted type)
@oraix I was also facing the same issue and you can solve this by wrapping the dictionary data in a list. Follow these steps in your case :
person_obj, person_created = Person.objects.get_or_create(name = <"any name">) if person_created: person_obj.gender = "Male" person_obj.principal = false data = {"subject":"Computer Science","text":"Computer science is AWESOME"} person_obj.notes=[data] person_obj.save()
I made a workaround, I had added the following code in my abstract model. I your case, the note model.
class Note(models.Model):
subject = models.CharField(max_length=128, null=True, blank=True)
text = models.TextField(max_length=1024, blank=True)
def __getitem__(self, name):
return getattr(self, name)
I made a workaround, I had added the following code in my abstract model. I your case, the note model.
class Note(models.Model): subject = models.CharField(max_length=128, null=True, blank=True) text = models.TextField(max_length=1024, blank=True) def __getitem__(self, name): return getattr(self, name)
Thanks you, It's a very helpful workaround.
@nesdis can you update this workaround in the code samples of djongomapper website
One line description of the issue
Error when insert data to Mongodb with Djongo (install last version from github) TypeError: 'Note' object is not subscriptable
Python script