Example #1
0
    def _verify_model_can_be_initialized(self) -> None:
        """
        Raises exception if model is abstract or has ForwardRefs in relation fields.

        :return: None
        :rtype: None
        """
        if self.Meta.abstract:
            raise ModelError(
                f"You cannot initialize abstract model {self.get_name()}")
        if self.Meta.requires_ref_update:
            raise ModelError(f"Model {self.get_name()} has not updated "
                             f"ForwardRefs. \nBefore using the model you "
                             f"need to call update_forward_refs().")
Example #2
0
 def objects(cls: Type["T"]) -> "QuerySet[T]":  # type: ignore
     if cls.Meta.requires_ref_update:
         raise ModelError(
             f"Model {cls.get_name()} has not updated "
             f"ForwardRefs. \nBefore using the model you "
             f"need to call update_forward_refs()."
         )
     return QuerySet(model_cls=cls)
Example #3
0
    def _process_kwargs(self, kwargs: Dict) -> Tuple[Dict, Dict]:
        """
        Initializes nested models.

        Removes property_fields

        Checks if field is in the model fields or pydatnic fields.

        Nullifies fields that should be excluded.

        Extracts through models from kwargs into temporary dict.

        :param kwargs: passed to init keyword arguments
        :type kwargs: Dict
        :return: modified kwargs
        :rtype: Tuple[Dict, Dict]
        """
        meta = object.__getattribute__(self, "Meta")
        property_fields = meta.property_fields
        model_fields = meta.model_fields
        pydantic_fields = object.__getattribute__(self, "__fields__")

        # remove property fields
        for prop_filed in property_fields:
            kwargs.pop(prop_filed, None)

        excluded: Set[str] = kwargs.pop("__excluded__", set())
        if "pk" in kwargs:
            kwargs[meta.pkname] = kwargs.pop("pk")

        # extract through fields
        through_tmp_dict = dict()
        for field_name in self.extract_through_names():
            through_tmp_dict[field_name] = kwargs.pop(field_name, None)

        try:
            new_kwargs: Dict[str, Any] = {
                k: self._convert_json(
                    k,
                    model_fields[k].expand_relationship(v, self, to_register=False,)
                    if k in model_fields
                    else (v if k in pydantic_fields else model_fields[k]),
                    "dumps",
                )
                for k, v in kwargs.items()
            }
        except KeyError as e:
            raise ModelError(
                f"Unknown field '{e.args[0]}' for model {self.get_name(lower=False)}"
            )

        # explicitly set None to excluded fields
        # as pydantic populates them with default if set
        for field_to_nullify in excluded:
            new_kwargs[field_to_nullify] = None

        return new_kwargs, through_tmp_dict
Example #4
0
 def __get__(
     self,
     instance: Optional[Union["QuerySet", "QuerysetProxy"]],
     owner: Union[Type["Model"], Type["QuerysetProxy"]],
 ) -> "QuerySet":
     if issubclass(owner, ormar.Model):
         if owner.Meta.requires_ref_update:
             raise ModelError(f"Model {owner.get_name()} has not updated "
                              f"ForwardRefs. \nBefore using the model you "
                              f"need to call update_forward_refs().")
     if issubclass(owner, ormar.Model):
         return self.__class__(model_cls=owner)
     return self.__class__()  # pragma: no cover
Example #5
0
    def __init__(self, *args: Any, **kwargs: Any) -> None:  # type: ignore
        """
        Initializer that creates a new ormar Model that is also pydantic Model at the
        same time.

        Passed keyword arguments can be only field names and their corresponding values
        as those will be passed to pydantic validation that will complain if extra
        params are passed.

        If relations are defined each relation is expanded and children models are also
        initialized and validated. Relation from both sides is registered so you can
        access related models from both sides.

        Json fields are automatically loaded/dumped if needed.

        Models marked as abstract=True in internal Meta class cannot be initialized.

        Accepts also special __pk_only__ flag that indicates that Model is constructed
        only with primary key value (so no other fields, it's a child model on other
        Model), that causes skipping the validation, that's the only case when the
        validation can be skipped.

        Accepts also special __excluded__ parameter that contains a set of fields that
        should be explicitly set to None, as otherwise pydantic will try to populate
        them with their default values if default is set.

        :raises ModelError: if abstract model is initialized, model has ForwardRefs
         that has not been updated or unknown field is passed
        :param args: ignored args
        :type args: Any
        :param kwargs: keyword arguments - all fields values and some special params
        :type kwargs: Any
        """
        self._verify_model_can_be_initialized()
        object.__setattr__(self, "_orm_id", uuid.uuid4().hex)
        object.__setattr__(self, "_orm_saved", False)
        object.__setattr__(self, "_pk_column", None)
        object.__setattr__(
            self,
            "_orm",
            RelationsManager(
                related_fields=self.extract_related_fields(),
                owner=self,
            ),
        )

        pk_only = kwargs.pop("__pk_only__", False)
        excluded: Set[str] = kwargs.pop("__excluded__", set())

        if "pk" in kwargs:
            kwargs[self.Meta.pkname] = kwargs.pop("pk")

        # build the models to set them and validate but don't register
        # also remove property fields values from validation
        try:
            new_kwargs: Dict[str, Any] = {
                k: self._convert_json(
                    k,
                    self.Meta.model_fields[k].expand_relationship(
                        v,
                        self,
                        to_register=False,
                    ),
                    "dumps",
                )
                for k, v in kwargs.items() if k not in object.__getattribute__(
                    self, "Meta").property_fields
            }
        except KeyError as e:
            raise ModelError(
                f"Unknown field '{e.args[0]}' for model {self.get_name(lower=False)}"
            )

        # explicitly set None to excluded fields
        # as pydantic populates them with default if set
        for field_to_nullify in excluded:
            new_kwargs[field_to_nullify] = None

        values, fields_set, validation_error = pydantic.validate_model(
            self,
            new_kwargs  # type: ignore
        )
        if validation_error and not pk_only:
            raise validation_error

        object.__setattr__(self, "__dict__", values)
        object.__setattr__(self, "__fields_set__", fields_set)

        # register the columns models after initialization
        for related in self.extract_related_names():
            self.Meta.model_fields[related].expand_relationship(
                new_kwargs.get(related),
                self,
                to_register=True,
            )
Example #6
0
    def __init__(self, *args: Any, **kwargs: Any) -> None:  # type: ignore
        object.__setattr__(self, "_orm_id", uuid.uuid4().hex)
        object.__setattr__(self, "_orm_saved", False)
        object.__setattr__(self, "_pk_column", None)
        object.__setattr__(
            self,
            "_orm",
            RelationsManager(
                related_fields=[
                    field for name, field in self.Meta.model_fields.items()
                    if issubclass(field, ForeignKeyField)
                ],
                owner=self,
            ),
        )

        pk_only = kwargs.pop("__pk_only__", False)
        excluded: Set[str] = kwargs.pop("__excluded__", set())

        if "pk" in kwargs:
            kwargs[self.Meta.pkname] = kwargs.pop("pk")

        # build the models to set them and validate but don't register
        # also remove property fields values from validation
        try:
            new_kwargs: Dict[str, Any] = {
                k: self._convert_json(
                    k,
                    self.Meta.model_fields[k].expand_relationship(
                        v, self, to_register=False, relation_name=k),
                    "dumps",
                )
                for k, v in kwargs.items() if k not in object.__getattribute__(
                    self, "Meta").property_fields
            }
        except KeyError as e:
            raise ModelError(
                f"Unknown field '{e.args[0]}' for model {self.get_name(lower=False)}"
            )

        # explicitly set None to excluded fields
        # as pydantic populates them with default if set
        for field_to_nullify in excluded:
            new_kwargs[field_to_nullify] = None

        values, fields_set, validation_error = pydantic.validate_model(
            self,
            new_kwargs  # type: ignore
        )
        if validation_error and not pk_only:
            raise validation_error

        object.__setattr__(self, "__dict__", values)
        object.__setattr__(self, "__fields_set__", fields_set)

        # register the columns models after initialization
        for related in self.extract_related_names():
            self.Meta.model_fields[related].expand_relationship(
                new_kwargs.get(related),
                self,
                to_register=True,
                relation_name=related)