2017-04-23 49 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)