Seb*_*ebi 4 flask flask-sqlalchemy flask-admin
在 Flask Admin 中,我有一列字符串值(我无法更改数据库定义)。在索引视图中过滤此列时,用户应该能够从下拉列表中选择值。
当用户选择过滤器时,应该计算过滤器的可能选项。所以我需要一种方法来设置基于自定义模型查询的选项。由于该列已编入索引,因此查询速度相当快。
该SQLA自定义过滤器例子只说明了如何应用自定义过滤器,但不知道如何做一个过滤器动态的选择。
options 参数可以是可调用的,因此请执行以下操作(使用您链接到的示例):
def get_all_last_names():
    unique_last_names = User.query.with_entities(User.last_name.distinct().label("last_name")).order_by(User.last_name.asc()).all()
    return [(user.last_name, user.last_name) for user in unique_last_names]
class UserAdmin(sqla.ModelView):
    column_filters = [
        FilterEqual(column=User.last_name, name='Last Name', options=get_all_last_names),
    ]
    # This is probably NOT the correct way to refresh the filters cache
    @expose('/')
    def index_view(self):
        self._refresh_filters_cache()
        return super(UserAdmin, self).index_view()
Run Code Online (Sandbox Code Playgroud)
请参阅下面的单个文件演示。添加新用户,他们将出现在“姓氏”过滤器中。正如@sortas 所指出的,这个版本在使用应用工厂方法时不起作用。
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from flask_admin.contrib import sqla
from flask_admin import Admin, expose
# required for creating custom filters
from flask_admin.contrib.sqla.filters import BaseSQLAFilter, FilterEqual
app = Flask(__name__)
# Create dummy secrey key so we can use sessions
app.config['SECRET_KEY'] = '123456790'
# Create in-memory database
app.config['DATABASE_FILE'] = 'sample_db.sqlite'
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///' + app.config['DATABASE_FILE']
app.config['SQLALCHEMY_ECHO'] = True
db = SQLAlchemy(app)
# Flask views
@app.route('/')
def index():
    return '<a href="/admin/">Click me to get to Admin!</a>'
# Create model
class User(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    first_name = db.Column(db.String(100))
    last_name = db.Column(db.String(100))
    username = db.Column(db.String(80), unique=True)
    email = db.Column(db.String(120), unique=True)
    # Required for admin interface. For python 3 please use __str__ instead.
    def __unicode__(self):
        return self.username
# Create custom filter class
class FilterLastNameBrown(BaseSQLAFilter):
    def apply(self, query, value, alias=None):
        if value == '1':
            return query.filter(self.column == "Brown")
        else:
            return query.filter(self.column != "Brown")
    def operation(self):
        return 'is Brown'
def get_options():
    return [('1', 'Yes'), ('0', 'No')]
def get_all_last_names():
    unique_last_names = User.query.with_entities(User.last_name.distinct().label("last_name")).order_by(
        User.last_name.asc()).all()
    return [(user.last_name, user.last_name) for user in unique_last_names]
# Add custom filter and standard FilterEqual to ModelView
class UserAdmin(sqla.ModelView):
    column_filters = [
        FilterEqual(column=User.last_name, name='Last Name', options=get_all_last_names),
        FilterLastNameBrown(column=User.last_name, name='Last Name', options=(('1', 'Yes'), ('0', 'No')))
    ]
    # This is probably NOT the correct way to refresh the filters cache
    @expose('/')
    def index_view(self):
        self._refresh_filters_cache()
        return super(UserAdmin, self).index_view()
admin = Admin(app, template_mode="bootstrap3")
admin.add_view(UserAdmin(User, db.session))
def build_sample_db():
    db.drop_all()
    db.create_all()
    user_obj1 = User(first_name="Paul", last_name="Brown", username="pbrown", email="paul@gmail.com")
    user_obj2 = User(first_name="Luke", last_name="Brown", username="lbrown", email="luke@gmail.com")
    user_obj3 = User(first_name="Serge", last_name="Koval", username="skoval", email="serge@gmail.com")
    db.session.add_all([user_obj1, user_obj2, user_obj3])
    db.session.commit()
if __name__ == '__main__':
    build_sample_db()
    app.run(port=5000, debug=True)
Run Code Online (Sandbox Code Playgroud)
使用应用工厂时的单个文件示例。
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from flask_admin.contrib import sqla
from flask_admin import Admin, expose
# required for creating custom filters
from flask_admin.contrib.sqla.filters import BaseSQLAFilter, FilterEqual
db = SQLAlchemy()
class User(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    first_name = db.Column(db.String(100))
    last_name = db.Column(db.String(100))
    username = db.Column(db.String(80), unique=True)
    email = db.Column(db.String(120), unique=True)
    # Required for admin interface. For python 3 please use __str__ instead.
    def __unicode__(self):
        return self.username
# Create custom filter class
class FilterLastNameBrown(BaseSQLAFilter):
    def apply(self, query, value, alias=None):
        if value == '1':
            return query.filter(self.column == "Brown")
        else:
            return query.filter(self.column != "Brown")
    def operation(self):
        return 'is Brown'
def get_options():
    return [('1', 'Yes'), ('0', 'No')]
def get_all_last_names():
    unique_last_names = User.query.with_entities(User.last_name.distinct().label("last_name")).order_by(
        User.last_name.asc()).all()
    return [(user.last_name, user.last_name) for user in unique_last_names]
# Add custom filter and dynamic FilterEqual to ModelView
class UserAdmin(sqla.ModelView):
    column_filters = [
        FilterLastNameBrown(column=User.last_name, name='Last Name', options=(('1', 'Yes'), ('0', 'No')))
    ]
    def get_filters(self):
        _dynamic_filters = getattr(self, 'dynamic_filters', None)
        if _dynamic_filters:
            return (super(UserAdmin, self).get_filters() or []) + _dynamic_filters
        else:
            return super(UserAdmin, self).get_filters()
    @expose('/')
    def index_view(self):
        self.dynamic_filters = []
        self.dynamic_filters.extend([
            FilterEqual(column=User.last_name, name='Last Name', options=get_all_last_names),
            # Add further dynamic filters here
        ])
        self._refresh_filters_cache()
        return super(UserAdmin, self).index_view()
def create_app():
    app = Flask(__name__)
    # Create dummy secrey key so we can use sessions
    app.config['SECRET_KEY'] = '123456790'
    # Create in-memory database
    app.config['DATABASE_FILE'] = 'sample_db.sqlite'
    app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///' + app.config['DATABASE_FILE']
    app.config['SQLALCHEMY_ECHO'] = True
    db.init_app(app)
    admin = Admin(app, template_mode="bootstrap3")
    admin.add_view(UserAdmin(User, db.session))
    # Flask views
    @app.route('/')
    def index():
        return '<a href="/admin/">Click me to get to Admin!</a>'
    @app.before_first_request
    def build_sample_db():
        db.drop_all()
        db.create_all()
        user_obj1 = User(first_name="Paul", last_name="Brown", username="pbrown", email="paul@gmail.com")
        user_obj2 = User(first_name="Luke", last_name="Brown", username="lbrown", email="luke@gmail.com")
        user_obj3 = User(first_name="Serge", last_name="Koval", username="skoval", email="serge@gmail.com")
        db.session.add_all([user_obj1, user_obj2, user_obj3])
        db.session.commit()
    return app
if __name__ == '__main__':
    app = create_app()
    app.run(port=5000, debug=True)
Run Code Online (Sandbox Code Playgroud)
        小智 5
您可以使用 Flaskhas_request_context函数检查函数中是否存在请求上下文,该函数返回过滤器的选项元组。在选项从数据库获取但此时请求上下文不存在的情况下,它可以提供帮助。
def _get_options_for_filter()
    if not has_request_context():
        return ()
    return tuple([(o.id, o.title) for o in Options.query.all()])
Run Code Online (Sandbox Code Playgroud)
        |   归档时间:  |  
           
  |  
        
|   查看次数:  |  
           5037 次  |  
        
|   最近记录:  |