SQLAlchemy自动加载插入记录

时间:2013-12-04 08:26:37

标签: 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)

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

有什么办法吗?

2 个答案:

答案 0 :(得分:2)

您可以立即插入记录,因为declarative_base包含一个带有命名参数的构造函数。该construtor的代码如下(逐字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列。 / p>

答案 1 :(得分:0)

你能使用这样的方法:

class TableObject(Base):
    def __init__(self, name, sex, age):
        super(TableObject, self).__init__()
        self.name = name
        self.sex = sex
        self.age = age