使用Asciimatics开发购物应用遇too many values to unpack错误求助
解决Asciimatics ListBox的"too many values to unpack"错误
这个错误的根源很明确:Asciimatics的ListBox组件要求选项是二元组格式,也就是(显示文本, 对应值),但你直接把SQLite返回的完整行对象(包含多个字段)传递给了ListBox,导致组件尝试解包时无法匹配预期的2个值。
具体修复步骤
1. 修正ListBox的选项格式
在你的Shop类中,需要把数据库返回的商品记录转换成ListBox能识别的二元组。我们可以把商品名称+价格作为显示文本,商品ID作为对应的值(方便后续操作数据库):
修改Shop类的__init__和loadContent方法:
def __init__(self, screen, db): super(Shop, self).__init__(screen, screen.height * 2 // 3, screen.width * 2 // 3, on_load=self.loadContent, hover_focus=True, title="Obchod ~~ ASCIIMATICO ~~") self.model = db # 初始化时就传入格式化后的选项 formatted_products = [(f"{row['product']} - {row['price']}€", row['id']) for row in db.showAllProducts()] self.productsList = ListBox(Widget.FILL_FRAME, formatted_products, name="shop") # ... 其余代码保持不变 def loadContent(self): # 重新加载时也要格式化选项 formatted_products = [(f"{row['product']} - {row['price']}€", row['id']) for row in self.model.showAllProducts()] self.productsList.options = formatted_products
2. 修正购物车添加逻辑
你的addToCart方法里有两个错误:引用了不存在的self._model和错误的字段名contacts(你的ListBox name是shop)。修改成这样:
def addToCart(self): selected_id = self.data["shop"] if selected_id is not None: self.model.addToCart(selected_id) # 重新加载商品列表,确保界面更新 self.loadContent()
3. 修复SQL注入风险(可选但推荐)
你的ShopDB类中,用字符串拼接SQL语句存在安全隐患,改成参数化查询:
def addToCart(self, product_id): self.db.cursor().execute('''UPDATE products SET in_cart=1 WHERE id=?''', (product_id,)) self.db.commit() def removeFromCart(self, product_id): self.db.cursor().execute('''UPDATE products SET in_cart=0 WHERE id=?''', (product_id,)) self.db.commit()
完整修改后的代码
from asciimatics.widgets import Frame, ListBox, Layout, Divider, Text, \ Button, TextBox, Widget from asciimatics.scene import Scene from asciimatics.screen import Screen from asciimatics.exceptions import ResizeScreenError, NextScene, StopApplication import sys import sqlite3 class ShopDB(object): def __init__(self): # vytvorí databazu v RAM pamati self.db = sqlite3.connect(':memory:') self.db.row_factory = sqlite3.Row self.db.cursor().execute(''' CREATE TABLE products( id INTEGER PRIMARY KEY, product TEXT, price REAL, notes TEXT, in_cart INTEGER) ''') self.db.cursor().execute('''INSERT INTO products(id, product, price, notes, in_cart) VALUES(1, "Mlieko", 0.59, "Veľmi lahodné plnotučné kravské mlieko.",0 )''') self.db.cursor().execute('''INSERT INTO products(id, product, price, notes, in_cart) VALUES(2, "Maslo", 1.59, "Kvalitné maslo priamo z vidieka.",0 )''') self.db.cursor().execute('''INSERT INTO products(id, product, price, notes, in_cart) VALUES(3, "Chlieb", 1.19, "Čerstvý chlieb.",0 )''') self.db.cursor().execute('''INSERT INTO products(id, product, price, notes, in_cart) VALUES(4, "Med", 3.49, "Veľký pohár medu.",0 )''') self.db.cursor().execute('''INSERT INTO products(id, product, price, notes, in_cart) VALUES(5, "Jablko", 0.49, "Zdravé jabĺčko.",0 )''') self.db.cursor().execute('''INSERT INTO products(id, product, price, notes, in_cart) VALUES(6, "Zemiaky 5kg", 0.60, "Vrecko zemiakov.",0 )''') self.db.cursor().execute('''INSERT INTO products(id, product, price, notes, in_cart) VALUES(7, "Šiška", 0.99, "Čerstvá a mäkká šiška.",0 )''') self.db.cursor().execute('''INSERT INTO products(id, product, price, notes, in_cart) VALUES(8, "Soľ", 0.29, "Soľ nad zlato.",0 )''') self.db.cursor().execute('''INSERT INTO products(id, product, price, notes, in_cart) VALUES(9, "Cukor", 1.19, "Kryštálový cukor.",0 )''') self.db.commit() def addToCart(self, product_id): self.db.cursor().execute('''UPDATE products SET in_cart=1 WHERE id=?''', (product_id,)) self.db.commit() def removeFromCart(self, product_id): self.db.cursor().execute('''UPDATE products SET in_cart=0 WHERE id=?''', (product_id,)) self.db.commit() def showAllProducts(self): return self.db.cursor().execute('''SELECT * FROM products''').fetchall() def showCart(self): return self.db.cursor().execute('''SELECT * FROM products WHERE in_cart=1''').fetchall() class Shop(Frame): def __init__(self, screen, db): super(Shop, self).__init__(screen, screen.height * 2 // 3, screen.width * 2 // 3, on_load=self.loadContent, hover_focus=True, title="Obchod ~~ ASCIIMATICO ~~") self.model = db # 格式化ListBox选项为(显示文本, 商品ID) formatted_products = [(f"{row['product']} - {row['price']}€", row['id']) for row in db.showAllProducts()] self.productsList = ListBox(Widget.FILL_FRAME, formatted_products, name="shop") self.addButton = Button("Pridaj do košíka", self.addToCart) #self.deleteButton = Button("Odstráň z košíka", self.deleteFromCart) self.showCartButton = Button("Ukáž košík", self.showCart) listLayout = Layout([100], fill_frame=True) self.add_layout(listLayout) listLayout.add_widget(self.productsList) listLayout.add_widget(Divider()) buttonLayout = Layout([1,1,1,1]) self.add_layout(buttonLayout) buttonLayout.add_widget(self.addButton, 0) buttonLayout.add_widget(self.showCartButton, 3) self.fix() def loadContent(self): # 重新加载时也要格式化选项 formatted_products = [(f"{row['product']} - {row['price']}€", row['id']) for row in self.model.showAllProducts()] self.productsList.options = formatted_products def addToCart(self): selected_id = self.data["shop"] if selected_id is not None: self.model.addToCart(selected_id) # 重新加载商品列表,更新界面 self.loadContent() def showCart(self): self.save() raise NextScene("Cart") #class Cart(Frame): #class ProductDetails(Frame): def demo(screen, scene): scenes = [ Scene([Shop(screen, database)], -1, name="Shop") ] screen.play(scenes, stop_on_resize=True, start_scene=scene) database = ShopDB() last_scene = None while True: try: Screen.wrapper(demo, catch_interrupt=True, arguments=[last_scene]) sys.exit(0) except ResizeScreenError as e: last_scene = e.scene
现在运行代码应该就能正常显示商品列表,并且可以点击按钮添加商品到购物车了。后续你可以继续完善Cart类,用同样的方式处理购物车商品的ListBox选项。
内容的提问来源于stack exchange,提问作者Martin Kumecký
相关产品推荐
相关产品推荐

