【发布时间】:2016-02-13 03:38:12
【问题描述】:
我在 flask-admin 中一直在努力实现的一个功能是,当用户编辑表单时,一旦设置了字段 1,就限制了字段 2 的值。
让我用文字举一个简化的例子(实际用例更复杂)。然后我将展示实现该示例的完整要点,减去“约束”功能。
假设我们有一个数据库,可以跟踪一些软件“配方”以输出各种格式的报告。我们示例数据库的recipe 表有两个配方:“Serious Report”、“ASCII Art”。
为了实现每个配方,我们从几种方法中选择一种。我们数据库的method表有两种方法:“tabulate_results”、“pretty_print”。
每个方法都有参数。 methodarg 表有两个用于“tabulate_results”的参数名称(“rows”、“display_total”)和两个用于“pretty_print”的参数(“embellishment_character”、“lines_to_jump”)。
现在,对于每个配方(“Serious Report”、“ASCII Art”),我们需要提供它们各自方法(“tabulate_results”、“pretty_print”)的参数值。
对于每条记录,recipearg 表允许我们选择一个配方(即字段 1,例如“Serious Report”)和参数名称(即字段 2)。问题是显示了所有可能的参数名称,而它们需要根据字段 1 的值进行约束。
我们可以实现什么过滤/约束机制,一旦我们选择“Serious Report”,我们就知道我们将使用“tabulate_results”方法,因此只有“rows”和“display_total”参数可用?
我在想一些 AJAX 魔法,它检查字段 1 并设置字段 2 值的查询,但不知道如何继续。
您可以通过使用要点来了解这一点:单击Recipe Arg 选项卡。在第一行(“严重报告”)中,如果您尝试通过单击来编辑“Methodarg”值,则所有四个参数名称都可用,而不仅仅是两个。
# full gist: please run this
from flask import Flask
from flask_admin import Admin
from flask_admin.contrib import sqla
from flask_sqlalchemy import SQLAlchemy
from sqlalchemy import Column, ForeignKey, Integer, String
from sqlalchemy.orm import relationship
# Create application
app = Flask(__name__)
# Create dummy secrey key so we can use sessions
app.config['SECRET_KEY'] = '123456790'
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///a_sample_database.sqlite'
app.config['SQLALCHEMY_ECHO'] = True
db = SQLAlchemy(app)
# Create admin app
admin = Admin(app, name="Constrain Values", template_mode='bootstrap3')
# Flask views
@app.route('/')
def index():
return '<a href="/admin/">Click me to get to Admin!</a>'
class Method(db.Model):
__tablename__ = 'method'
mid = Column(Integer, primary_key=True)
method = Column(String(20), nullable=False, unique=True)
methodarg = relationship('MethodArg', backref='method')
recipe = relationship('Recipe', backref='method')
def __str__(self):
return self.method
class MethodArg(db.Model):
__tablename__ = 'methodarg'
maid = Column(Integer, primary_key=True)
mid = Column(ForeignKey('method.mid', ondelete='CASCADE', onupdate='CASCADE'), nullable=False)
methodarg = Column(String(20), nullable=False, unique=True)
recipearg = relationship('RecipeArg', backref='methodarg')
inline_models = (Method,)
def __str__(self):
return self.methodarg
class Recipe(db.Model):
__tablename__ = 'recipe'
rid = Column(Integer, primary_key=True)
mid = Column(ForeignKey('method.mid', ondelete='CASCADE', onupdate='CASCADE'), nullable=False)
recipe = Column(String(20), nullable=False, index=True)
recipearg = relationship('RecipeArg', backref='recipe')
inline_models = (Method,)
def __str__(self):
return self.recipe
class RecipeArg(db.Model):
__tablename__ = 'recipearg'
raid = Column(Integer, primary_key=True)
rid = Column(ForeignKey('recipe.rid', ondelete='CASCADE', onupdate='CASCADE'), nullable=False)
maid = Column(ForeignKey('methodarg.maid', ondelete='CASCADE', onupdate='CASCADE'), nullable=False)
strvalue = Column(String(80), nullable=False)
inline_models = (Recipe, MethodArg)
def __str__(self):
return self.strvalue
class MethodArgAdmin(sqla.ModelView):
column_list = ('method', 'methodarg')
column_editable_list = column_list
class RecipeAdmin(sqla.ModelView):
column_list = ('recipe', 'method')
column_editable_list = column_list
class RecipeArgAdmin(sqla.ModelView):
column_list = ('recipe', 'methodarg', 'strvalue')
column_editable_list = column_list
admin.add_view(RecipeArgAdmin(RecipeArg, db.session))
# More submenu
admin.add_view(sqla.ModelView(Method, db.session, category='See Other Tables'))
admin.add_view(MethodArgAdmin(MethodArg, db.session, category='See Other Tables'))
admin.add_view(RecipeAdmin(Recipe, db.session, category='See Other Tables'))
if __name__ == '__main__':
db.drop_all()
db.create_all()
db.session.add(Method(mid=1, method='tabulate_results'))
db.session.add(Method(mid=2, method='pretty_print'))
db.session.commit()
db.session.add(MethodArg(maid=1, mid=1, methodarg='rows'))
db.session.add(MethodArg(maid=2, mid=1, methodarg='display_total'))
db.session.add(MethodArg(maid=3, mid=2, methodarg='embellishment_character'))
db.session.add(MethodArg(maid=4, mid=2, methodarg='lines_to_jump'))
db.session.add(Recipe(rid=1, mid=1, recipe='Serious Report'))
db.session.add(Recipe(rid=2, mid=2, recipe='ASCII Art'))
db.session.commit()
db.session.add(RecipeArg(raid=1, rid=1, maid=2, strvalue='true' ))
db.session.add(RecipeArg(raid=2, rid=1, maid=1, strvalue='12' ))
db.session.add(RecipeArg(raid=3, rid=2, maid=4, strvalue='3' ))
db.session.commit()
# Start app
app.run(debug=True)
【问题讨论】:
-
对于灵活的数据库接口,此功能必须具备。一个好的答案会帮助很多人。当然,数据本身可以有不同的结构,但这不是重点。添加赏金。 :)
标签: python flask sqlalchemy flask-sqlalchemy flask-admin