Exemple #1
0
    def get_update_sql(
        self,
        update_fields: Optional[Iterable[str]],
        arithmetic_or_function: Optional[Dict[str, Union[ArithmeticExpression,
                                                         Function]]],
    ) -> str:
        """
        Generates the SQL for updating a model depending on provided update_fields.
        Result is cached for performance.
        """
        key = ",".join(update_fields) if update_fields else ""
        if key in self.update_cache:
            return self.update_cache[key]
        arithmetic_or_function = arithmetic_or_function or {}
        table = self.model._meta.basetable
        query = self.db.query_class.update(table)
        count = 0
        for field in update_fields or self.model._meta.fields_db_projection.keys(
        ):
            db_column = self.model._meta.fields_db_projection[field]
            field_object = self.model._meta.fields_map[field]
            if not field_object.pk:
                if field not in arithmetic_or_function.keys():
                    query = query.set(db_column, self.parameter(count))
                    count += 1
                else:
                    value = F.resolver_arithmetic_expression(
                        self.model, arithmetic_or_function.get(field))[0]
                    query = query.set(db_column, value)

        query = query.where(
            table[self.model._meta.db_pk_column] == self.parameter(count))

        sql = self.update_cache[key] = query.get_sql()
        return sql
Exemple #2
0
    def resolve(self, model: "Type[Model]", table: Table) -> dict:
        """
        Used to resolve the Function statement for SQL generation.

        :param model: Model the function is applied on to.
        :param table: ``pypika.Table`` to keep track of the virtual SQL table
            (to allow self referential joins)
        :return: Dict with keys ``"joins"`` and ``"fields"``
        """

        if isinstance(self.field, str):
            function = self._resolve_field_for_model(model, table, self.field)
            function["field"] = self._get_function_field(function["field"], *self.default_values)
            return function

        field, field_object = F.resolver_arithmetic_expression(model, self.field)
        if self.populate_field_object:
            self.field_object = field_object
        return {"joins": [], "field": self._get_function_field(field, *self.default_values)}
Exemple #3
0
    def _make_query(self) -> None:
        table = self.model._meta.basetable
        self.query = self._db.query_class.update(table)
        self.resolve_filters(
            model=self.model,
            q_objects=self.q_objects,
            annotations=self.annotations,
            custom_filters=self.custom_filters,
        )
        # Need to get executor to get correct column_map
        executor = self._db.executor_class(model=self.model, db=self._db)

        for key, value in self.update_kwargs.items():
            field_object = self.model._meta.fields_map.get(key)
            if not field_object:
                raise FieldError(
                    f"Unknown keyword argument {key} for model {self.model}")
            if field_object.pk:
                raise IntegrityError(
                    f"Field {key} is PK and can not be updated")
            if isinstance(field_object,
                          (ForeignKeyFieldInstance, OneToOneFieldInstance)):
                fk_field: str = field_object.source_field  # type: ignore
                db_field = self.model._meta.fields_map[fk_field].source_field
                value = executor.column_map[fk_field](getattr(
                    value, field_object.to_field_instance.model_field_name),
                                                      None)
            else:
                try:
                    db_field = self.model._meta.fields_db_projection[key]
                except KeyError:
                    raise FieldError(
                        f"Field {key} is virtual and can not be updated")
                if isinstance(value, Term):
                    value = F.resolver_arithmetic_expression(
                        self.model, value)[0]
                elif isinstance(value, Function):
                    value = value.resolve(self.model, table)["field"]
                else:
                    value = executor.column_map[key](value, None)

            self.query = self.query.set(db_field, value)