A reference to *any* :class:`~mongoengine.document.Document` subclass that will be automatically dereferenced on access (lazily). Note this field works the same way as :class:`~mongoengine.document.ReferenceField`, doing database I/O access the first time it is accessed (even if it's to
| 1440 | |
| 1441 | |
| 1442 | class GenericReferenceField(BaseField): |
| 1443 | """A reference to *any* :class:`~mongoengine.document.Document` subclass |
| 1444 | that will be automatically dereferenced on access (lazily). |
| 1445 | |
| 1446 | Note this field works the same way as :class:`~mongoengine.document.ReferenceField`, |
| 1447 | doing database I/O access the first time it is accessed (even if it's to access |
| 1448 | it ``pk`` or ``id`` field). |
| 1449 | To solve this you should consider using the |
| 1450 | :class:`~mongoengine.fields.GenericLazyReferenceField`. |
| 1451 | |
| 1452 | .. note :: |
| 1453 | * Any documents used as a generic reference must be registered in the |
| 1454 | document registry. Importing the model will automatically register |
| 1455 | it. |
| 1456 | |
| 1457 | * You can use the choices param to limit the acceptable Document types |
| 1458 | """ |
| 1459 | |
| 1460 | def __init__(self, *args, **kwargs): |
| 1461 | choices = kwargs.pop("choices", None) |
| 1462 | super().__init__(*args, **kwargs) |
| 1463 | self.choices = [] |
| 1464 | # Keep the choices as a list of allowed Document class names |
| 1465 | if choices: |
| 1466 | for choice in choices: |
| 1467 | if isinstance(choice, str): |
| 1468 | self.choices.append(choice) |
| 1469 | elif isinstance(choice, type) and issubclass(choice, Document): |
| 1470 | self.choices.append(choice._class_name) |
| 1471 | else: |
| 1472 | # XXX ValidationError raised outside of the "validate" |
| 1473 | # method. |
| 1474 | self.error( |
| 1475 | "Invalid choices provided: must be a list of" |
| 1476 | "Document subclasses and/or str" |
| 1477 | ) |
| 1478 | |
| 1479 | def _validate_choices(self, value): |
| 1480 | if isinstance(value, dict): |
| 1481 | # If the field has not been dereferenced, it is still a dict |
| 1482 | # of class and DBRef |
| 1483 | value = value.get("_cls") |
| 1484 | elif isinstance(value, Document): |
| 1485 | value = value._class_name |
| 1486 | super()._validate_choices(value) |
| 1487 | |
| 1488 | @staticmethod |
| 1489 | def _lazy_load_ref(ref_cls, dbref): |
| 1490 | dereferenced_son = ref_cls._get_db().dereference(dbref) |
| 1491 | if dereferenced_son is None: |
| 1492 | raise DoesNotExist(f"Trying to dereference unknown document {dbref}") |
| 1493 | |
| 1494 | return ref_cls._from_son(dereferenced_son) |
| 1495 | |
| 1496 | def __get__(self, instance, owner): |
| 1497 | if instance is None: |
| 1498 | return self |
| 1499 |