0

I am using flask, and I am wondering, how can I get my application variable into my html template without needing to add it when calling the template like in this example:

render_template('home.html', app=app)

Maybe there is a import function I don't know about.

I would like to make it so I can loop through all of my endpoints(app.url_map.iter_rules()) and compare them with the current endpoint( request.endpoint) . My current main problem is getting all of the endpoints into my html file.

My current way of achieving my navigation bar is this:

<header>
   <div class="head" align="center">
       {% if request.endpoint!='users.login' and current_user.is_authenticated!=true %}
           <a  href="{{ url_for('users.login') }}">
               <button class="tablecontent">Login</button>
           </a>
       {% endif %}
       {% if request.endpoint!='users.register' %}
           <a  href="{{ url_for('users.register') }}">
               <button class="tablecontent">Register</button>
           </a>
       {% endif %}
       {% if request.endpoint!='core.home_page' %}
           <a  href="{{ url_for('core.home_page') }}">
               <button class="tablecontent">Home</button>
           </a>
       {% endif %}
       {% if current_user.is_authenticated %}
           {% if request.endpoint!='users.logout' %}
               <a  href="{{ url_for('users.logout') }}">
                   <button class="tablecontent">Logout</button>
               </a>
           {% endif %}
       {% endif %}
       {% if current_user.is_authenticated %}
           {% if request.endpoint!='products.new_product' %}
               <a  href="{{ url_for('products.add_product') }}">
                   <button class="tablecontent">Add Product</button>
               </a>
           {% endif %}
       {% endif %}
   </div>
</header>

The import error when I try to use the sitemap from the answer:

  File "C:\Users\ulman\PycharmProjects\database_website_optimised\source\database_website\application.py", line 20, in register_applications
    from database_website.applications.core.urls import blueprint as core_blueprint
  File "C:\Users\ulman\PycharmProjects\database_website_optimised\source\database_website\applications\core\urls.py", line 3, in <module>
    from database_website.applications.core import views
  File "C:\Users\ulman\PycharmProjects\database_website_optimised\source\database_website\applications\core\views.py", line 7, in <module>
    from database_website.properties import sitemap
  File "C:\Users\ulman\PycharmProjects\database_website_optimised\source\database_website\properties.py", line 4, in <module>
    from database_website.application import application
  File "C:\Users\ulman\PycharmProjects\database_website_optimised\source\database_website\application.py", line 39, in <module>
    application = Application.create()
  File "C:\Users\ulman\PycharmProjects\database_website_optimised\source\database_website\application.py", line 35, in create
    instance.register_applications()
  File "C:\Users\ulman\PycharmProjects\database_website_optimised\source\database_website\application.py", line 20, in register_applications
    from database_website.applications.core.urls import blueprint as core_blueprint
ImportError: cannot import name 'blueprint' from 'database_website.applications.core.urls' (C:\Users\ulman\PycharmProjects\database_website_optimised\source\database_website\applications\core\urls.py)

My view file:

from flask import Flask, render_template, url_for, flash, redirect, request
from flask.views import MethodView

from database_website.applications.views import FormViewMixin
from database_website.applications.products.models import Product
from database_website.applications.core import forms
from database_website.application import application


def has_no_empty_params(rule):
    defaults = rule.defaults if rule.defaults is not None else ()
    arguments = rule.arguments if rule.arguments is not None else ()
    return len(defaults) >= len(arguments)

def sitemap():
    links = []
    for rule in application.url_map.iter_rules():
        # Filter out rules we can't navigate to in a browser
        # and rules that require parameters
        if "GET" in rule.methods and has_no_empty_params(rule):
            url = url_for(rule.endpoint, **(rule.defaults or {}))
            links.append((url, rule.endpoint))
    return links

class HomePageView(MethodView, FormViewMixin):

    def get(self):
        form = forms.ProductSearchForm()
        products = Product.query.all()
        return render_template('core/home.html', title='Home',  products=products, form=form)

    def post(self):

        product_search = request.form.get('search_name')

        return redirect(url_for('products.search_product', search_name=product_search))

This is when it has sitemap hardoced, it still shows the exact same error because at the time, when the application object gets imported it does not exist yet. I can show the way I initialize my app.

MareksNo
  • 140
  • 2
  • 12
  • As far as I know that is the simplest most common, way to go about it. I am sure there are some convulated hacks you might be able to do. But your above example is how it is generally done. Is there a particular reason you want to do it differently? Could you add more information and context to your question? – Akib Rhast May 30 '20 at 15:10
  • I want to make a navigation bar, I have got a good idea how I could make it without many if loops it involves using app.url_map. As it would be displayed in every page I would need to include this variable in every single place I render a template. I know that there is Flask-Nav, but I just wanted to try making that without installing another library. – MareksNo May 30 '20 at 15:19
  • Does this answer your question? Or does this help you do what you are trying to achieve? https://stackoverflow.com/questions/62094647/flaskwtf-same-form-on-every-view-page/62095737?noredirect=1#comment109826776_62095737 – Akib Rhast May 30 '20 at 15:42
  • No, as I have gotten an idea of how I will get the html to show on every page as a header, and I just need to find a way to import my app into the base html template so I cpuld use app.url_map within my template, but maybe I just missed that part in that post. Edit: Maybe the include would work with a .py file though. – MareksNo May 30 '20 at 15:47
  • Let me see if I understand your question correctly. (1) You want to create a navbar . (2)You want the navbar to appear on every page? – Akib Rhast May 30 '20 at 15:56
  • Yes, but that part isnt my problem. I making the nav bar so that the current page wouldnt be displayed on it, so my idea is to loop thoigh all of my endpoints that I get using app.url_map and then compare it to request.endpoint, but to use url_map I need to import the application object into the base.html file. – MareksNo May 30 '20 at 17:41
  • Sorry for being bad at explaining. – MareksNo May 30 '20 at 18:02
  • Ah thank you for clarifying it makes more sense now. May i ask what you meant by "", I have got a good idea how I could make it without many if loops it involves using app.url_map"" – Akib Rhast May 30 '20 at 18:54
  • So right now I have it where it checks if the current endpoint is the same a hardcoded endpoints, but if I would use app.url_map, I could get all of my endpoints and if one name would be changed, I wouln't need to change it manually and that way I could loop through all of the endpoints and seeing which ones to show and which one to not show, I hope I explained my idea somewhat understandably. – MareksNo May 30 '20 at 18:59
  • Could you update your original post to reflect the details of what you want to do. Also code snippet of how you are doing " I have it where it checks if the current endpoint is the same a hardcoded endpoints" . Something like an [MRE] would be good – Akib Rhast May 30 '20 at 19:13
  • Ok, added the snipped and summary of some details, if you need more info of something I can provide more. – MareksNo May 30 '20 at 19:47
  • Thanks for the update. So you are struggling with this "My current main problem is getting all of the endpoints into my html file." ? Right? @MareksNo – Akib Rhast May 30 '20 at 19:49
  • Yes, as the Map utility needs the app object. – MareksNo May 30 '20 at 19:53
  • I have added an answer, let me know if it works? Also, if all the code abocve are navigation bar/nav links. Look into using #include with jinja. Since typically your href, scripts and some other stuff also goes into the header file. You could separate the navigation component into its own file – Akib Rhast May 30 '20 at 20:03
  • So you would end up with something like
    {% include "navbar.html" ignore missing with context %}
    . Here is a link https://tedboy.github.io/jinja2/templ11.html?highlight=include#include
    – Akib Rhast May 30 '20 at 20:06

1 Answers1

1

Hopefully this will help :

def has_no_empty_params(rule):
    defaults = rule.defaults if rule.defaults is not None else ()
    arguments = rule.arguments if rule.arguments is not None else ()
    return len(defaults) >= len(arguments)

def sitemap():
    links = []
    for rule in app.url_map.iter_rules():
        # Filter out rules we can't navigate to in a browser
        # and rules that require parameters
        if "GET" in rule.methods and has_no_empty_params(rule):
            url = url_for(rule.endpoint, **(rule.defaults or {}))
            links.append((url, rule.endpoint))
    return links

render_template('home.html', links=sitemap())

{% for url, endpoint in links %}
    <a href="{{ url }}">{{ endpoint }}</a>
{% endfor %}
Akib Rhast
  • 651
  • 4
  • 15
  • Thank you, I will try this out tomorrow as it is late from where I am from, but if you could help me understand what the first function does, I would be thankful. – MareksNo May 30 '20 at 20:05
  • I think this link might help you as that is where I have gotten my answer. https://stackoverflow.com/questions/13317536/get-list-of-all-routes-defined-in-the-flask-app . – Akib Rhast May 30 '20 at 20:10
  • Ok sweet, I guess I will let you know tomorrow if it worked or not if that is ok, my only concern is that I mihht have problems with some imports(due to how the app is initialized/split up) but that is unrelated to this. Have a good day/evening/night. – MareksNo May 30 '20 at 20:15
  • Sadly when initializing, if I import it into my view file I get an import error, I am guessing because it goes like this: Registering the blueprints, it looks into my view file, finds the sitemap import, looks there, sees import application, when the application hasn't finished loading yet., This is the error:| from database_website.applications.core.urls import blueprint as core_blueprint ImportError: cannot import name 'blueprint' from 'database_website.applications.core.urls' (C:\Users\ulman\PycharmProjects\database_website_optimised\source\database_website\applications\core\urls.py) – MareksNo May 31 '20 at 09:58
  • I added a longer version of the traceback to my post, I somehow now have to find a way for it to not try importing the application object before it exists. – MareksNo May 31 '20 at 10:00
  • "if I import it into my view file I get an import error" , what are you importing to the view file ? Could you update your op with the view file ? Also instead of importing the above code into your view file could you hardcode it into the view file and test if it works? – Akib Rhast May 31 '20 at 15:18
  • It wont work, because the problem isnt when I import the code into my biew it is when it cycles though the imports, goes to the file with the function and sees the application import at which point application isnt defined yet, I will try includong the view file I guess though – MareksNo May 31 '20 at 16:09
  • Yeah tried hardcoding it into the view file, same error, added the view file code to the post. – MareksNo May 31 '20 at 16:18
  • Unfortunately, this isn't an error I know the answer to of the top of my head(from the look of your view that you posted, you are right in your statement off "It wont work, because the problem isnt when I import the code into my biew it is when it cycles though the imports, goes to the file with the function and sees the application import at which point application isnt defined yet" ). If you have a git that I can clone, I would be happy to try and debug :D – Akib Rhast May 31 '20 at 16:28
  • Welp, here it is, I am thankful for your help. https://github.com/MareksNo/database_website_withimportproblem The reason some views, if you end up looking into them, are over the place is because I am in the middle of optimising certain things :) – MareksNo May 31 '20 at 17:16
  • Just got an idea, could it be possible for the sitemap be made into a macro in htmp templates? Because those dont get called until a function renders the template, in the result of the applicatiom object would exist by the time the import gets called, but not quite sure how to execute that. – MareksNo May 31 '20 at 17:23
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/215047/discussion-between-akib-rhast-and-mareksno). – Akib Rhast May 31 '20 at 19:45