如何将基表中的列与基于用户注册创建的用户表结合起来
Posted
技术标签:
【中文标题】如何将基表中的列与基于用户注册创建的用户表结合起来【英文标题】:How to combine columns from base table with user table created based on user registration 【发布时间】:2018-07-30 21:23:02 【问题描述】:我有一个表的 BaseModel 定义如下:
class BaseModel(db.Model):
"""
a base model for other database tables to inherit
"""
__abstract__ = True
userid = db.Column(db.Integer, primary_key=True, autoincrement=True)
date_created = db.Column(db.DateTime, default=db.func.current_timestamp())
date_modified = db.Column(db.DateTime, default=db.func.current_timestamp(),
onupdate=db.func.current_timestamp())
现在这是Users
表和ApiKey
表的基表,但我在用户注册时创建了另一个表
因此新表是根据电子邮件地址动态创建的。
# if user exists get table name
user_table_name = user_exists.email.replace("@", "_").replace(".", "_")
# Check if table for the user exists.
if not engine.dialect.has_table(engine, user_table_name):
metadata = MetaData(engine)
user_table = IpMap(user_table_name, meta,
Column("ipaddress", CIDR, nullable=False),
Column("urlmap", String(10), nullable=False, unique=True),
Columnb("port", Integer, unique=True, index=True),
Column("device", String(10)),
Column("path", String(30)),
Column("service_name", String(10)),
Column("count_updates", Integer)
)
user_table.create(engine)
else:
meta = MetaData(engine, reflect=True)
user_table = meta.tables[user_table_name]
因此,对于这个基于用户电子邮件的表,我还想利用 BaseModel
,因此我选择创建自己的表并将 sqlalchemy.Table
和 BaseModel
子类化为 db.Model
的子类。
但这会引发错误。
class IpMap(Table, BaseModel):
TypeError: Error when calling the metaclass bases
metaclass conflict: the metaclass of a derived class must be a (non-strict) subclass of the metaclasses of all its bases
我什至无法启动我的烧瓶应用程序。我怎样才能做到这一点?
【问题讨论】:
【参考方案1】:我不确定您尝试做的任何事情都会奏效,因为无法保证将复杂层次结构中的复杂类组合在一起。
在这种情况下,尽管您没有提及它,但您正在尝试将 db.Model
我认为是 flask_sqlalchemy 使用的类与 sqlalchmey.table 结合起来——这两个类都“充满了魔术”,这包括每个都有不同的元类。
Python 不会实例化从独立元类继承的类——相反,您会得到刚刚看到的“元类冲突”错误。但是,如果元类的编写方式可能是协作的,那么只需将两个元类结合起来,这可以在一行代码中完成。
查看sqlalchemy.Table
的元类的源代码,即this file 中的VisitableType
,我们看到它确实在重要的地方使用了super
。这应该是类协作所需要的全部 - 尽管不能确定属性名称或元类实现的其他自定义机制不会发生冲突。
无论如何,检查一下,您的代码构建并且您能够从两个类继承所需的一切就是创建组合元类:
class Meta(type(sqlalchemy.Table), type(db.Model)): pass
然后,这应该可以工作:
class IpMap(Table, BaseModel, metaclass=Meta):
...
(我将在下面粘贴一个完整的 sn-p,以便其他研究此问题的人有一些自包含的代码用于他们的实验)
import flask
from flask_sqlalchemy import SQLAlchemy
import sqlalchemy
app = flask.Flask("bla")
app.config["SQLALCHEMY_DATABASE_URI"]="sqlite://"
db = SQLAlchemy(app)
print (f"metaclass for db.Model: type(db.Model)")
print (f"metaclass for sqlalchemy.Table: type(sqlalchemy.Table)")
# This will raise a metaclass conflict:
class A(sqlalchemy.Table, db.Model):
pass
# combining the metaclasses
class Meta(type(sqlalchemy.Table), type(db.Model)): pass
# Working example
# (with dummy primary key filed, otherwise one gets an sqlalchemy error)
class B(sqlalchemy.Table, db.Model, metaclass=Meta):
id = sqlalchemy.Column(sqlalchemy.INT, name="id", primary_key=True)
【讨论】:
我想要创建带有userid
、 date_created
和 date_modified
字段的 user_table
以及来自 BaseModel
类。以上是关于如何将基表中的列与基于用户注册创建的用户表结合起来的主要内容,如果未能解决你的问题,请参考以下文章