Python 在sqlalchemy映射的类构造函数中忽略额外关键字的选项?
根据下面的内容,我正在尝试从一个具有额外键的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
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()
哇,这太有用了。非常感谢。