2017-04-23 47 views
2

那么,我最近接近flask-admin,我无法弄清楚如何解决这个问题。我知道我可以使用form_choices通过指定元组列表来限制文本字段的可能值。无论如何,form_choices允许一次只选择一个值。我如何指定在某些情况下,我可能需要用逗号分隔的值列表?烧瓶管理员form_choices中的多个选择

我尝试以下解决方法:

form_args = { 
    'FIELD': { 
     'render_kw': {"multiple": "multiple"}, 
    } 
} 

但是,即使多选输入网页上实际上出现,只有第一个值将被保存。

EIDT 2017年5月13日

通过打了一下,用烧瓶管理员,我发现我的问题的两种可能(partial-)解决方案,它们都具有特定的缺点。

1)配合使用的Select2TagsField

from flask_admin.form.fields import Select2TagsField 
... 
form_extra_fields = { 
    'muri': Select2TagsField() 
} 

用这种方法的第一笔交易是有可能轻松地实现选择菜单正常输入文本,即使在目前,我不知道如何选择传递给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) 

该解决方案这一次配对,尽管前者,允许绘制的选择和行之有效的将数据添加到模型时,但在编辑它提供了一些问题。任何时候我打开编辑对话框时,FIELD都是空的。如果我查看发送到表单的数据(使用on_form_prefill通过打印form.FIELD.data),我会在终端中获取逗号分隔的字符串,但网页上的相关选择字段中不会显示任何内容。

回答

2

对于这种工作方式,您需要使用可存储元素列表的列。至少在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) 
+0

感谢MrLeeh,无怀疑)。我知道所提出的方法确实不是非常正统的,但是,因为在我的模型中有很多情况,比如上面提到的那个(但是,必须很少使用的情况),我想知道是否有一些方法可以继承它们N:M关系的行为而不交替模型。我在想一个以逗号分隔的字符串列表,但我不知道如何用flask-admin指定这个列表 – Pankus

2

也许这已经过时了,但我设法改变它,并使其与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))) 

,并为你解答(正确的使用它做到这一点的模型视图

class SomeView(ModelView): 
    form_args = dict(FIELD=dict(render_kw=dict(multiple="multiple"), choices=CHOICES_TUPLE)) 
    form_overrides = dict(FIELD=MultipleSelect2Field)