Example #1
0
 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
Example #2
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)
Example #3
0
    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)
Example #4
0
    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