osj*_*ick 13 python flask flask-sqlalchemy flask-admin
我有一个具有依赖于其它列的值一列,按照该指令的数据模型,这个页面,我创建了用于确定在创建这个特定列,像这样的值上下文敏感的功能:
def get_column_value_from_context(context):
# Instructions to produce value
return value
class MyModel(db.Model):
id = db.Column(db.Integer,
primary_key=True)
my_column = db.Column(db.String(64),
nullable=False,
default=get_column_value_from_context)
name = db.Column(db.String(32),
nullable=False,
unique=True,
index=True)
title = db.Column(db.String(128),
nullable=False)
description = db.Column(db.String(256),
nullable=False)
Run Code Online (Sandbox Code Playgroud)
这种方法非常不错,我可以从命令行或使用脚本创建没有问题的行.
我还ModelView使用Flask-Admin在应用程序中添加了一个:
class MyModelView(ModelView):
can_view_details = True
can_set_page_size = True
can_export = True
admin.add_view(MyModelView(MyModel, db.session))
Run Code Online (Sandbox Code Playgroud)
在我单击列表视图中的" 创建"按钮之前,这也很有效.我收到此错误:
AttributeError:'NoneType'对象没有属性'get_current_parameters'
因为在这里执行create_model处理程序ModelView是这样的:
def create_model(self, form):
"""
Create model from form.
:param form:
Form instance
"""
try:
model = self.model()
form.populate_obj(model)
self.session.add(model)
self._on_model_change(form, model, True)
self.session.commit()
except Exception as ex:
if not self.handle_view_exception(ex):
flash(gettext('Failed to create record. %(error)s', error=str(ex)), 'error')
log.exception('Failed to create record.')
self.session.rollback()
return False
else:
self.after_model_change(form, model, True)
return model
Run Code Online (Sandbox Code Playgroud)
并且这里没有context实例化模型的时间.所以,我创建了一个自定义视图,可以重新定义创建处理程序中的模型实例化:
class CustomSQLAView(ModelView):
def __init__(self, *args, **kwargs):
super(CustomSQLAView, self).__init__(*args, **kwargs)
def create_model(self, form):
"""
Create model from form.
:param form:
Form instance
"""
try:
model = self.get_populated_model(form)
self.session.add(model)
self._on_model_change(form, model, True)
self.session.commit()
except Exception as ex:
if not self.handle_view_exception(ex):
flash(gettext('Failed to create record. %(error)s', error=str(ex)), 'error')
log.exception('Failed to create record.')
self.session.rollback()
return False
else:
self.after_model_change(form, model, True)
return model
def get_populated_model(self, form):
model = self.model()
form.populate_obj(model)
return model
Run Code Online (Sandbox Code Playgroud)
现在我可以重新定义get_populated_model方法以通常的方式实例化模型:
class MyModelView(CustomSQLAView):
can_view_details = True
can_set_page_size = True
can_export = True
def get_populated_model(self, form):
model = self.model(
name=form.name.data,
title=form.title.data,
description=form.description.data,
)
return model
Run Code Online (Sandbox Code Playgroud)
尽管如此,我怀疑它打破了一些东西.Flask-Admin有几种populate_obj表单和字段方法的实现,所以我想保证一切安全.
这样做的正确方法是什么?
因此,有几个因素会影响这个问题。
但首先,用一个功能齐全的小型应用程序来说明:
from flask_admin.contrib.sqla import ModelView
from flask_sqlalchemy import SQLAlchemy
from flask_admin import Admin
from flask import Flask
app = Flask(__name__)
db = SQLAlchemy(app)
admin = Admin(app)
app.secret_key = 'arstartartsar'
def get_column_value_from_context(context):
print('getting value from context...')
if context.isinsert:
return 'its an insert!'
else:
return 'aww, its not an insert'
class MyModel(db.Model):
id = db.Column(db.Integer, primary_key=True)
my_column = db.Column(db.String(64), nullable=False, default=get_column_value_from_context)
name = db.Column(db.String(32), nullable=False, unique=True, index=True)
class MyModelView(ModelView):
form_excluded_columns = ['my_column']
db.create_all()
admin.add_view(MyModelView(MyModel, db.session))
print('1')
x = MyModel(name='hey')
print('2')
db.session.add(x)
print('3')
db.session.commit()
print('4')
Run Code Online (Sandbox Code Playgroud)
当我们启动这个应用程序时,打印的内容是:
1
2
3
getting value from context...
4
Run Code Online (Sandbox Code Playgroud)
因此,只有在提交后get_column_value_from_context,该函数才会启动。当您在创建视图中“创建”新模型时,您还没有上下文,因为您还没有向数据库提交任何内容。当您将实例提交到数据库时,您只能获取设置默认值的上下文!这就是为什么,在flask admin的源代码中,会发生这种情况:
if getattr(default, 'is_callable', False):
value = lambda: default.arg(None) # noqa: E731
Run Code Online (Sandbox Code Playgroud)
他们检查您指定的默认值是否是一个函数,如果是,他们会在没有上下文的情况下调用它(因为还没有上下文!)。
根据您的目标,您有多种选择来克服这个问题:
my_column1)只计算添加到数据库时的值:
只需忽略表单中的字段,当您将其添加到 db 时就会确定。
class MyModelView(ModelView):
form_excluded_columns = ['my_column']
Run Code Online (Sandbox Code Playgroud)
2)仅在将其添加到数据库时计算它,但之后使其可编辑:
class MyModelView(ModelView):
form_edit_rules = ['name', 'my_column']
form_create_rules = ['name']
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
524 次 |
| 最近记录: |