Closed ttiimmaahh closed 1 year ago
Hi @ttiimmaahh I am also trying List of Reference Fields and getting the error .Did you got any solution for it ?
TypeError: ('Cannot convert to a Firestore Value', <__main__.Keyword object at 0x00000210CDD8F7F0>, 'Invalid type', <class '__main__.Keyword'>)
If ListField
is not fullfil your requirement then you can extend it Create Custom Field
You can also use Base Field
Hi! I implemented it in the next way:
class TypedListField(ListField):
allowed_attributes = ['nested_field']
nested_field: Field
def __init__(self, nested_field, *args, **kwargs):
if not isinstance(nested_field, Field):
raise AttributeTypeError('"nested_field" must be an instance of "Field".')
super().__init__(*args, **kwargs, nested_field=nested_field)
def contribute_to_model(self, model_cls, name):
super().contribute_to_model(model_cls, name)
self.raw_attributes['nested_field'].name = name
self.raw_attributes['nested_field'].model_cls = model_cls
def attr_nested_field(self, attr_val, field_val):
return field_val
def db_value(self, val: list[Any] | None) -> list[Any] | None:
"""Serialize using nested field."""
serialized = super().db_value(val)
if serialized is not None:
serialized = [
self.raw_attributes['nested_field'].db_value(item)
for item in serialized
]
return serialized
def field_value(self, val: list[Any] | None) -> list[Any] | None:
"""Deserialize enum from value"""
parsed = super().field_value(val)
if parsed is not None:
parsed = [
self.raw_attributes['nested_field'].field_value(item)
for item in parsed
]
return parsed
But I would prefer to have it out of the box... I can create PR with changes to original ListField
And list of models:
class NestedListField(ListField):
allowed_attributes = ['nested_model_class']
nested_model_class: Model
def __init__(self, nested_model_class, *args, **kwargs):
if not issubclass(nested_model_class, Model):
raise AttributeTypeError('"nested_model_class" must be a subclass of "Model".')
super().__init__(*args, **kwargs, nested_model_class=nested_model_class)
def attr_nested_model_class(self, attr_val, field_val):
return field_val
def get_value(self, val, ignore_required=False, ignore_default=False):
items: list[Model] = super().get_value(val, ignore_required, ignore_default)
results = []
for item in items:
item_dict = {}
for nested_field in self.raw_attributes['nested_model_class']._meta.field_list.values():
nested_field: Field
nested_field_value = getattr(item, nested_field.name)
value = nested_field.get_value(nested_field_value, ignore_required, ignore_default)
if value is not None:
item_dict[nested_field.db_column_name] = value
results.append(item_dict)
return results
def field_value(self, val):
parsed = super().field_value(val)
if not parsed:
return parsed
parsed = [
ModelWrapper.from_query_result(
self.raw_attributes['nested_model_class'](),
item,
True,
)
for item in parsed
]
return parsed
Thanks for this implementation. PR are welcomes, You can create a PR
Firestore supports the ability to create an array (list) of reference fields. I'm not 100% sure if this is a limitation of the google firestore library or if its on the fireo side, but I'm unable to do that via code. I'm able to do it manually via the GCP console, but querying all of the objects fails just as it does when trying to create that object scenario.
Has anyone come across this before?
` class MyFirstModel(Model): field1 = TextField() field2 = TextField()
class MySecondModel(Model): field1 = TextField() field2 = ListField(ReferenceField(MyFirstModel))`