【发布时间】:2021-07-22 22:32:52
【问题描述】:
上下文
我有三个表,Users、Subreddits 和 Keywords。思路是users可以监控多个subreddits,subreddits可以监控多个keywords。
由于一个用户可以监控多个 subreddit,而一个 subreddit 可以有多个用户监控它,我希望在 Users 和 Subreddits 之间建立多对多的关系。
同理,由于一个subreddit可以监控多个关键字,一个关键字可以被多个subreddit监控,我希望Subreddits和Keywords之间有一个多对多的关系。
我使用的是 association object 而不是 2 association tables,因为我有 3 个表要相互关联,而关联表仅用于 2 个表之间的关系。
实现
以下是我如何实现每个表,以及关联对象:
用户
class User(db.Model, JsonSerializer):
__tablename__ = 'users'
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(64), index=True, unique=True)
email = db.Column(db.String(128), index=True, unique=True)
password_hash = db.Column(db.String(128))
phone_num = db.Column(db.String(64), index=True, unique=True)
received_posts = db.Column(db.String(128), index=True, unique=True)
monitor = db.relationship('Monitor', back_populates='user')
//...
子版块
class Subreddit(db.Model, JsonSerializer):
__tablename__ = 'subreddits'
id = db.Column(db.Integer, primary_key=True)
subreddit_name = db.Column(db.String(128), index=True)
// ...
关键字
class Keyword(db.Model, JsonSerializer):
__tablename__ = 'keywords'
id = db.Column(db.Integer, primary_key=True)
keyword = db.Column(db.String(128), index=True)
monitor = db.relationship('Monitor', back_populates='keyword')
// ...
关联对象:
class Monitor(db.Model):
__table_name__ = 'monitors'
id = db.Column(db.Integer, primary_key=True)
user_id = db.Column(db.Integer, db.ForeignKey("users.id"), nullable=True)
subreddit_id = db.Column(db.Integer, db.ForeignKey("subreddits.id"), nullable=True)
keyword_id = db.Column(db.Integer, db.ForeignKey("keywords.id"), nullable=True)
user = db.relationship('User', back_populates='monitor')
subreddit = db.relationship('Subreddit')
keyword = db.relationship('Keyword', back_populates='monitor')
我要做什么
理想情况下,每次user 跟踪subreddit 和相应的多个keywords,所有这些信息都存储到monitor 对象中。
例如,
-
user1监控subreddit1,它正在跟踪keyword1和keyword2。 - 所有这些关系都应该存储在
monitor1。
这应该会导致:
- monitor1.user =
user1 - monitor1.subreddit =
subreddit1 - monitor1.keyword =
keyword1, keyword2
我试过的
方法#1
使用keywords 列表初始化monitor 实例。
# Parse the incoming data.
incoming = request.get_json()
subreddit_name = incoming["subredditName"]
subreddit_keywords = incoming["subredditKeywords"]
logged_in_user_id = incoming["id"]
# Query the User.
user = User.query.get(logged_in_user_id)
# Query the Subreddit.
subreddit = Subreddit.query.filter_by(subreddit_name=subreddit_name).first()
# Create a list of Keywords.
monitor_keywords = []
for kw in subreddit_keywords:
# check if Keyword objects are in the database already
if Keyword.query.filter_by(keyword=kw).first() is not None:
keyword = Keyword.query.filter_by(keyword=kw).first()
else: # create new Keyword objects
keyword = Keyword(kw)
monitor_keywords.append(keyword)
# Create the monitoring1 association object.
monitor1 = Monitor(user=user, subreddit=subreddit, keyword=monitor_keywords) <----- Problem
db.session.add(monitor1)
db.session.commit()
我无法用keyword=monitor_keywords 初始化monitor1。
我收到以下错误:
AttributeError: 'list' object has no attribute '_sa_instance_state'。
Stack Overflow 上的其他提交与我的特定错误案例无关。
方法#2到#5
我尝试先初始化一个 monitor 对象,然后将多个 keywords 附加到它上面,但这也没有用。
# Query the User
user = User.query.get(logged_in_user_id)
# Create the association object
monitor = Monitor(user=user, subreddit=None, keyword=None)
db.session.add(monitor)
// ...
for kw in subreddit_keywords:
# check if Keyword objects are in the database already
if Keyword.query.filter_by(keyword=kw).first() is not None:
keyword = Keyword.query.filter_by(keyword=kw).first()
else: # create new Keyword objects
keyword = Keyword(kw)
# Initialize monitor.keyword so we can append to it.
if (monitor.keyword is None):
monitor.keyword = keyword
else: #All failed attempts to append to monitor.keyword.
# monitor.keyword.append(keyword) <- Method #2
# keyword.append(monitor) <- Method #3
# monitor.append(keyword) <- Method #4
# user.monitor.append(keyword) <- Method #5
问题
当我初始化一个关联对象时,我需要用多个keywords来初始化它。
无论是用keywords初始化关联对象,还是以后用keywords更新关联对象,都不起作用。理想情况下,我想坚持方法 #1 的方法,但我愿意接受其他建议。
【问题讨论】:
标签: python sqlalchemy many-to-many flask-sqlalchemy associations