python - Working with Many to Many Relationships in Deform/Colander HTML Select Field -
i'm working in pyramid framework , using deform package render html forms given colander scheme. i'm struggling head wrapped around how handle schema many many relationship. example, sqlalchemy models this:
class product(base): """ sqlalchemy declarative model class 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): """ sqlalchemy declarative model class 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')) ) as can see, it's pretty simple model representing online store product can belong 1 or more categories. in rendered form, have select multiple field in can choose few different categories in place product into. here's simple colander schema:
def get_category_choices(): all_categories = dbsession.query(category).all() choices = [] category in all_categories: choices.append((category.id, category.name)) return choices class productform(colander.schema): """ class constructs propertyform form 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), ) and, sure enough, proper rendering of fields, however, categories field doesn't seem 'tied' anything. if edit product know belong 2 categories, expect select field have 2 categories highlighted. making change (selecting third item) should result in db change product_categories has 3 rows given product_id, each different category_id. may tmi, i'm using method similar this read/write appstruct.
now, i've seen mention (and again) of using mapping handle many many relationship fields such this, there's not solid example of how use it.
thanks in advance can lend hand. it'd appreciated.
i out in left field on one, not asking right question right area. after have defaults selected in multi-select colander schemanode. brought question on pylons-discuss google group, , able me out. came down using 'set()' when construct appstruct in product class below:
def appstruct(self): """ returns appstruct model use deform. """ appstruct = {} k in sorted(self.__dict__): if k[:4] == "_sa_": continue appstruct[k] = self.__dict__[k] # special case categories appstruct['categories'] = set([str(c.id) c in self.categories]) return appstruct then, passed (along other items in appstruct) along form , rendered html properly, categories selected. apply appstruct after submitting, code ended looking like:
def apply_appstruct(self, appstruct): """ set product appstruct submitted form. """ kw, arg in appstruct.items(): if kw == "categories": categories = [] id in arg: categories.append(dbsession.query(category).filter(category.id == id).first()) arg = categories setattr(self, kw, arg) the colander schema ended looking like:
def get_category_choices(): all_categories = dbsession.query(category).all() return [(str(c.id), c.name) c in all_categories] categories = get_category_choices() class productform(colander.schema): """ class constructs productform form 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), ) thanks looked. apologies asking wrong questions , not keeping simple. :-)
Comments
Post a Comment