user4495602
user4495602

Reputation:

Populate a WTForms SelectField with an SQL query

I'm want to populate a WTForms SelectField with the rows returned by this query:

cur.execute("SELECT length FROM skipakke_alpin_ski WHERE stock > 0")

The query returns rows with the ski length of different types of skis. cur.fetchall() returns the following tuple:

[(70,), (75,), (82,), (88,), (105,), (115,), (125,), (132,), (140,), (150,), (160,), (170,)]

How would I go about to do add these numbers to a SelectField, so that each ski length would be its own selectable choice? If I had done this manually, I would have done the following:

ski_size = SelectField('Ski size', choices=['70', '70', '75', '75'])

... And so on for all of the different lengths.

Upvotes: 5

Views: 9451

Answers (4)

Alex Kosh
Alex Kosh

Reputation: 2564

Solution:

I had quite simmilar problem, and here is my workaround

class SkiForm(FlaskForm):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        
        cur.execute("SELECT length FROM skipakke_alpin_ski WHERE stock > 0")
        skies = cur.fetchall()

        self.ski_size.choices = [
            (ski , ski) for ski in skies
        ]

    ski_size = SelectField("Ski size")

Explanation:

We modified original FlaskForm, so that it executs database query each time when it is being created.

So SkiForm field data choices always stays up to date.

Upvotes: 1

Denis Berezovskiy
Denis Berezovskiy

Reputation: 31

The solution might look like the code below.

Let's assume you have two files: routes.py and views.py

In routes.py file you put this

from flask_wtf import FlaskForm
from wtforms import SelectField

# Here we have class to render ski
class SkiForm(FlaskForm):
    ski = SelectField('Ski size')

In views.py file you put this

# Import your SkiForm class from `routes.py` file
from routes import SkiForm

# Here you define `cur`
cur = ...

# Now let's define a method to return rendered page with SkiForm
def show_ski_to_user():
    # List of skies
    cur.execute("SELECT length FROM skipakke_alpin_ski WHERE stock > 0")
    skies = cur.fetchall()

    # create form instance
    form = SkiForm()
    # Now add ski length to the options of select field
    # it must be list with options with (key, value) data
    form.ski.choices = [(ski, ski) for ski in skies]
    # If you want to use id or other data as `key` you can change it in list generator
    if form.validate():
        # your code goes here

    return render_template('any_file.html', form=form)

Remember that by default key value is unicode. If you want to use int or other data type use coerce argument in SkiForm class, like this

class SkiForm(FlaskForm):
    ski = SelectField('Ski size', coerce=int)

Upvotes: 3

user4495602
user4495602

Reputation:

I managed to solve this by doing the following:

def fetch_available_items(table_name, column):
    with sqlite3.connect('database.db') as con:
        cur = con.cursor()
        cur.execute("SELECT length FROM skipakke_alpin_ski WHERE stock > 0")
        return cur.fetchall()

class SkipakkeForm(Form):
    alpin_ski = SelectField('Select your ski size', choices=[])

@app.route('/skipakke')
def skipakke():
    form = SkipakkeForm

    # Clear the SelectField on page load
    form.alpin_ski.choices = []        

    for row in fetch_available_items('skipakke_alpin_ski', 'length'):
        stock = str(row[0])
        form.alpin_ski.choices += [(stock, stock + ' cm')]

Upvotes: 0

Pradeepb
Pradeepb

Reputation: 2572

In one of the projects I have used like below:

models

class PropertyType(db.Model):
    id = db.Column(db.Integer, primary_key=True)

    title = db.Column(db.String(255), nullable=False)

    def __repr__(self):
        return str(self.id)

and in forms

from wtforms.ext.sqlalchemy.fields import QuerySelectField

class PropertyEditor(Form):
    property_type = QuerySelectField(
        'Property Type',
        query_factory=lambda: models.PropertyType.query,
        allow_blank=False
    )
    //Other remaining fields

Hope this helps.

Upvotes: 6

Related Questions