Python 在sqlalchemy映射的类构造函数中忽略额外关键字的选项?

Python 在sqlalchemy映射的类构造函数中忽略额外关键字的选项?,python,orm,sqlalchemy,Python,Orm,Sqlalchemy,根据下面的内容,我正在尝试从一个具有额外键的python字典初始化一个sqlalchemy映射类。是否可以让映射类自动忽略额外的键而不是抛出错误?同样,如果键不存在,映射类是否可以具有默认值 from sqlalchemy import Column, Integer, String class User(Base): __tablename__ = 'users' id = Column(Integer, primary_key=True) name = Col

根据下面的内容,我正在尝试从一个具有额外键的python字典初始化一个sqlalchemy映射类。是否可以让映射类自动忽略额外的键而不是抛出错误?同样,如果键不存在,映射类是否可以具有默认值

from sqlalchemy import Column, Integer, String
class User(Base):
     __tablename__ = 'users'

     id = Column(Integer, primary_key=True)
     name = Column(String)
以下是初始部分:

my_example_user = {'id'=1, 'name'='john', 'extra_key'= 1234}
User(**my_example_user)
这会引发无效的密钥错误


想法?

简而言之,定义构造函数,它不将参数传递给它的超类:

class User(Base):

    # ...

    def __init__(self, **entries):

        # NOTE: Do not call superclass
        #       (which is otherwise a default behaviour).
        #super(User, self).__init__(**entries)

        self.__dict__.update(entries)
我在转换过程中遇到了同样的问题,它要求相反的参数传递给它的超类(因此,构造函数已经定义)。所以,我试着把这句话注释出来,事情就开始起作用了

更新


另外,确保
条目
不包含(因此,覆盖)为SQLAlchemy定义的
用户
类中的任何元字段,例如,那些ORM关系。这是很明显的(SQLAlchemy),但是当出现错误时,可能不容易发现问题。

我们是否可以保证超类的
\uuuuuu init\uuuu
除了设置
\uuu dict\uu
条目之外,不会有其他想要的效果?我觉得完全绕过超类调用并不舒服,所以我尝试解决这个问题的方法如下,只传递与列名对应的条目:

class User(Base):

    # ...

    def __init__(self, **entries):
        '''Override to avoid TypeError when passed spurious column names'''
        col_names = set([col.name for col in self.__table__.columns])
        superentries = {k : entries[k] for k in col_names.intersection(entries.keys())}
        super().__init__(**superentries)

另外,要传递额外的关键字并调用
Base.\uuuu init\uuu()
方法,您可以从
super()
中排除额外关键字,然后执行所需操作:

from sqlalchemy import Column, Integer, String

class User(Base):
     __tablename__ = 'users'

     id = Column(Integer, primary_key=True)
     name = Column(String)

     def __init__(self, **kwargs):
         extra_kw_list = ['key1', 'key2']
         super(User, self).__init__(**{x: y for x, y in kwargs.items()
                                       if x not in extra_kw_list})
         #do something you need here
         item1, item2 = kwargs['key1'], kwargs['key2']

根据R Yakovlev的回答,您可以将元素列表动态化:

from sqlalchemy import Column, Integer, String

class User(Base):
    __tablename__ = 'users'

    id = Column(Integer, primary_key=True)
    name = Column(String)
    def __init__(self, **kwargs):
        keep_kwargs = {k: v for k, v in kwargs.items() if k in user_columns}
        super(User, self).__init__(**keep_kwargs)


user_columns = [_ for _ in User.__dict__.keys() if not _.startswith('_')]
我想尝试找到一种方法,将user\u列嵌入到对象中,就像使用@hybrid\u属性一样,但不要每次使用它时都调用它


我希望这是可能的,但超出了我的时间限制。

SQLAlchemy
Mapper
对象有一个
attrs
属性,它是映射类字段名称的字典

from sqlalchemy import Column, Integer, String
from sqlalchemy.orm import class_mapper
from sqlalchemy.ext.declarative import declarative_base
Base = declarative_base()

class User(Base):
    __tablename__ = 'user'

    id = Column(Integer, primary_key=True)
    name = Column(String)

user = {
    'name': 'Eihli',
    'skill': 11
}

user_mapper = class_mapper(User)
mapped_user = User(**user)
# Boom! TypeError: 'skill' is an invalid keyword argument for User

mapped_user = User(**{
    k: v for k, v in user.items()
    if k in user_mapper.attrs.keys()
})
# Success!
无需维护排除列表,也无需乱动dict,也无需妨碍超级呼叫

如果您试图用嵌套数据生成模型,那么您必须做一些不同的事情。否则,您将得到一个“不可损坏的类型'dict'”错误

下面是一个帮助器的示例,用于检查映射器并获取关系的键

def from_json(model, data):
    mapper = class_mapper(model)
    keys = mapper.attrs.keys()
    relationships = inspect(mapper).relationships
    args = {k: v for k, v in data.items()
            if k in keys and k not in relationships}
    return model(**args)

如果模型具有关系,则可以使用模型的
映射器
对象,如@eric ihli。下面是另一种方法(注意
\uuuuu init\uuuu
方法):

来自sqlalchemy导入列,ForeignKey,Integer,String
从sqlalchemy.orm导入backref,关系
从my_app.db_模型导入库
类别雇员(基本):
__tablename_=“employee”
id=列(整数,主键=True,自动递增=True)
department\u id=列(整数,ForeignKey(“department.id”),index=True)
email=列(字符串,unique=True,index=True,nullable=False)
名称=列(字符串)
部门=关系(
“部门”,backref=backref(“员工”,cascade=“全部,删除孤儿”)
)
定义初始(自我,**kwargs):
allowed_args=self.uuuu mapper_uuuu.class_uManager_35;返回一个dict
kwargs={k:v代表k,kwargs.items()中的v如果k在允许的参数中}
超级()
这样,您可以创建如下员工模型:

从contextlib导入关闭
从my_app.db_模型导入部门、员工、会话本地
关闭(SessionLocal())为db时:
dept=db.query(Department.filter(Department.name=='HR')。first()
雇员=雇员(姓名='John Smith',电子邮件='john@smith.com,department=dept)
db.add(员工)
db.commit()

哇,这太有用了。非常感谢。