def get_weight(prop): if is_onetoone(prop): return 4 elif is_onetomany(prop): return 3 elif is_manytoone(prop): return 2 elif is_manytomany(prop): return 1 return 0
def required_widget(prop): """Returns bool Returns True if the widget corresponding to the given prop should be required """ is_nullable = lambda prop: sum([c.nullable for c in getattr(prop, 'columns', [])]) if not is_relation(prop): if not is_nullable(prop): return True return False if not is_manytoone(prop) and not is_onetoone(prop): return False localname = compat.local_name(prop) # If the local field is required, the relation should be required pkey = dict([(p.key, is_nullable(p)) for p in prop.parent.iterate_properties]) return not pkey.get(localname, True)
def post_define(cls): if not getattr(cls, 'entity', None) and getattr(cls.parent, 'entity', None): cls.entity = cls.parent.entity if getattr(cls, 'entity', None) and not getattr(cls, '_auto_widgets', False): cls._auto_widgets = True fkey = dict((compat.local_name(p), p) for p in sa.orm.class_mapper(cls.entity).iterate_properties if is_manytoone(p) or is_onetoone(p)) new_children = [] used_children = set() orig_children = getattr(cls.child, 'children', []) mapper = sa.orm.class_mapper(cls.entity) properties = mapper._props.values() localname_from_relationname = dict((p.key, compat.local_name(p)) for p in mapper.iterate_properties if is_manytoone(p) or is_onetoone(p)) localname_creation_order = dict((p.key, p._creation_order) for p in mapper.iterate_properties if not is_relation(p)) properties.sort(sort_properties(localname_from_relationname, localname_creation_order)) reverse_property_name = getattr(cls, 'reverse_property_name', None) for prop in properties: # Swap ids and objs if fkey.get(prop.key): continue if prop.key == reverse_property_name: # Avoid circular loop for the one to one relation continue widget_name = prop.key if isinstance(prop, sa.orm.RelationshipProperty): widget_name = compat.local_name(prop) matches = [w for w in orig_children if w.key == widget_name] widget = len(matches) and matches[0] or None if widget: if not issubclass(widget, NoWidget): new_children.append(widget) used_children.add(widget_name) else: new_widget = cls.policy.factory(prop) if new_widget: new_children.append(new_widget) edit_link = getattr(cls.entity, 'tws_edit_link', None) if cls.policy.add_edit_link and edit_link: new_children += [DbLinkField('edit', text='edit', entity=cls.entity, link=edit_link)] def child_filter(w): return w.key not in used_children and \ w.key not in [W.key for W in new_children] new_children.extend(filter(child_filter, orig_children)) cls.required_children = [] if getattr(cls, 'required_on_parent', False): for c in new_children: if c.validator and c.validator.required: cls.required_children += [c] c.validator.required = False cls.child = cls.child(children=new_children, entity=cls.entity)
def factory(cls, prop): widget = None widget_kw = {} factory_widget = None cols = getattr(prop, 'columns', []) if cls.hint_name: if is_relation(prop): widget = prop.info.get(cls.hint_name) elif cols: widget = cols[0].info.get(cls.hint_name) if widget: if issubclass(widget, NoWidget): # We don't want to display this field! return None if issubclass(widget, FactoryWidget): factory_widget = widget widget = None if widget: pass elif is_onetomany(prop): if not cls.onetomany_widget: raise twc.WidgetError( "Cannot automatically create a widget " + "for one-to-many relation '%s'" % prop.key) prop_cls = prop.mapper.class_ edit_link = getattr(prop_cls, 'tws_edit_link', None) if cls.add_edit_link: widget_kw['link'] = edit_link widget_kw.update({ 'entity': prop_cls, }) widget = cls.onetomany_widget elif sum([c.primary_key for c in getattr(prop, 'columns', [])]): widget = cls.pkey_widget elif is_manytoone(prop): if not cls.manytoone_widget: raise twc.WidgetError( "Cannot automatically create a widget " + "for many-to-one relation '%s'" % prop.key) widget_kw = { 'entity': prop.mapper.class_ } widget = cls.manytoone_widget elif is_manytomany(prop): # Use the same widget as onetomany if not cls.onetomany_widget: raise twc.WidgetError( "Cannot automatically create a widget " + "for many-to-many relation '%s'" % prop.key) prop_cls = prop.mapper.class_ edit_link = getattr(prop_cls, 'tws_edit_link', None) if cls.add_edit_link: widget_kw['link'] = edit_link widget = cls.onetomany_widget widget_kw.update({ 'id': prop.key, 'entity': prop_cls, 'reverse_property_name': get_reverse_property_name(prop), }) elif is_onetoone(prop): if not cls.onetoone_widget: raise twc.WidgetError( "Cannot automatically create a widget " + "for one-to-one relation '%s'" % prop.key) required = required_widget(prop) widget = cls.onetoone_widget widget_kw = { 'id': prop.key, 'entity': prop.mapper.class_, 'required': required, 'reverse_property_name': get_reverse_property_name(prop), 'required_on_parent': (not required), } elif prop.key in cls.name_widgets: widget = cls.name_widgets[prop.key] else: for t, c in product(cls.type_widgets, cols): if isinstance(c.type, t): widget = cls.type_widgets[t] break else: if not cls.default_widget: raise twc.WidgetError( "Cannot automatically create a widget " + "for '%s'" % prop.key) widget = cls.default_widget if widget: widget_kw['id'] = prop.key if factory_widget: for k, v in widget._all_params.items(): value = getattr(factory_widget, k, None) if value and value != v.default: widget_kw[k] = value if 'validator' not in widget_kw and not getattr(widget, 'validator', None) and required_widget(prop): widget_kw['validator'] = twc.Required widget = widget(**widget_kw) return widget