I am trying to autopopulate data from my Flask-SQLAlchemy database to a FlaskForm. Here are my code snippets:
class Products(db.Model):
id = db.Column(db.Integer(), primary_key=True)
name = db.Column(db.String(100), nullable=False, unique=True)
cost = db.Column(db.Float(), nullable=False)
price = db.Column(db.Float(), nullable=False)
category = db.Column(db.String(20), nullable=False)
details = db.Column(db.String(255), nullable=True)
quantity = db.Column(db.Integer(), nullable=False, default=0)
threshold = db.Column(db.Integer(), nullable=False, default=0)
prod_img = db.Column(db.String(20), nullable=False, default='prod_img.jpg')
disc_amt = db.Column(db.Float(), nullable=True)
disc_percent = db.Column(db.Float(), nullable=True)
disc_conditions = db.Column(db.String(255), nullable=True)
promo_start = db.Column(db.DateTime(), nullable=True)
promo_end = db.Column(db.DateTime(), nullable=True)
def __repr__(self):
return f"Products('{self.name}', '{self.price}', '{self.quantity}')"
I want to autopopulate the products from this model to a form that takes in purchases. Here are my forms:
from flask_wtf import FlaskForm
from wtforms import SubmitField, FloatField, IntegerField, FieldList, FormField, DateField
from wtforms.validators import DataRequired
from wtforms_sqlalchemy.fields import QuerySelectField
from root.models import Products, Suppliers
class ProductForm(FlaskForm):
name = QuerySelectField('Product Name', validators=[DataRequired()], query_factory=lambda: Products.query.all(), get_label='name')
quantity = IntegerField('Quantity', validators=[DataRequired()])
total = FloatField('Total Cost', validators=[DataRequired()])
submit = SubmitField('Add Product')
class ReceiptForm(FlaskForm):
date = DateField('Date', validators=[DataRequired()])
supplier = QuerySelectField('Supplier', validators=[DataRequired()], query_factory=lambda: Suppliers.query.all(), get_label='company')
products = FieldList(FormField(ProductForm), min_entries=1)
submit = SubmitField('Add Purchase')
And here is my route:
from flask import Blueprint, render_template
from root.models import Products
from root.purchases.forms import ReceiptForm
purchases = Blueprint('purchases', __name__)
@purchases.route('/add_receipt/', methods=['GET', 'POST'])
def add_receipt():
form = ReceiptForm()
print(type(form.products[0].name)) # Print the type of the 'name' field
print(form.products[0].name) # Print the 'name' field itself
if form.validate_on_submit():
pass
return render_template('add_purchases.html', form=form)
And finally a snippet of my template:
<div class="card">
<div class="card-header"><h2 class="lead">Add Purchases</h2></div>
<div class="card-body">
<form action="" id="purchase-form">
{{ form.hidden_tag() }}
<div class="mb-3">
{{ form.date.label }} {{ form.date(class="form-control") }}
</div>
<div class="mb-3">
{{ form.supplier.label }} {{ form.supplier(class="form-control") }}
</div>
{% for product_form in form.products %}
<div class="mb-3">
{{ product_form.name.label }} {{ product_form.name(class="form-control") }}
{{ product_form.quantity.label }} {{ product_form.quantity(class="form-control") }}
{{ product_form.total.label }} {{ product_form.total(class="form-control") }}
</div>
{% endfor %}
<button type="submit" class="btn btn-primary">Submit</button>
</form>
</div>
When I run this code, I keep getting the error below:
127.0.0.1 - - [09/Sep/2023 16:24:36] "GET /add_receipt/ HTTP/1.1" 500 -
Traceback (most recent call last):
File "X:\Code\a-FLASK\Projects\retail_pos\virt\Lib\site-packages\flask\app.py", line 2213, in __call__
return self.wsgi_app(environ, start_response)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "X:\Code\a-FLASK\Projects\retail_pos\virt\Lib\site-packages\flask\app.py", line 2193, in wsgi_app
response = self.handle_exception(e)
^^^^^^^^^^^^^^^^^^^^^^^^
File "X:\Code\a-FLASK\Projects\retail_pos\virt\Lib\site-packages\flask\app.py", line 2190, in wsgi_app
response = self.full_dispatch_request()
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "X:\Code\a-FLASK\Projects\retail_pos\virt\Lib\site-packages\flask\app.py", line 1486, in full_dispatch_request
rv = self.handle_user_exception(e)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "X:\Code\a-FLASK\Projects\retail_pos\virt\Lib\site-packages\flask\app.py", line 1484, in full_dispatch_request
rv = self.dispatch_request()
^^^^^^^^^^^^^^^^^^^^^^^
File "X:\Code\a-FLASK\Projects\retail_pos\virt\Lib\site-packages\flask\app.py", line 1469, in dispatch_request
return self.ensure_sync(self.view_functions[rule.endpoint])(**view_args)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "x:\Code\a-FLASK\Projects\retail_pos\root\purchases\routes.py", line 16, in add_receipt
return render_template('add_purchases.html', form=form)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "X:\Code\a-FLASK\Projects\retail_pos\virt\Lib\site-packages\flask\templating.py", line 151, in render_template
return _render(app, template, context)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "X:\Code\a-FLASK\Projects\retail_pos\virt\Lib\site-packages\flask\templating.py", line 132, in _render
rv = template.render(context)
^^^^^^^^^^^^^^^^^^^^^^^^
File "X:\Code\a-FLASK\Projects\retail_pos\virt\Lib\site-packages\jinja2\environment.py", line 1301, in render
self.environment.handle_exception()
File "X:\Code\a-FLASK\Projects\retail_pos\virt\Lib\site-packages\jinja2\environment.py", line 936, in handle_exception
raise rewrite_traceback_stack(source=source)
File "x:\Code\a-FLASK\Projects\retail_pos\root\templates\add_purchases.html", line 1, in top-level template code
{% extends 'base.html' %}
File "x:\Code\a-FLASK\Projects\retail_pos\root\templates\base.html", line 162, in top-level template code
{% block content %}{% endblock content %}
File "x:\Code\a-FLASK\Projects\retail_pos\root\templates\add_purchases.html", line 30, in block 'content'
{{ product_form.name.label }} {{ product_form.name(class="form-control") }}
TypeError: 'str' object is not callable
127.0.0.1 - - [09/Sep/2023 16:24:36] "GET /add_receipt/?__debugger__=yes&cmd=resource&f=style.css HTTP/1.1" 304 -
127.0.0.1 - - [09/Sep/2023 16:24:36] "GET /add_receipt/?__debugger__=yes&cmd=resource&f=debugger.js HTTP/1.1" 304 -
127.0.0.1 - - [09/Sep/2023 16:24:36] "GET /add_receipt/?__debugger__=yes&cmd=resource&f=console.png HTTP/1.1" 304 -
127.0.0.1 - - [09/Sep/2023 16:24:37] "GET /add_receipt/?__debugger__=yes&cmd=resource&f=console.png HTTP/1.1" 304 -
Can someone please tell me where I went wrong?
I tried working with the coerce function as well but that bore me another whole mountain of errors.
The error is occurring because
product_form.nameis a string, not aQuerySelectFieldas you intended.For debugging purposes, you can print
form.products[0].namebefore rendering the template to inspect what it contains. It should be a field object, not astring.