python - SQLAlchemy 自动加载插入记录

标签 python postgresql sqlalchemy

PostgreSQL 有学生表:

                                Table "public.student"
 Column |         Type          |                      Modifiers                   
--------+-----------------------+------------------------------------------------------
 id     | integer               | not null default nextval('student_id_seq'::regclass)
 name   | character varying(10) |
 sex    | character varying(6)  |
 age    | integer               |
Indexes:
    "student_pkey" PRIMARY KEY, btree (id)

我可以这样插入一条记录:

Base = declarative_base()

class TableObject(Base):
    __table__ = Table('student', metadata, autoload=True)   

record = TableObject(name="tom", sex="male")
session.add(record)
record = TableObject(name="alice", sex="female", age=10)
session.add(record)

我希望有这样一种方法:

record = TableObject("alice", "female", 10)
session.add(record)

导致错误

TypeError: __init__() takes exactly 1 argument (4 given)

因为我会从一个文件中获取记录,并将每一行拆分成列表,所以如果支持这种方法,那将是非常方便的。

有什么办法吗?

最佳答案

您现在可以插入记录,因为 declarative_base 包含一个采用命名参数的构造函数。该构造函数的代码如下(来自 github repository 的逐字记录):

def _declarative_constructor(self, **kwargs):
    """A simple constructor that allows initialization from kwargs.

    Sets attributes on the constructed instance using the names and
    values in ``kwargs``.

    Only keys that are present as
    attributes of the instance's class are allowed. These could be,
    for example, any mapped columns or relationships.
    """
    cls_ = type(self)
    for k in kwargs:
        if not hasattr(cls_, k):
            raise TypeError(
                "%r is an invalid keyword argument for %s" %
                (k, cls_.__name__))
        setattr(self, k, kwargs[k])
_declarative_constructor.__name__ = '__init__'

因此,如果您想用位置版本替换此构造函数,那么它将适用于您的所有模型。以下可能是一个起点:

def _declarative_positional_constructor(self, *args, **kwargs):
    assert len(kwargs) == 0
    column_names = tuple(c.name for c in self.__mapper__.columns if not(c in self.__mapper__.primary_key))
    assert len(column_names) == len(args)
    for name, value in zip(column_names, args):
        setattr(self, name, value)
_declarative_positional_constructor.__name__ = '__init__'

# ...
# use own default constructor
Base = declarative_base(constructor = _declarative_positional_constructor)

然而,在这种情况下,使用名称创建实例的方法将不起作用。因此,您可以增强它以处理两个版本。
另一件要检查的事情是 autoload 保证表中列的顺序相同,以防止在将“John”写入 Gender 时将“male”存储为名称专栏。

关于python - SQLAlchemy 自动加载插入记录,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20370424/

相关文章:

sql - 从每行中排除最大元素

sql - Postgres : How to set check constraint during an update?

python - SQLAlchemy:禁用延迟加载并仅在 join() 上加载对象

python - 使用 WHERE 在 SQLAlchemy Core 中进行批量更新

python - 在没有子类声明基础的情况下使用 flask-sqlalchemy

python - 如何在 python matplotlib colormap 中增加颜色分辨率

python - 如何在 Python 中将单个函数导出为模块?

python - 如何在 jupyter 笔记本中隐藏 Out[] 单元格

python - 通过字段名称映射接近 Django 模型字段

postgresql - 带有 INSTEAD OF 触发器的 Postgres INSERT ON CONFLICT 行为