[Flask] Populate form with multiple item from database

Philippe Le Toquin philippe at ppmt.org
Tue Feb 9 17:00:49 EST 2016

Very new to this mailing and first post so not sure if I am in the right
place for my question. If it is not appropriate or if pasting so much
code is wrong,  I apologise in advance!
And would appreciate if you could redirect me to a better place.

I am trying to write an application for entering recipe.
I am not expert in Python but by reading and with lots of trial and
errors, I normally
get the result I need.
But lately I have been stuck on a problem which I believe is beyond my
understanding of programming. I have a form which I use to add
ingredient to a recipe
Since it can have more than one ingredient I use some javascript code to
clone the form for each additional ingredient. Once submitted it is then
saved in a table.

That part is working even though I am sure the code would scare most of you.

Where I am stuck is that when I want to edit the ingredient list. I
can't find a way to populate the form with the list of ingredient that
are already
in the table for that recipe. Instead it starts the form as if there is
no ingredient.
I have tried various way and search the web for similar case but cant
find anything

Here is the form I use:

class IngredientListTemplate(Form):
    Template to add a new ingredient to a recipe
    The 2 input are prefilled with the date from the query_factory
    category = QuerySelectField(query_factory=categorylist,
get_label=u'category', allow_blank=False)
    ingredient = QuerySelectField(query_factory=ingredientlist,
get_label=u'ingredient', allow_blank=False)

    #it removes the CSRF token missing error
    def __init__(self, *args, **kwargs):
           kwargs['csrf_enabled'] = False
           super(IngredientListTemplate, self).__init__(*args, **kwargs)

class IngredientListForm(Form):
    Display the template
    ingredient_list = FieldList(FormField(IngredientListTemplate),

and the function I use to edit the recipe:

@mod.route('/ingredients_selection/<int:recipe_id>', methods=['GET',
def ingredient_selection(recipe_id):
    This is where you can select ingredients for a specific recipe
    It also stores them in a database for that recipe.
    It is accessed from /ingredients

    recipe = Recipeingredients.query.get(recipe_id)
    print recipe.ingredient_id #returns [5, 6, 9, 10, 19, 21, 23] being
the id of each ingredients
    form = IngredientListForm()
    form.ingredient_list[0]['ingredient'].data=9  # this is my attempt
at trying to force a some data in the form
    form.ingredient_list[0]['category'].data=1    # but it doesn't work.
I still end up with the default form

    print form.data

    # Section to refresh the ingredient when the category is changed
    # if filters the ingredient based on the chosen category
    # it is buggy and sometime it just won't work :(
    if request.is_xhr:
        ## each line is numbered like this : ingredient_list-x-category
        ## x is the number of the line (each time you press clone it
will step
        key = list(request.args.keys())[0] ## extract the line number
        form_cat = request.args.get(key) ## get the value chosen (ie the
category id)

        ## Then query the ingredient and filter them by the category
        ingredients = Ingredientlist.query.filter_by(category_id=form_cat)
        result = dict()
        for ingredient in  ingredients:
            #print ingredient.ingredient
            result[ingredient.ingredient] = ingredient.id
        print result
        return jsonify(result=result) # ingredients name and id for the
clicked category

   # Section when we validate the form
    if form.validate_on_submit():
        print form.data
        Return a dictionary in the form of :
            {'category': Flour - Grain, 'ingredient': ingredient_id },
            {'category': Flour - Grain, 'ingredient': ingredient_id }
        #remove potential duplicate
        for i in form.data['ingredient_list']:
            if i not in ingredients_list:

        #Let's store it in the Recipeingredients table
        #We are just interested in storing the id of the ingredients
since the rest can
        #be deducted from there.

        # First we create the list of ingredient id
        ing_list = []
        for ingredient in ingredients_list:

        # Then we update the table with the updated ingredient
        recipe.ingredient_id = ing_list

        # Now we can return to displaying the ingredients list
        return redirect(url_for('.ingredients_display',recipe_id=recipe_id))

   # Default display of the form
    ## TODO: We need to read the recipe being edited and preload it with
    ##       pre existing ingredient if they exist or a "clear form" if not
    return render_template("ingredients_selection.html",
                            action = 'Save',
                            title='List of Ingredients',
                            form = form,

and finally the template I use

    {% extends "bootstrap/base.html" %}
{% import "bootstrap/wtf.html" as wtf %}

{% include "mybase.html" %}

{% block content %}
<h1>{{ title }}</h1>
<p>In this section you will select the ingredient that will be the base
of the recipe</p>
<form class="form form-inline" method="post" name="list_of_ingredient">
  {{ form.hidden_tag() }}
    <fieldset class="clonable">
      {% for ingredient in form.ingredient_list %}
        {{ wtf.form_field(ingredient.category) }}
        {{ wtf.form_field(ingredient.ingredient) }}
      {% endfor %}
    <div id="formbuttons" class="regrow">
        <input type="button" class="button" id="clonetrigger"
value="Clone" />
        <input type="submit" value="Submit" />

{% endblock %}

{% block scripts %}
  {{ super() }}
  <script type="text/javascript">
        $('form').click(function(event) {
                myid = event.target.id; //get the id of the event
                if (myid.indexOf("category") !=-1) { //Are we clicking
on a category (if not ignore)
                  ing_target = myid.replace('-category','-ingredient');
                  //Lets pack the XHR request
                  $('form').on('change','#'+myid,function() {
recipe_id }}",
                              function(data) {

                                $.each( data.result, function( key, val ) {

//$('#ingredient_list-1-ingredient').append($('<option>', {'value': val,
'text': key }));
{'value': val, 'text': key }));


  //Section for the cloning
              var yourclass=".clonable"; //The class you have used in
your form
              var clonecount = $(yourclass).length-1; //how many clones
do we already have? was 0 but changed it to -1 to avoid jumping from 0 to 2
              var newid = Number(clonecount) + 1; //Id of the new clone
              //alert( newid);

              $(yourclass+":first").fieldclone({//Clone the original element
                  newid_: newid, //Id of the new clone, (you can pass
your own if you want)
                  target_: $("#formbuttons"), //where do we insert the
clone? (target element)
                  insert_: "before", //where do we insert the clone?
                  limit_: 9 //Maximum Number of Clones


      (function($) {

          $.fn.fieldclone = function(options) {

          //==> Options <==//
          var settings = {
            newid_ : 0,
            target_: $(this),
            insert_: "before",
            limit_: 0
              if (options) $.extend(settings, options);
          if( (settings.newid_ <= (settings.limit_)) ||
(settings.limit_==0) ){	//Check the limit to see if we can clone

            //==> Clone <==//
            var fieldclone = $(this).clone();
            //alert (fieldclone);
            var node = $(this)[0].nodeName;
            var classes = $(this).attr("class");

            //==> Increment every input id <==//
            var srcid = 0;
              var s = $(this).attr("name");


            //==> Locate Target Id <==//

            var targetid = $(settings.target_).attr("id");
            //alert (targetid);
              targetid = "clonetarget";

            //==> Insert Clone <==//
            var newhtml = $(fieldclone).html().replace(/\n/gi,"");
            newhtml = '<'+node+'
            eval("var insertCall =



{% endblock %}

I know it is a lot of code but I would appreciate if someone could help
me understand how I could achieve what I want.

Thanks for reading so far.


More information about the Flask mailing list