A truly dynamic field type capable of handling different and varying types of data. Used by :class:`~mongoengine.DynamicDocument` to handle dynamic data
| 844 | |
| 845 | |
| 846 | class DynamicField(BaseField): |
| 847 | """A truly dynamic field type capable of handling different and varying |
| 848 | types of data. |
| 849 | |
| 850 | Used by :class:`~mongoengine.DynamicDocument` to handle dynamic data""" |
| 851 | |
| 852 | def to_mongo(self, value, use_db_field=True, fields=None): |
| 853 | """Convert a Python type to a MongoDB compatible type.""" |
| 854 | |
| 855 | if isinstance(value, str): |
| 856 | return value |
| 857 | |
| 858 | if hasattr(value, "to_mongo"): |
| 859 | cls = value.__class__ |
| 860 | val = value.to_mongo(use_db_field, fields) |
| 861 | # If we its a document thats not inherited add _cls |
| 862 | if isinstance(value, Document): |
| 863 | val = {"_ref": value.to_dbref(), "_cls": cls.__name__} |
| 864 | if isinstance(value, EmbeddedDocument): |
| 865 | val["_cls"] = cls.__name__ |
| 866 | return val |
| 867 | |
| 868 | if not isinstance(value, (dict, list, tuple)): |
| 869 | return value |
| 870 | |
| 871 | is_list = False |
| 872 | if not hasattr(value, "items"): |
| 873 | is_list = True |
| 874 | value = {k: v for k, v in enumerate(value)} |
| 875 | |
| 876 | data = {} |
| 877 | for k, v in value.items(): |
| 878 | data[k] = self.to_mongo(v, use_db_field, fields) |
| 879 | |
| 880 | value = data |
| 881 | if is_list: # Convert back to a list |
| 882 | value = [v for k, v in sorted(data.items(), key=itemgetter(0))] |
| 883 | return value |
| 884 | |
| 885 | def to_python(self, value): |
| 886 | if isinstance(value, dict) and "_cls" in value: |
| 887 | doc_cls = get_document(value["_cls"]) |
| 888 | if "_ref" in value: |
| 889 | value = doc_cls._get_db().dereference(value["_ref"]) |
| 890 | return doc_cls._from_son(value) |
| 891 | |
| 892 | return super().to_python(value) |
| 893 | |
| 894 | def lookup_member(self, member_name): |
| 895 | return member_name |
| 896 | |
| 897 | def prepare_query_value(self, op, value): |
| 898 | if isinstance(value, str): |
| 899 | return StringField().prepare_query_value(op, value) |
| 900 | return super().prepare_query_value(op, self.to_mongo(value)) |
| 901 | |
| 902 | def validate(self, value, clean=True): |
| 903 | if hasattr(value, "validate"): |
no outgoing calls
no test coverage detected