好吧,我最近接触了flask-admin,但我不知道如何解决这个问题。我知道我可以form_choices通过指定元组列表来限制文本字段的可能值。无论如何,form_choices允许一次只选择一个值。如何指定在某些情况下我可能需要以逗号分隔的值列表?
我试过这个解决方法:
form_args = {
'FIELD': {
'render_kw': {"multiple": "multiple"},
}
}
Run Code Online (Sandbox Code Playgroud)
但是,即使网页上实际出现了多选输入,也只会保存第一个值。
EIDT 05/13/2017
通过使用flask-admin,我为我的问题找到了两种可能的(部分)解决方案,它们都有特定的缺点。
1)第一个处理使用 Select2TagsField
from flask_admin.form.fields import Select2TagsField
...
form_extra_fields = {
'muri': Select2TagsField()
}
Run Code Online (Sandbox Code Playgroud)
使用此方法可以轻松实现普通输入文本的选择菜单,即使目前我不明白如何将选项传递给 Select2TagsField。它可以很好地作为一种多自由文本输入。但是,据我所知,不可能配对 Select2TagsField 和 form_choices
2)第二个有点长,但它提供了对代码的更多控制(至少我认为)。仍然暗示使用form_choices,但这次与on_model_change
form_args = {
'FIELD': {
'render_kw': {"multiple": "multiple"},
}
}
form_choices = {'FIELD': [
('1', 'M1'), ('2', 'M2'), ('3', 'M3'), ('4', 'M4')
]}
...
def on_model_change(self, form, model, is_created):
if len(form.FIELD.raw_data) > 1:
model.FIELD = ','.join(form.FIELD.raw_data)
Run Code Online (Sandbox Code Playgroud)
尽管是前一种,但该解决方案允许映射选择并且在将数据添加到模型时运行良好,但在编辑时会出现一些问题。每当我打开编辑对话框时,FIELD 都是空的。如果我查看发送到表单的数据(on_form_prefill通过打印form.FIELD.data),我会在终端中得到一个逗号分隔的字符串,但网页上的相关选择字段中没有任何显示。
也许这已经过时了,但我设法更改它并使其与 postgres 的多项选择数组字段一起使用。为了使其工作,我扩展了 Select2Field 以了解如何处理列表:
class MultipleSelect2Field(Select2Field):
"""Extends select2 field to make it work with postgresql arrays and using choices.
It is far from perfect and it should be tweaked it a bit more.
"""
def iter_choices(self):
"""Iterate over choices especially to check if one of the values is selected."""
if self.allow_blank:
yield (u'__None', self.blank_text, self.data is None)
for value, label in self.choices:
yield (value, label, self.coerce(value) in self.data)
def process_data(self, value):
"""This is called when you create the form with existing data."""
if value is None:
self.data = []
else:
try:
self.data = [self.coerce(value) for value in value]
except (ValueError, TypeError):
self.data = []
def process_formdata(self, valuelist):
"""Process posted data."""
if not valuelist:
return
if valuelist[0] == '__None':
self.data = []
else:
try:
self.data = [self.coerce(value) for value in valuelist]
except ValueError:
raise ValueError(self.gettext(u'Invalid Choice: could not coerce'))
def pre_validate(self, form):
"""Validate sent keys to make sure user don't post data that is not a valid choice."""
sent_data = set(self.data)
valid_data = {k for k, _ in self.choices}
invalid_keys = sent_data - valid_data
if invalid_keys:
raise ValueError('These values are invalid {}'.format(','.join(invalid_keys)))
Run Code Online (Sandbox Code Playgroud)
并在 ModelView 上使用它
class SomeView(ModelView):
form_args = dict(FIELD=dict(render_kw=dict(multiple="multiple"), choices=CHOICES_TUPLE))
form_overrides = dict(FIELD=MultipleSelect2Field)
Run Code Online (Sandbox Code Playgroud)
为了使这种方法发挥作用,您需要使用可以存储元素列表的列。至少对于 sqlite,使用 Flask-Admin 是不可能的。但是,最好将您的选择存储在单独的数据模型中,并使用约束来链接两个模型。请参阅此处的工作示例。
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from flask_admin import Admin
from flask_admin.contrib.sqla import ModelView
app = Flask(__name__)
app.config['SECRET_KEY'] = '8e12c91677b3b3df266a770b22c82f2f'
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///:memory:'
db = SQLAlchemy(app)
admin = Admin(app)
item_tag_relation = db.Table('item_tag_relation',
db.Column('item_id', db.Integer, db.ForeignKey('item.id')),
db.Column('tag_id', db.Integer, db.ForeignKey('tag.id'))
)
class Item(db.Model):
id = db.Column(db.Integer(), primary_key=True)
name = db.Column(db.String())
tags = db.relationship("Tag",
secondary=item_tag_relation,
backref="items")
def __repr__(self):
return self.name
class Tag(db.Model):
id = db.Column(db.Integer(), primary_key=True)
name = db.Column(db.String())
def __repr__(self):
return self.name
class ItemModelView(ModelView):
pass
db.create_all()
admin.add_view(ItemModelView(Item, db.session))
admin.add_view(ModelView(Tag, db.session))
if __name__ == '__main__':
app.run(debug=True)
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
4517 次 |
| 最近记录: |