A list field that wraps a standard field, allowing multiple instances of the field to be used as a list in the database. If using with ReferenceFields see: :ref:`many-to-many-with-listfields` .. note:: Required means it cannot be empty - as the default for ListFields is []
| 905 | |
| 906 | |
| 907 | class ListField(ComplexBaseField): |
| 908 | """A list field that wraps a standard field, allowing multiple instances |
| 909 | of the field to be used as a list in the database. |
| 910 | |
| 911 | If using with ReferenceFields see: :ref:`many-to-many-with-listfields` |
| 912 | |
| 913 | .. note:: |
| 914 | Required means it cannot be empty - as the default for ListFields is [] |
| 915 | """ |
| 916 | |
| 917 | def __init__(self, field=None, *, max_length=None, **kwargs): |
| 918 | self.max_length = max_length |
| 919 | kwargs.setdefault("default", list) |
| 920 | super().__init__(field=field, **kwargs) |
| 921 | |
| 922 | def __get__(self, instance, owner): |
| 923 | if instance is None: |
| 924 | # Document class being used rather than a document object |
| 925 | return self |
| 926 | value = instance._data.get(self.name) |
| 927 | LazyReferenceField = _import_class("LazyReferenceField") |
| 928 | GenericLazyReferenceField = _import_class("GenericLazyReferenceField") |
| 929 | if ( |
| 930 | isinstance(self.field, (LazyReferenceField, GenericLazyReferenceField)) |
| 931 | and value |
| 932 | ): |
| 933 | instance._data[self.name] = [self.field.build_lazyref(x) for x in value] |
| 934 | return super().__get__(instance, owner) |
| 935 | |
| 936 | def validate(self, value): |
| 937 | """Make sure that a list of valid fields is being used.""" |
| 938 | if not isinstance(value, (list, tuple, BaseQuerySet)): |
| 939 | self.error("Only lists and tuples may be used in a list field") |
| 940 | |
| 941 | # Validate that max_length is not exceeded. |
| 942 | # NOTE It's still possible to bypass this enforcement by using $push. |
| 943 | # However, if the document is reloaded after $push and then re-saved, |
| 944 | # the validation error will be raised. |
| 945 | if self.max_length is not None and len(value) > self.max_length: |
| 946 | self.error("List is too long") |
| 947 | |
| 948 | super().validate(value) |
| 949 | |
| 950 | def prepare_query_value(self, op, value): |
| 951 | # Validate that the `set` operator doesn't contain more items than `max_length`. |
| 952 | if op == "set" and self.max_length is not None and len(value) > self.max_length: |
| 953 | self.error("List is too long") |
| 954 | |
| 955 | if self.field: |
| 956 | # If the value is iterable and it's not a string nor a |
| 957 | # BaseDocument, call prepare_query_value for each of its items. |
| 958 | is_iter = hasattr(value, "__iter__") |
| 959 | eligible_iter = is_iter and not isinstance(value, (str, BaseDocument)) |
| 960 | if ( |
| 961 | op in ("set", "unset", "gt", "gte", "lt", "lte", "ne", None) |
| 962 | and eligible_iter |
| 963 | ): |
| 964 | return [self.field.prepare_query_value(op, v) for v in value] |