Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

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')

...
like image 361
jul Avatar asked Aug 01 '15 17:08

jul


People also ask

How do I create a custom User Manager in flask?

# Setup Flask-User user_manager = CustomUserManager(app, db, User) Forms shows a complete list of customizable forms. Notice that in a simple use case like this, the form will work without customizing the accompanying view method.

How do I edit a form template in flask?

After you’ve copied the Form template files, you can edit any template file in your app/templates/flask_user/ directory, and change it to your liking. All Flask-User templates extend from app/template/flask_user_layout.html . You can configure all Flask-User templates to extend from your own layout template by:

How do I set the default view in flask?

# Setup Flask-User user_manager = CustomUserManager(app, db, User) View methods perform lots of intricate operations, so use this feature with caution. Be sure to read the source code of the default view method and make sure you understand all that it does before attempting to modify its behavior.

Is it possible to pass custom attributes to a selectfield?

Here’s a nice clean solution to pass those custom attributes, keeping the built-in SelectField, but using a custom widget which supports providing attributes for any of the options via a keyed dictionary. I want to generate markup equivalent to this boostrap 4 example, where the first option is disabled.


1 Answers

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')
like image 174
Kronas Avatar answered Sep 19 '22 11:09

Kronas