Предположим, что у нас есть отношение между Владельцем и Экранами между собой (владелец может владеть несколькими экранами).Flask-Admin сортировать по одному во многих подсчитанных полях
Можно отобразить столбец, показывающий количество экранов, принадлежащих каждому владельцу, с помощью функции hybrid_property и call count() для отношения. Однако я не нашел способ сделать это значение, рассчитанное значение сортируется в веб-интерфейсе: Если добавить number_of_screens в column_sortable_list, я получил следующее сообщение об ошибке:
Traceback (most recent call last):
File "app.py", line 71, in <module>
admin.add_view(OwnerAdmin(Owner, db.session))
File "C:\Python27\lib\site-packages\flask_admin\contrib\sqla\view.py", line 319, in __init__
menu_icon_value=menu_icon_value)
File "C:\Python27\lib\site-packages\flask_admin\model\base.py", line 718, in __init__
self._refresh_cache()
File "C:\Python27\lib\site-packages\flask_admin\model\base.py", line 795, in _refresh_cache
self._sortable_columns = self.get_sortable_columns()
File "C:\Python27\lib\site-packages\flask_admin\contrib\sqla\view.py", line 539, in get_sortable_columns
column, path = self._get_field_with_path(c)
File "C:\Python27\lib\site-packages\flask_admin\contrib\sqla\view.py", line 365, in _get_field_with_path
value = getattr(model, attribute)
File "C:\Python27\lib\site-packages\sqlalchemy\ext\hybrid.py", line 740, in __get__
return self.expr(owner)
File "app.py", line 48, in number_of_screens
return self.screens.count()
File "C:\Python27\lib\site-packages\sqlalchemy\orm\attributes.py", line 193, in __getattr__
key)
AttributeError: Neither 'InstrumentedAttribute' object nor 'Comparator' object associated with Owner.screens has an attribute 'count'
Вот пример кода для иллюстрации проблемы :
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from sqlalchemy.ext.hybrid import hybrid_property
import flask_admin as admin
from flask_admin.contrib import sqla
from flask_admin.contrib.sqla.filters import IntGreaterFilter
# Create application
app = Flask(__name__)
# Create dummy secrey key so we can use sessions
app.config['SECRET_KEY'] = '123456790'
# Create in-memory database
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///sample_db_2.sqlite'
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>'
class Screen(db.Model):
__tablename__ = 'screen'
id = db.Column(db.Integer, primary_key=True)
width = db.Column(db.Integer, nullable=False)
height = db.Column(db.Integer, nullable=False)
owner_id = db.Column(db.Integer, db.ForeignKey('owner.id'))
owner = db.relationship('Owner',
backref=db.backref('screens', lazy='dynamic'))
@hybrid_property
def number_of_pixels(self):
return self.width * self.height
class Owner(db.Model):
__tablename__ = 'owner'
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.Unicode)
@hybrid_property
def number_of_screens(self):
return self.screens.count()
class ScreenAdmin(sqla.ModelView):
''' Flask-admin can not automatically find a hybrid_property yet. You will
need to manually define the column in list_view/filters/sorting/etc.'''
list_columns = ['id', 'width', 'height', 'number_of_pixels']
column_sortable_list = ['id', 'width', 'height', 'number_of_pixels']
# make sure the type of your filter matches your hybrid_property
column_filters = [IntGreaterFilter(Screen.number_of_pixels,
'Number of Pixels')]
class OwnerAdmin(sqla.ModelView):
''' Flask-admin can not automatically find a hybrid_property yet. You will
need to manually define the column in list_view/filters/sorting/etc.'''
list_columns = ['id', 'name', 'number_of_screens']
column_sortable_list = ['id', 'name', 'number_of_screens']
# Create admin
admin = admin.Admin(app, name='Example: SQLAlchemy2', template_mode='bootstrap3')
admin.add_view(ScreenAdmin(Screen, db.session))
admin.add_view(OwnerAdmin(Owner, db.session))
if __name__ == '__main__':
# Create DB
db.create_all()
# Start app
app.run(debug=True)
Спасибо, это именно то, что я искал! – jbfuzier
'TypeError: count() принимает ровно один аргумент (0 задано)' :( –
Получил его для работы с 'return len (self.screens)' под '@ hybrid_property'. –