pythonflaskjinja2

How do I use jinja for conditional css classes?


I'm making a flask application that displays pizzas and their ingredients using python and jinja. I want to represent veg ingredients as green circles and meat ingredients as red circles.

I have a pizza collection, and an ingredients collection. I want to compare toppings in the pizza collection, to ingredients properties in the ingredients collection.

I've tried using jinja to loop through toppings in the pizza collection, nesting a loop so that if any of the toppings match those in the ingredients then it should change which class is applied to aan icon.

A document in the pizzas collection:

_id:5d506eed1c9d4400000a4254
pizza_name:"vegetairian supreme"
pizza_code:"vs"
sauce_type:"pizza"
cheese_type:"mozzarella"
toppings:Array
0:"onions"
1:"mushrooms"
2:"peppers"
3:"sweetcorn"
4:"tomatoes"
allergens:""
is_veg:true

A document in the ingredients collection:

_id:5d506d341c9d4400000a4238
topping:"bacon"
is_meat:true

My code to display pizzas:

<div class="row">
    <div class="row">
    {% for pizza in pizzas %}
    <div class="card">
        <ul class="collection with-header">
            <li class="collection-header">
                <h4>{{ pizza.pizza_name }}</h4>
            </li>
            {% for topping in pizza.toppings %}
            <li class="collection-item">
                {% for ing in ingredients %}
                    {% if ing.topping == topping %}
                        {% if ing.is_meat == True %}
                            <i class="meat tiny material-icons">brightness_1</i>{{topping}}
                        {% elif ing.is_meat == False %}
                            <i class="veg tiny material-icons">brightness_1</i>{{topping}}
                        {% endif %}
                    {% endif %}
                {% endfor %} 
            </li>
            {% endfor %}
        </ul>
    </div>
    {% endfor %}
</div>

The current result

If I just do:

<div class="row">
    {% for pizza in pizzas %}
    <div class="card">
        <ul class="collection with-header">
            <li class="collection-header">
                <h4>{{ pizza.pizza_name }}</h4>
            </li>
            {% for topping in pizza.toppings %}
            <li class="collection-item">
                <i class="meat tiny material-icons">brightness_1</i>{{topping}}
            </li>
            {% endfor %}
        </ul>
    </div>
    {% endfor %}
</div>

I will get a list of the toppings for each pizza with a black circle beside each, so I'm on the right track, I think!

CSS: style.css

.meat {
  color: red;
}
.veg {
  color: red;
}

Other styles are from materialize

Current html output:

<div class="card">
  <ul class="collection with-header">
    <li class="collection-header">
      <h4>vegetairian supreme</h4>
    </li>
    <li class="collection-item"><i class="veg tiny material-icons">brightness_1</i>onions</li>
    <li class="collection-item"></li>
    <li class="collection-item"></li>
    <li class="collection-item"></li>
    <li class="collection-item"></li>
  </ul>
</div>

Solution

  • Ok so here is what I did to make it work.

    On mongo I tidied things up:

    {"_id":{"$oid":"5d5353ee1c9d440000cb278e"},"meats":["bacon","beef","roast chicken","tandoori chicken","ham","meatballs","pepperoni","chorizo","sausage"]}
    

    Then in my app.py I made dictionaries for each ingredient to be reuseable:

    meats = mongo.db.ingredients.find_one({'meats' : {'$exists': True}})
    vegs = mongo.db.ingredients.find_one({'vegs' : {'$exists': True}})
    sauces = mongo.db.ingredients.find_one({'sauces' : {'$exists': True}})
    cheeses = mongo.db.ingredients.find_one({'cheeses' : {'$exists': True}})
    
    @app.route('/')
    @app.route('/get_pizzas')
    def get_pizzas():
        return render_template("pizzas.html",
                               pizzas=mongo.db.pizzas.find(), 
                               meats = meats,
                               vegs = vegs,
                               sauces = sauces,
                               cheeses = cheeses)
    

    Then to display the pizzas with the conditionaly classes I done:

        <div class="row ">
            {% for pizza in pizzas %}
            <div class="card">
                <ul class="collection with-header">
                    <li class="collection-header">
                        <h4>{{ pizza.pizza_name.capitalize() }}</h4>
                    </li>
                    <li class="collection-item">
                        <i class="{{pizza.sauce_type}} tiny material-icons">brightness_1</i>{{pizza.sauce_type.capitalize()}}
                    </li>
                    <li class="collection-item">
                        <i class="cheese tiny material-icons">brightness_1</i>{{pizza.cheese_type.capitalize()}}
                    </li>
                    {% for topping in pizza.toppings %}
                        {% for veg in vegs.vegs %}
                            {% if veg == topping %}
                                <li class="collection-item">
                                    <i class="veg tiny material-icons">brightness_1</i>{{topping.capitalize()}}
                                </li>
                            {% endif %}
                        {% endfor %}
                        {% for meat in meats.meats %}
                            {% if meat == topping %}
                                <li class="collection-item">
                                    <i class="meat tiny material-icons">brightness_1</i>{{topping.capitalize()}}
                                </li>
                            {% endif %}
                        {% endfor %}
                    {% endfor %}
                </ul>
            </div>
            {% endfor %}
        </div>
    </div>
    

    And now it works! Thanks everyone for your help!