我试图更新Postgres上包含Generated列的表中的一些值(通过django)。这是我得到的错误:列“xx_xx”只能更新为DEFAULTSee complete error here
cygmwpex1#
我知道这个问题很老了,但以后可能有人会发现它。尽管在Postgres12(4年前)中引入了生成列,但我在Django中找不到对它的适当支持,所以我自己构建了一个这个答案的灵感来自https://code.djangoproject.com/ticket/21454Django文档https://docs.djangoproject.com/en/4.2/howto/custom-model-fields/这是一个通用字段[接受类似于ArrayField的base_field],您可以将其用作
base_field
line_total = GeneratedField( base_field=models.IntegerField(), expression=F("price") * F("quantity"), help_text=_("line total, calculated as = price * quantity"), )
字符串请注意,您不能引用其他模型中的字段,也不能在表达式中使用子查询或其他生成的字段,如postgresql docs中所述
from django.db.models import Field from django.db.models.expressions import BaseExpression from django.db.models.expressions import Combinable from django.db.models.fields.mixins import CheckFieldDefaultMixin from psycopg2.extensions import AsIs from psycopg2.extensions import register_adapter class PostgresDefaultValueType: pass register_adapter(PostgresDefaultValueType, lambda _: AsIs("DEFAULT")) class GeneratedField(CheckFieldDefaultMixin, Field): def __init__(self, base_field, expression: BaseExpression | Combinable, **kwargs): self.base_field = base_field self.expression = expression kwargs["editable"] = False kwargs["blank"] = True kwargs["default"] = None if hasattr(self.base_field, "from_db_value"): self.from_db_value = self._from_db_value super().__init__(**kwargs) @property def model(self): try: return self.__dict__["model"] except KeyError: raise AttributeError("'%s' object has no attribute 'model'" % self.__class__.__name__) @model.setter def model(self, model): self.__dict__["model"] = model self.base_field.model = model def set_attributes_from_name(self, name): super().set_attributes_from_name(name) self.base_field.set_attributes_from_name(name) @property def description(self): return "Generated Field of %s" % self.base_field.description def has_default(self): return True def _from_db_value(self, value, expression, connection): if value is None: return value return self.base_field.from_db_value(value, expression, connection) def db_type(self, connection): from django.db.models.sql.query import Query base_type = self.base_field.db_type(connection) query = Query(model=self.model, alias_cols=False) compiler = query.get_compiler(connection=connection) sql, params = self.expression.resolve_expression(query).as_sql(compiler=compiler, connection=connection) expr = sql % tuple(connection.schema_editor().quote_value(p) for p in params) return f"{base_type} GENERATED ALWAYS AS ({expr}) STORED" def deconstruct(self): name, path, args, kwargs = super().deconstruct() kwargs.update({"base_field": self.base_field.clone(), "expression": self.expression}) return name, path, args, kwargs def formfield(self, **kwargs): kwargs.setdefault("form_class", self.base_field.formfield()) return super().formfield(**kwargs) def get_prep_value(self, value): # inspired by https://code.djangoproject.com/ticket/21454 if value is None: # avoid adding DEFAULT to the query when migrating return super().get_prep_value(value) return PostgresDefaultValueType()
型免责声明:正如你的问题中提到的,这个答案只适用于PostgreSQL,我猜稍微修改一下就可以让它适用于MySQL了。如果您觉得有用,请将其标记为接受的答案
kgsdhlau2#
您不能以保存/更新其他列的方式编辑生成的列正如PostgreSQL documentation所述不能直接写入生成的列。在UPDATE或UPDATE命令中,不能为生成的列指定值,但可以指定关键字DEFAULT。
2条答案
按热度按时间cygmwpex1#
我知道这个问题很老了,但以后可能有人会发现它。
尽管在Postgres12(4年前)中引入了生成列,但我在Django中找不到对它的适当支持,所以我自己构建了一个
这个答案的灵感来自https://code.djangoproject.com/ticket/21454
Django文档https://docs.djangoproject.com/en/4.2/howto/custom-model-fields/
这是一个通用字段[接受类似于ArrayField的
base_field
],您可以将其用作字符串
请注意,您不能引用其他模型中的字段,也不能在表达式中使用子查询或其他生成的字段,如postgresql docs中所述
型
免责声明:正如你的问题中提到的,这个答案只适用于PostgreSQL,我猜稍微修改一下就可以让它适用于MySQL了。
如果您觉得有用,请将其标记为接受的答案
kgsdhlau2#
您不能以保存/更新其他列的方式编辑生成的列
正如PostgreSQL documentation所述
不能直接写入生成的列。在UPDATE或UPDATE命令中,不能为生成的列指定值,但可以指定关键字DEFAULT。