How To Fix Sqlalchemy Form "db.session.commit()" To The Wrong Parent Object?
Solution 1:
I agree with the previous speaker (@PGHE). It's not the session. Your query for the "scrapingAccounts" is the reason. The query is based on the id passed in the URL. However, this belongs to the BotList.
<formaction="/update/{{bot.id}}"method="POST">
However, you ask for an account here.
accounts = scrapingAccount.query.get_or_404(id)
The most sensible thing would be if you would not write everything in the same route but would distribute tasks to several. This not only improves the structure of your application, but also makes it clearer. The CRUD paradigm could serve as a guide for a better structure. Using blueprints can make this even easier.
The following approach is a hacky, quick fix.
# ParentclassbotList(db.Model):
__tablename__ = 'botlist'id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(200), nullable=False)
channel = db.Column(db.String(200), nullable=False)
bots = db.Column(db.Integer, nullable=False)
status = db.Column(db.String(200), nullable=False)
igUsername = db.Column(db.String(200), nullable=True)
igPassword = db.Column(db.String(200), nullable=True)
ytUsername = db.Column(db.String(200), nullable=True)
ytPassword = db.Column(db.String(200), nullable=True)
scrapingAccounts = db.relationship("scrapingAccount",
backref="owner",
lazy='dynamic',
# Make sure that the referenced child objects are deleted when the # parent object is deleted.
cascade="all, delete-orphan"
)
def__repr__(self):
return'<Username %r>' % self.id# ChildclassscrapingAccount(db.Model):
__tablename__ = 'scrapingaccount'id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(200), nullable=False)
username = db.Column(db.String(200), nullable=False)
# To avoid unassigned accounts, you can forbid empty entries for the foreign key.# An error will be thrown if you try to set it to null / none.
owner_id = db.Column(db.Integer, db.ForeignKey("botlist.id"), nullable=False)
@app.route('/update/<int:id>', methods=['GET', 'POST'])defupdateBot(id):
bot_to_update = botList.query.get_or_404(id)
if request.method == "POST":
# If it is a POST request.if request.form.get("updateBotButton"):
bot_to_update.username = request.form['username']
bot_to_update.channel = request.form['channel']
bot_to_update.bots = request.form['bots']
bot_to_update.status = request.form['status']
bot_to_update.igUsername = request.form['igUsername']
bot_to_update.igPassword = request.form['igPassword']
bot_to_update.ytUsername = request.form['ytUsername']
bot_to_update.ytPassword = request.form['ytPassword']
try:
db.session.commit()
return redirect('#')
except:
return"There was a problem updating that bot."elif request.form.get("addAccountButton"):
name = request.form['addigname']
username = request.form['addiguser']
# You want to add an account to the bot here, so you have to set the# reference, otherwise it will be saved, but it does not belong anywhere.
new_account = scrapingAccount(
name=name,
username=username,
owner_id=bot_to_update.id
)
db.session.add(new_account)
# Instead of assigning the associated bot id to the new account and# adding it to the session, you can also add it to the scrapingAccounts# list. Then you don't need to add it to the session as the parent is # already part of it. The owner_id is assigned automatically.## bot_to_update.scrapingAccounts.add(new_account)try:
db.session.commit()
return redirect('#')
except:
return"There was a problem adding an account."elif request.form.get("updateAccountButton"):
# Request the account using its id and owner_id.
account = scrapingAccount.query.filter_by(
owner_id=bot_to_update.id,
id=request.form['accountid']
).first_or_404()
account.name = request.form['igname']
account.username = request.form['iguser']
try:
db.session.commit()
return redirect('#')
except:
return"There was a problem updating an account."else:
return render_template("update.html", bot=bot_to_update)
{% for account in bot.scrapingAccounts %}
<form action="/update/{{bot.id}}" method="POST">
<inputtype="hidden" name="accountid" value="{{ account.id }}"/>
<inputtype="text" name="igname" id="igname" placeholder="eg. Jane Doe" value="{{account.name}}"/>
<inputtype="text" name="iguser" id="iguser" placeholder="eg. jandoe" value="{{account.username}}"/>
<inputtype="submit" name="updateAccountButton" value="Update accounts">
</form>
{% endfor %}
Another alternative could be to use optional parameters within the route / URL.
Solution 2:
You're querying your table scrapingaccount
by its id
column, and returning a potentially unrelated account to your bot list. You want to query scrapingaccount
by the owner_id
column.
This line:
accounts = scrapingAccount.query.get_or_404(id)
should be:
accounts = db.session.query(scrapingAccount).filter(scrapingAccount.owner_id == id).all()
Edit: I have assumed id
in your function is the id
for the BotList table.
Post a Comment for "How To Fix Sqlalchemy Form "db.session.commit()" To The Wrong Parent Object?"