I have a basic Flask purchase order management CRUD program that I'm putting together. The current functionality allows me to input purchase orders, and add items to said orders (Item type and quantity). I am currently working on an edit route that allows me to edit the pre-existing items on an order, and to do that I need to set the value of the item select fields and item quantity control fields to the current pre-existing values. To begin, I've tried doing this for the first order item (each order can have up to 10) by querying the item object and setting it as the value for the item1 select field. For some reason it isn't working - my select field only shows the default 'Please Select' when I run the program. I've troubleshooted by adding some print statements, which show that the object does exist - so I am assuming the problem is somehow with the way I am setting the select field value. Thanks in advance for any advice. For reference, I've attached my model, route, form, and template.
*MODELS MODULE**
class Order(db.Model):
__tablename__='orders'
id = db.Column(db.Integer, primary_key=True)
po_number = db.Column(db.String(64), index=True, unique=True)
date = db.Column(db.Date)
customer_id = db.Column(db.Integer, db.ForeignKey('customers.id'))
carrier_id = db.Column(db.Integer, db.ForeignKey('carriers.id'))
cpiq = db.Column(db.Boolean, default=False)
tracker = db.Column(db.Integer)
destination = db.Column(db.String(50))
notes = db.Column(db.String(100))
cpiq_number = db.Column(db.String(30))
tracker = db.Column(db.Integer)
carrier = db.relationship("Carriers", back_populates="order")
customer = db.relationship("Customer", back_populates="order")
order_item = db.relationship('OrderItem', back_populates="order")
#this below will be useful for debugging
def __repr__(self):
class OrderItem(db.Model):
__tablename__='order_items'
id = db.Column(db.Integer, primary_key=True)
item_number = db.Column(db.Integer)
package_type_id = db.Column(db.Integer, db.ForeignKey('items.id'))
quantity = db.Column(db.Integer)
order_id = db.Column(db.Integer, db.ForeignKey('orders.id'))
order = db.relationship("Order", back_populates='order_item')
item = db.relationship("Item", back_populates='order_item')
def __repr__(self):
return '<OrderItem {}>'.format(self.package_type_id)
def getOrder():
order = self.order_id.po_number
print(order)
class Item(db.Model):
__tablename__='items'
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(50))
label = db.Column(db.String(150))
package = db.Column(db.String(50))
product = db.Column(db.String(20))
weight = db.Column(db.Integer)
grade = db.Column(db.String(10))
order_item = db.relationship("OrderItem", back_populates="item")
def __repr__(self):
return '<Item {}>'.format(self.name)
**ROUTE SNIPPET**
@app.route('/update_items/<int:id>', methods=['GET', 'POST'])
def update_items(id):
form = ItemForm()
order_to_update = Order.query.get_or_404(id)
if form.validate_on_submit():
# Retreive any old order items for this order and delete them
order_items = OrderItem.query.filter(OrderItem.order_id==order_to_update.id).all()
for order_item in order_items:
db.session.delete(order_item)
# go through each filled form element, and create new order items based on the information.
for i in range(1, 11):
# First get the item.id and item.quantity (Item object) from the select field and control field
item_data = getattr(form, 'item' + str(i)).data
quantity_data = getattr(form, 'item' + str(i) + '_quantity').data
# If there's nothing in the item select field, skip it
if not item_data:
continue # Skip if item is not provided
# Create a and add new OrderItem object, passing in the Item object id for the package_type_id
item = OrderItem(
package_type_id=item_data.id,
quantity=quantity_data,
order_id=order_to_update.id,
item_number=i
)
db.session.add(item)
try:
db.session.commit()
flash('Items updated!')
return redirect('/index')
except Exception as e:
print("Error:", str(e)) # Print the error message if there's an exception
db.session.rollback() # Rollback the session to avoid partial updates
flash('Error! Problem updating items.')
return redirect('/index')
else:
# Generate form, with fields pre-filled with pre-existing order items
# Grab order item id's based on order
order_item = OrderItem.query.filter(OrderItem.order_id==order_to_update.id)
# For each order item..
# Grab and store the package_type_id
order_item = order_item[0]
print('Order Item: ',order_item)
package_id = order_item.package_type_id
print('Package ID: ',package_id)
# Use the package_type_id to grab the name of the package type, store it
package = Item.query.get(package_id)
print('Package', package)
# Set the select field for the item select field to the package name by default
if package:
form.item1.data = package.id
print('Package Name: ', package.name)
#render the template
return render_template('update_items.html', title='Add Order Items', form=form, order_to_update=order_to_update, package=package)
**FORM SNIPPET**
class ItemForm(FlaskForm):
item1 = QuerySelectField('Item 1:', query_factory=lambda: Item.query, allow_blank=True, blank_text=u'Please Select', get_label='name')
item1_quantity = IntegerField('Item 1 Quantity:', validators=[Optional()])
item2 = QuerySelectField('Item 2:', query_factory=lambda: Item.query, allow_blank=True, blank_text=u'Please Select', get_label='name')
item2_quantity = IntegerField('Item 2 Quantity:', validators=[Optional()])
item3 = QuerySelectField('Item 3:', query_factory=lambda: Item.query, allow_blank=True, blank_text=u'Please Select', get_label='name')
item3_quantity = IntegerField('Item 3 Quantity:', validators=[Optional()])
item4 = QuerySelectField('Item 4:', query_factory=lambda: Item.query, allow_blank=True, blank_text=u'Please Select', get_label='name')
item4_quantity = IntegerField('Item 4 Quantity:', validators=[Optional()])
item5 = QuerySelectField('Item 5:', query_factory=lambda: Item.query, allow_blank=True, blank_text=u'Please Select', get_label='name')
item5_quantity = IntegerField('Item 5 Quantity:', validators=[Optional()])
item6 = QuerySelectField('Item 6:', query_factory=lambda: Item.query, allow_blank=True, blank_text=u'Please Select', get_label='name')
item6_quantity = IntegerField('Item 6 Quantity:', validators=[Optional()])
item7 = QuerySelectField('Item 7:', query_factory=lambda: Item.query, allow_blank=True, blank_text=u'Please Select', get_label='name')
item7_quantity = IntegerField('Item 7 Quantity:', validators=[Optional()])
item8 = QuerySelectField('Item 8:', query_factory=lambda: Item.query, allow_blank=True, blank_text=u'Please Select', get_label='name')
item8_quantity = IntegerField('Item 8 Quantity:', validators=[Optional()])
item9 = QuerySelectField('Item 9:', query_factory=lambda: Item.query, allow_blank=True, blank_text=u'Please Select', get_label='name')
item9_quantity = IntegerField('Item 9 Quantity:', validators=[Optional()])
item10 = QuerySelectField('Item 10:', query_factory=lambda: Item.query, allow_blank=True, blank_text=u'Please Select', get_label='name')
item10_quantity = IntegerField('Item 10 Quantity:', validators=[Optional()])
submit = SubmitField('Add Items')
**TEMPLATE**
{% extends "base.html" %}
{% import 'bootstrap/wtf.html' as wtf %}
{% block content %}
<form action="/update_order/{{ order_to_update.id }}" method="post" novalidate>
{{ form.hidden_tag() }}
<p>
{{ form.po_number.label (class="form-label") }}<br>
{{ form.po_number(class="form-control", value=order_to_update.po_number, size=32) }}
{% for error in form.po_number.errors %}
<span style="color: red;">[{{ error }}]</span>
{% endfor %}
</p>
<p>
{{ form.date.label (class="form-label") }}<br>
{{ form.date(class="form-control", value=order_to_update.date, size=32) }}
{% for error in form.date.errors %}
<span style="color: red;">[{{ error }}]</span>
{% endfor %}
</p>
<p>
{{ form.customer.label (class="form-label") }}<br>
{{ form.customer(class="form-select", value=order_to_update.customer, size=1) }}
{% for error in form.customer.errors %}
<span style="color: red;">[{{ error }}]</span>
{% endfor %}
</p>
<p>
{{ form.carrier.label (class="form-label") }}<br>
{{ form.carrier(class="form-select", value=order_to_update.carrier, size=1) }}
{% for error in form.carrier.errors %}
<span style="color: red;">[{{ error }}]</span>
{% endfor %}
</p>
<p>
{{ form.destination.label (class="form-label") }}<br>
{{ form.destination(class="form-control",value=order_to_update.destination, size=1) }}
{% for error in form.destination.errors %}
<span style="color: red;">[{{ error }}]</span>
{% endfor %}
</p>
<p>
{{ form.notes.label (class="form-label") }}<br>
{{ form.notes(class="form-control", value=order_to_update.notes, size=32) }}
{% for error in form.notes.errors %}
<span style="color: red;">[{{ error }}]</span>
{% endfor %}
</p>
<p>
{{ form.cpiq.label (class="form-check-label") }}<br>
{% if order_to_update.cpiq %}
{{ form.cpiq(class="form-check-input", id="cpiqCheckbox", value="true", checked="checked") }}
{% else %}
{{ form.cpiq(class="form-check-input", id="cpiqCheckbox", value="true") }}
{% endif %}
{% for error in form.cpiq.errors %}
<span style="color: red;">[{{ error }}]</span>
{% endfor %}
</p>
<p>
{{ form.tracker.label (class="form-label") }}<br>
{{ form.tracker(class="form-control", id="trackerField",value=order_to_update.tracker, size=1, disabled="disabled") }}
{% for error in form.tracker.errors %}
<span style="color: red;">[{{ error }}]</span>
{% endfor %}
</p>
<p>
{{ form.cpiq_number.label (class="form-label") }}<br>
{{ form.cpiq_number(class="form-control", id="cpiqNumberField",value=order_to_update.cpiq_number, size=1, disabled="disabled") }}
{% for error in form.cpiq_number.errors %}
<span style="color: red;">[{{ error }}]</span>
{% endfor %}
</p>
<p>
{{ form.submit(class="btn btn-primary") }}
<a href="{{ url_for('delete_order', id=order_to_update.id) }}" class="btn btn-danger">Delete</a></p>
</form>
<script>
$(document).ready(function() {
// Function to enable or disable the tracker and cpiq_number fields based on the cpiq checkbox state
function updateFieldsState() {
if ($('#cpiqCheckbox').prop('checked')) {
$('#trackerField').prop('disabled', false);
$('#cpiqNumberField').prop('disabled', false);
} else {
$('#trackerField').prop('disabled', true);
$('#cpiqNumberField').prop('disabled', true);
}
}
// Initially set the fields state based on the cpiq checkbox value
updateFieldsState();
// Listen for changes to the cpiq checkbox and update the fields state accordingly
$('#cpiqCheckbox').on('change', function() {
updateFieldsState();
});
});
</script>
{% endblock %}
As I said, so far I've tried troubleshooting with print statements, with no luck. To make the program work for the time being, the user has to reinput all the order items each time the edit items route is opened.
To fill the form with data, you can pass a dict to the data attribute of the form. This should contain the identifier of the form field as a key and the assigned value as a value. To fill out the form, use the relationships that you created in the database model.
@app.route('/update_items/<int:id>', methods=['GET', 'POST'])
def update_items(id):
order = Order.query.get_or_404(id)
form_data = {}
for i, order_item in enumerate(order.order_item):
form_data[f'item{i + 1}'] = order_item.item
form_data[f'item{i + 1}_quantity'] = order_item.quantity
form = ItemForm(request.form, data=form_data)
# ...