0

I am working on a Grocery-Store web application using Flask and SQLAlchemy I am trying to print the products as a card arranged under their respective categories But then I get this error. I can't seem to figure out what the error is. All the functions and variables seem to be declared perfectly.

Here's the block of code of app.py

return Product.query.filter_by(category_id=category_id).all()
@app.route('/')
def index():
categories = Category.query.all()
products = Product.query.order_by(Product.id.desc()).limit(10).all()
return render_template('index.html', categories=categories, products=products)

The block of code in index.html


    {% extends "base.html" %}
    
    {% block content %}
    <div class="container mt-5">
        {% for category in categories %}
        <h2>{{ category.name }}</h2>
        <div class="row">
            {% set category_products = get_products_by_category(category.id) %}
            {% for product in category_products %}
                        <div class="col-md-4 mb-4">
                        <div class="card">
                            <div class="card-body">
                                <h5 class="card-title">{{ product.name }}</h5>
                                <p class="card-text">Price: {{ product.price }}</p>
                                {% if 'user_id' in session %}
                                    <form action="{{ url_for('add_to_cart', product_id=product.id) }}" method="post">
                                        <button class="btn btn-primary" type="submit">+</button>
                                    </form>
                                    <form action="{{ url_for('remove_from_cart', product_id=product.id) }}" method="post">
                                        <button class="btn btn-danger" type="submit">-</button>
                                    </form>
                                {% else %}
                                    <p><a href="{{ url_for('login') }}">Log in</a> to add products to your cart</p>
                                {% endif %}
                            </div>
                        </div>
                    </div>
                {% endfor %}
            </div>
        {% endfor %}
    </div>
    
    {% endblock %}

This is the traceback:

return self.wsgi_app(environ, start_response)
       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "C:\Users\Admin\AppData\Local\Programs\Python\Python311\Lib\site-packages\flask\app.py", line 2193, in wsgi_app
response = self.handle_exception(e)
           ^^^^^^^^^^^^^^^^^^^^^^^^
File "C:\Users\Admin\AppData\Local\Programs\Python\Python311\Lib\site-packages\flask\app.py", line 2190, in wsgi_app
response = self.full_dispatch_request()
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "C:\Users\Admin\AppData\Local\Programs\Python\Python311\Lib\site-packages\flask\app.py", line 1486, in full_dispatch_request
rv = self.handle_user_exception(e)
     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "C:\Users\Admin\AppData\Local\Programs\Python\Python311\Lib\site-packages\flask\app.py", line 1484, in full_dispatch_request
rv = self.dispatch_request()
     ^^^^^^^^^^^^^^^^^^^^^^^
File "C:\Users\Admin\AppData\Local\Programs\Python\Python311\Lib\site-packages\flask\app.py", line 1469, in dispatch_request
return self.ensure_sync(self.view_functions[rule.endpoint])(**view_args)
       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "c:\Users\Admin\Desktop\Ananyaa\MAD1\app.py", line 71, in index
return render_template('index.html', categories=categories, products=products)
       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "C:\Users\Admin\AppData\Local\Programs\Python\Python311\Lib\site-packages\flask\templating.py", line 151, in render_template
return _render(app, template, context)
       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "C:\Users\Admin\AppData\Local\Programs\Python\Python311\Lib\site-packages\flask\templating.py", line 132, in _render
rv = template.render(context)
     ^^^^^^^^^^^^^^^^^^^^^^^^
File "C:\Users\Admin\AppData\Local\Programs\Python\Python311\Lib\site-packages\jinja2\environment.py", line 1301, in render
self.environment.handle_exception()
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "C:\Users\Admin\AppData\Local\Programs\Python\Python311\Lib\site-packages\jinja2\environment.py", line 936, in handle_exception
raise rewrite_traceback_stack(source=source)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "c:\Users\Admin\Desktop\Ananyaa\MAD1\template\index.html", line 11, in top-level template code
{% extends "base.html" %}
File "c:\Users\Admin\Desktop\Ananyaa\MAD1\template\base.html", line 28, in top-level template code
{% block content %}
File "c:\Users\Admin\Desktop\Ananyaa\MAD1\template\index.html", line 18, in block 'content'
{% set category_products = get_products_by_category(category.id) %}
File "C:\Users\Admin\AppData\Local\Programs\Python\Python311\Lib\site-packages\jinja2\utils.py", line 83, in from_obj
if hasattr(obj, "jinja_pass_arg"):
   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
jinja2.exceptions.UndefinedError: 'get_products_by_category' is undefined```

Can someone help me point out the error?

Ananyaa S
  • 1
  • 1

1 Answers1

0

The function get_products_by_category is not known within jinja.
It is not possible to use a defined function in Jinja without assigning it to the Jinja environment globals or passing it to the template via render_template.

app.jinja_env.globals.update(get_products_by_category=get_products_by_category)

In your example, however, I think it makes more sense to define a relationship between the two database models Category and Product beyond the use of a foreign key.
The following example shows you the possibility of using relationship in combination with the backref attribute to make the products of the category accessible.

class Product(db.Model):
    __tablename__ = 'products'

    id = db.Column(db.Integer, primary_key=True)
    
    # ...

    category_id = db.Column(db.Integer, db.ForeignKey('categories.id'))
    category = db.relationship('Category', backref='products')

class Category(db.Model):
    __tablename__ = 'categories'

    id = db.Column(db.Integer, primary_key=True)

    # ...

The iteration within the template would then look like this.

<div class="container mt-5">
    {% for category in categories -%}
    <!-- ... -->
    <div class="row">
        {% for product in category.products -%}
        {# Use the respective product of the category here. #}
        <!-- ... -->
        {% endfor -%}
    </div>
    {% endfor -%}
</div>
Detlef
  • 6,137
  • 2
  • 6
  • 24