Python 在Deform/Colander HTML选择字段中处理多对多关系
我在金字塔框架中工作,并使用该包呈现给定colander方案的HTML表单。我正努力思考如何处理具有多对多关系的模式。例如,我的sqlalchemy模型如下所示:Python 在Deform/Colander HTML选择字段中处理多对多关系,python,pyramid,deform,colander,Python,Pyramid,Deform,Colander,我在金字塔框架中工作,并使用该包呈现给定colander方案的HTML表单。我正努力思考如何处理具有多对多关系的模式。例如,我的sqlalchemy模型如下所示: class Product(Base): """ The SQLAlchemy declarative model class for a Product object. """ __tablename__ = 'products' id = Column(Integer, primary_key=True)
class Product(Base):
""" The SQLAlchemy declarative model class for a Product object. """
__tablename__ = 'products'
id = Column(Integer, primary_key=True)
name = Column(String(80), nullable=False)
description = Column(String(2000), nullable=False)
categories = relationship('Category', secondary=product_categories,
backref=backref('categories', lazy='dynamic'))
class Category(Base):
""" The SQLAlchemy declarative model class for a Category object. """
__tablename__ = 'categories'
id = Column(Integer, primary_key=True)
name = Column(String(80), nullable=False)
products = relationship('Product', secondary=product_categories,
backref=backref('products', lazy='dynamic'))
product_categories = Table('product_categories', Base.metadata,
Column('products_id', Integer, ForeignKey('products.id')),
Column('categories_id', Integer, ForeignKey('categories.id'))
)
如您所见,这是一个相当简单的模型,表示一个在线商店,其中的产品可以属于一个或多个类别。在我的呈现形式中,我希望有一个selectmultiple字段,我可以在其中选择几个不同的类别来放置产品。下面是一个简单的colander模式:
def get_category_choices():
all_categories = DBSession.query(Category).all()
choices = []
for category in all_categories:
choices.append((category.id, category.name))
return choices
class ProductForm(colander.Schema):
""" The class which constructs a PropertyForm form for add/edit pages. """
name = colander.SchemaNode(colander.String(), title = "Name",
validator=colander.Length(max=80),
)
description = colander.SchemaNode(colander.String(), title="Description",
validator=colander.Length(max=2000),
widget=deform.widget.TextAreaWidget(rows=10, cols=60),
)
categories = colander.SchemaNode(
colander.Set(),
widget=deform.widget.SelectWidget(values=get_category_choices(), multiple=True),
validator=colander.Length(min=1),
)
而且,可以肯定的是,我确实得到了所有字段的正确渲染,但是,类别字段似乎与任何内容都没有“关联”。如果我编辑一个我知道属于两个类别的产品,我希望选择字段已经突出显示了这两个类别。进行更改(选择第三项)应导致DB更改,其中product_categories针对给定product_id有三行,每行具有不同的category_id。它可能是TMI,但我也使用类似于读/写appstruct的方法
现在,我已经看到(和)使用映射来处理像这样的多对多关系字段,但是没有一个可靠的例子说明如何使用它
提前感谢任何能伸出援手的人。非常感谢。这一次我在左外野,甚至没有问正确区域的正确问题。我真正想要的是在一个多选的colander模式中选择一些默认值。我把我的问题带到谷歌集团,他们能帮我解决。当我在我的产品类中构造appstruct时,它归结为使用“set()”,如下所示:
def appstruct(self):
""" Returns the appstruct model for use with deform. """
appstruct = {}
for k in sorted(self.__dict__):
if k[:4] == "_sa_":
continue
appstruct[k] = self.__dict__[k]
# Special case for the categories
appstruct['categories'] = set([str(c.id) for c in self.categories])
return appstruct
然后,我将其(以及appstruct中的其他项)传递给表单,表单正确呈现HTML,并选择所有类别。若要在提交后应用appstruct,代码最终如下所示:
def apply_appstruct(self, appstruct):
""" Set the product with appstruct from the submitted form. """
for kw, arg in appstruct.items():
if kw == "categories":
categories = []
for id in arg:
categories.append(DBSession.query(Category).filter(Category.id == id).first())
arg = categories
setattr(self, kw, arg)
def get_category_choices():
all_categories = DBSession.query(Category).all()
return [(str(c.id), c.name) for c in all_categories]
categories = get_category_choices()
class ProductForm(colander.Schema):
""" The class which constructs a ProductForm form for add/edit pages. """
name = colander.SchemaNode(colander.String(), title = "Name",
validator=colander.Length(max=80),
)
description = colander.SchemaNode(colander.String(), title="Description",
validator=colander.Length(max=2000),
widget=deform.widget.TextAreaWidget(rows=10, cols=60),
)
categories = colander.SchemaNode(
colander.Set(),
widget=deform.widget.SelectWidget(
values=categories,
multiple=True,
),
validator=colander.Length(min=1),
)
colander模式最终看起来像:
def apply_appstruct(self, appstruct):
""" Set the product with appstruct from the submitted form. """
for kw, arg in appstruct.items():
if kw == "categories":
categories = []
for id in arg:
categories.append(DBSession.query(Category).filter(Category.id == id).first())
arg = categories
setattr(self, kw, arg)
def get_category_choices():
all_categories = DBSession.query(Category).all()
return [(str(c.id), c.name) for c in all_categories]
categories = get_category_choices()
class ProductForm(colander.Schema):
""" The class which constructs a ProductForm form for add/edit pages. """
name = colander.SchemaNode(colander.String(), title = "Name",
validator=colander.Length(max=80),
)
description = colander.SchemaNode(colander.String(), title="Description",
validator=colander.Length(max=2000),
widget=deform.widget.TextAreaWidget(rows=10, cols=60),
)
categories = colander.SchemaNode(
colander.Set(),
widget=deform.widget.SelectWidget(
values=categories,
multiple=True,
),
validator=colander.Length(min=1),
)
谢谢所有看过的人。很抱歉,我问错了问题,没有保持简单。:-) 我深入研究了一下,发现对于初学者来说,“categories”对象甚至不在我的appstruct中,所以我使用以下方法添加了它:
appstruct['categories']=[{'id':c.id,'name':c.name}在self.categories中代表c]
,必须将“selected”属性添加到生成的HTML中,以便选中appstruct中的项:Name 1 Name 2 Name 3,以便选中“Name 1”和“Name 3”。思想?