I have a simple application, full code presented here. It uses flask-admin
the models:
class User(db.Model):
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String, unique=True)
class UserNote(db.Model):
id = db.Column(db.Integer, primary_key=True)
body = db.Column(db.String, nullable=False)
user_id = db.Column(db.Integer, db.ForeignKey('users.id'))
author_id = db.Column(db.Integer, db.ForeignKey('users.id'))
user = db.relationship(User,
foreign_keys='UserNote.user_id',
backref=db.backref('user_notes', order_by=id))
author = db.relationship(User,
foreign_keys='UserNote.author_id',
backref=db.backref('author_user_notes',
order_by=id))
and the main app.py:
app = Flask(__name__)
class ModelFormWithAuthorship(InlineFormAdmin):
def on_model_change(self, form, model):
user = User.query.first()
print('++++++')
print(user)
print(model)
print('++++++')
model.author = user
class UserModelView(ModelView):
inline_models = (ModelFormWithAuthorship(UserNote),)
admin = Admin(app, url='/admin', name='MyAdmin', template_mode='bootstrap3')
admin.add_view(UserModelView(User, db.session))
I want to automatically set the first user from the query as author of the changed UserNote. It's simplification for a current logged in user.
But the flask admin passes all inline models to this method.
Here is steps for reporduce
Expected result for these actions for me was, that first note will have user1 as author and author of the second note will remain the same. But Actual result is following: author for both notes set to the user1.
I've tried to debug, and found some interesting attributes:
# Not changed note
model._sa_instance_state._attached = {bool} True
model._sa_instance_state.deleted = {bool} False
model._sa_instance_state.detached = {bool} False
model._sa_instance_state.expired = {bool} False
model._sa_instance_state.has_identity = {bool} True
model._sa_instance_state.pending = {bool} False
model._sa_instance_state.persistent = {bool} True
model._sa_instance_state.transient = {bool} False
model.body = {str} 'test1'
model._sa_instance_state.modified = {bool} True
# Changed note
model._sa_instance_state._attached = {bool} True
model._sa_instance_state.deleted = {bool} False
model._sa_instance_state.detached = {bool} False
model._sa_instance_state.expired = {bool} False
model._sa_instance_state.has_identity = {bool} True
model._sa_instance_state.pending = {bool} False
model._sa_instance_state.persistent = {bool} True
model._sa_instance_state.transient = {bool} False
model.body = {str} 'test2A'
model._sa_instance_state.modified = {bool} True
But they're indistinguishable from each other.
Is there way to catch only changed models?
You can use WTForms' Field.object_data attribute:
This is the data passed from an object or from kwargs to the field, stored unmodified. This can be used by templates, widgets, validators as needed (for comparison, for example)
So you can compare UserNote.body old and new values, then change the author if needed like this:
class ModelFormWithAuthorship(InlineFormAdmin):
def on_model_change(self, form, model):
# Check whether note's body has changed
if form.body.object_data != form.body.data:
model.author = User.query.first()
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With