Forums

Flask and python 3.6: How to create a menu list with data from MySQL database in a template.html file?

Hello, I use flask and python 3.6 and I want to populate a menu list with data from MySQL database. I use a template.html file where I want the list of links to appear. I want it to work similar to the @app.route() 'thing' but I don't want a page dedicated to the menu. I want it to appear on every page that uses the template.html file.

class Menu(db.Model):

  __tablename__ = "menu"

  id = db.Column(db.Integer, primary_key=True)
  name = db.Column(db.String(4096))
  link = db.Column(db.String(4096))
  weight = db.Column(db.String(4096))
  description = db.Column(db.String(4096))

@app.route('/menu1')
    def menu1():
        return render_template("menu1.html", menuItems=Menu.query.all())

The code above, from my flask_app.py file, renders a page for the menu to be displayed on but that's not what I want to achieve. Below is my template.html file. I want the menu list to appear in the <head> section.

<!doctype html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css" integrity="sha512-dTfge/zgoMYpP7QbHy4gWMEGsbsdZeCXz7irItjcC3sPUFtf0kuFbDz/ixG7ArTxmDjLXDmezHubeNikyKGVyQ==" crossorigin="anonymous">
   <!-- ***THIS IS WHERE I WANT MY MENU LIST TO APPEAR. THE CODE IN THE {%block head %} BELOW DOES NOT WORK NOW BUT I PASTE IT THERE TO GIVE A CLEAR EXAMPLE OF WHAT I WANT TO ACHIEVE***
  {% block head %}
    <ul class="Menu">
    {% for item in menuItems %}
        <li>
            <a href="{{ item.link }}">{{ item.name }}</a>
        </li>
    {% endfor %}
    </ul>
   {% endblock %} -->


  </head>
  <body>
    <div class="container">
        {% block content %}
        {% endblock %}
        {% for message in get_flashed_messages() %}
            {{ message }}
        {% endfor %}
        {% if error %}
            <p class="error"><strong>Error:</strong> {{ error }}
        {% endif %}
    </div> <!-- container -->
    <!-- Optional JavaScript -->
    <!-- jQuery first, then Popper.js, then Bootstrap JS -->
    <!-- <script src="https://code.jquery.com/jquery-3.2.1.slim.min.js" integrity="sha384-KJ3o2DKtIkvYIK3UENzmM7KCkRr/rE9/Qpg6aAZGJwFDMVNA/GpGFF93hXpG5KkN" crossorigin="anonymous"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.12.9/umd/popper.min.js" integrity="sha384-ApNbgh9B+Y1QKtv3Rn7W3mgPxhU9K/ScQsAP7hUibX39j7fakFPskvXusvfa0b4Q" crossorigin="anonymous"></script>
    <script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js" integrity="sha384-JZR6Spejh4U02d8jOt6vLEHfe/JQGiRRSQQxSfFWpi1MquVdAyjUar5+76PVCmYl" crossorigin="anonymous"></script> -->
  </body>
</html>

I'm grateful for any advise or link to a guide that gets me closer to achieving my goal since I've been stuck on this for a while.

HTML that appears in the <head> section is not displayed -- it's there to define stuff that isn't part of the visible page itself -- the title to put on the browser tab and that kind of thing. If you put it in the <body> section then it will be rendered. So, for example, if you want it at the top of the page, just put it above the {% block content %} section.

giles, thanks for your reply but the menu will not be rendered if I i type for example username.pythonanywhere.com/welcome The welcome page uses the template.html file:

{% extends "template.html" %}
{% block content %}
    <div class="jumbo">
        <h1>Welcome</h1>
        <p>How is you day sir/madame?</p>
    </div>

{% endblock %}

I want the menu to appear on all directories by placing it in my template.html file some how, but @app.route() only renders it on a specific directory for example @app.route('/menu1'). If I use @app.route('/template') the menu will never appear since I'm not using the directory username.pythonanywhere.com/template There must be a solution for this.

Can I take a look at your code? We can see it from our admin interface, but we always ask for permission first.

giles, sure, go right ahead.

Thanks!

OK, so I think I see what the problem is. In your template.html, you've put the code to iterate over the menu items inside the content block. This means that in any template that inherits from the template and overrides the content block, the menu items won't appear.

A simplified example might make this clearer. Let's say you have a template:

A
{% block foo %}
B
{% endblock %}
C

If you then extend that in another template with this:

{% extends "template.html" %}
{% block foo %}
D 
{% endblock %}

...then the result will be

A 
D
C

If what you wanted was

A
B
C
D

...then your original template should instead be

A
B
{% block foo %}
{% endblock %}
C

It works if I go to bob123b.pythonanywhere.com/template. Any other directory will give me an unpopulated unordered list (no list items). Isn't the point of for example @app.route('/template') that it only runs if you go the the directory bob123b.pythonanywhere.com/template ? I need it to always render, no matter what directory I go to.

You can probably use a variable route to make your app publish a route that has a variable component.