def contribute_inline(model, form_class, inline_models): # Contribute columns for p in inline_models: # Figure out settings if isinstance(p, tuple): info = InlineFormAdmin(p[0], **p[1]) elif isinstance(p, InlineFormAdmin): info = p elif isinstance(p, BaseModel): info = InlineFormAdmin(p) else: raise Exception('Unknown inline model admin: %s' % repr(p)) # Find property from target model to current model reverse_field = None for field in info.model._meta.get_fields(): field_type = type(field) if field_type == ForeignKeyField: if field.to == model: reverse_field = field break else: raise Exception('Cannot find reverse relation for model %s' % info.model) # Remove reverse property from the list ignore = [reverse_field.name] if info.excluded_form_columns: exclude = ignore + info.excluded_form_columns else: exclude = ignore # Create field converter = CustomModelConverter() child_form = model_form(info.model, base_class=form.BaseForm, only=info.form_columns, exclude=exclude, field_args=info.form_args, allow_pk=True, converter=converter) prop_name = 'fa_%s' % model.__name__ setattr( form_class, prop_name, InlineModelFormList(child_form, info.model, reverse_field.name, label=info.model.__name__)) setattr(field.to, prop_name, property(lambda self: self.id)) return form_class
def get_info(self, p): info = super(InlineModelConverter, self).get_info(p) if info is None: if isinstance(p, BaseModel): info = InlineFormAdmin(p) else: model = getattr(p, 'model', None) if model is None: raise Exception('Unknown inline model admin: %s' % repr(p)) attrs = dict() for attr in dir(p): if not attr.startswith('_') and attr != model: attrs[attr] = getattr(p, attr) info = InlineFormAdmin(model, **attrs) return info
def get_info(self, p): info = super(InlineModelConverter, self).get_info(p) if info is None: if isinstance(p, BaseModel): info = InlineFormAdmin(p) else: model = getattr(p, 'model', None) if model is None: raise Exception('Unknown inline model admin: %s' % repr(p)) attrs = dict() for attr in dir(p): if not attr.startswith('_') and attr != 'model': attrs[attr] = getattr(p, attr) info = InlineFormAdmin(model, **attrs) # Resolve AJAX FKs info._form_ajax_refs = self.process_ajax_refs(info) return info
def get_info(self, p): info = super(InlineModelConverter, self).get_info(p) # Special case for model instances if info is None: if hasattr(p, '_sa_class_manager'): return InlineFormAdmin(p) else: model = getattr(p, 'model', None) if model is None: raise Exception('Unknown inline model admin: %s' % repr(p)) attrs = dict() for attr in dir(p): if not attr.startswith('_') and attr != 'model': attrs[attr] = getattr(p, attr) return InlineFormAdmin(model, **attrs) info = InlineFormAdmin(model, **attrs) return info
def contribute_inline(session, model, form_class, inline_models): """ Generate form fields for inline forms and contribute them to the `form_class` :param session: SQLAlchemy session :param model: Model class :param form_class: Form to add properties to :param inline_models: List of inline model definitions. Can be one of: - ``tuple``, first value is related model instance, second is dictionary with options - ``InlineFormAdmin`` instance - Model class :return: Form class """ # Get mapper mapper = model._sa_class_manager.mapper # Contribute columns for p in inline_models: # Figure out settings if isinstance(p, tuple): info = InlineFormAdmin(p[0], **p[1]) elif isinstance(p, InlineFormAdmin): info = p elif hasattr(p, '_sa_class_manager'): info = InlineFormAdmin(p) else: raise Exception('Unknown inline model admin: %s' % repr(p)) # Find property from target model to current model target_mapper = info.model._sa_class_manager.mapper reverse_prop = None for prop in target_mapper.iterate_properties: if hasattr(prop, 'direction') and prop.direction.name == 'MANYTOONE': if prop.mapper.class_ == model: reverse_prop = prop break else: raise Exception('Cannot find reverse relation for model %s' % info.model) # Find forward property forward_prop = None for prop in mapper.iterate_properties: if hasattr(prop, 'direction') and prop.direction.name == 'ONETOMANY': if prop.mapper.class_ == target_mapper.class_: forward_prop = prop break else: raise Exception('Cannot find forward relation for model %s' % info.model) # Remove reverse property from the list ignore = [reverse_prop.key] if info.excluded_form_columns: exclude = ignore + info.excluded_form_columns else: exclude = ignore # Create field converter = AdminModelConverter(session, info) child_form = get_form(info.model, converter, only=info.form_columns, exclude=exclude, field_args=info.form_args, hidden_pk=True) setattr( form_class, forward_prop.key, InlineModelFormList(child_form, session, info.model, forward_prop.key)) return form_class