Custom Flask-Admin form with some select field choices set according to another select field
Asked Answered
C

1

8

I am trying to use Flask-Admin to create a create/edit form for the model Matriline shown below. This model has a string field name and a field pod_id with a foreign key constraint to another model Pod, which itself has a foreign key field to a Clan model.

The default form created by Flask-Admin shows the name field and a select field for the Pod instances, but I would like to add a field Clan, which would reset the Pod list according to the Clan instance selected.

To add the Clan field I override the default ModelView for Matriline and add an extra select field Clan with all the Clan instances, as shown in the view MatrilineView below.

Now I need to add some Ajax code to the rendered form to reset the list of pods every time a new clan is selected.

Do I have to replace entirely the default form by a custom one including the Ajax code? Or is there any easier way to that with Flask-Admin?

<b>models.py</b>

...

class Matriline(db.Model):
    __tablename__ = 'matriline'
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.Unicode(64))
    pod_id = db.Column(db.Integer, db.ForeignKey('pod.id'))

    def __unicode__(self):
        return self.name


class Pod(db.Model):
    __tablename__ = 'pod'
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.Unicode(64))
    matrilines = db.relationship('Matriline', backref='pod', lazy='select')
    clan_id = db.Column(db.Integer, db.ForeignKey('clan.id'))

    def __unicode__(self):
        return self.name


class Clan(db.Model):
    __tablename__ = 'clan'
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.Unicode(64))
    pods = db.relationship('Pod', backref='clan', lazy='select')

    def __unicode__(self):
        return self.name

...

<b>views.py</b>

from flask_admin.contrib import sqla
from wtforms import SelectField
from orcall import models


class MatrilineView(sqla.ModelView):
    column_hide_backrefs = False
    form_extra_fields = {
        'clan': SelectField('Clan',
            choices=[ (c.id, c.name) for c in models.Clan.query.all()])
    }
    column_list = ('name', 'pod', 'clan')

...
Ciracirca answered 1/8, 2015 at 17:37 Comment(0)
D
8

You are need to use a QuerySelectField. For example:

from flask.ext.admin.form import Select2Widget

class MatrilineView(sqla.ModelView):
    column_hide_backrefs = False
    form_extra_fields = {
        'clan': sqla.fields.QuerySelectField(
            label='Clan',
            query_factory=lambda: Clan.query.all(),
            widget=Select2Widget()
        )
    }
    column_list = ('name', 'pod', 'clan')
Demonstration answered 11/12, 2015 at 13:5 Comment(3)
Clan.query.all should be Clan.query.all() for it to work on flask-admin 1.4.0Defaulter
your solution work fine for me , but I was use SelectField and added even onchange on it when I use this query Field it do the first part good load the query before get choices but its div element and have no values or change event any ideaAnticlerical
How does this answer the question about dynamically changing the Select2 list of available pod options based on the clan selected? The pod AJAX query would need to be modified in JS on clan field "change" event, I think.Sparkie

© 2022 - 2024 — McMap. All rights reserved.