是否有一种简单的方法将表单转换为Deform中的模型,因为pyramid_simpleform中有bind(model)?

时间:2012-11-21 00:06:07

标签: python pyramid deform

pyramid_simpleform says you can use bind(model)可以轻松地将表单的值转换为模型的值:

(以下pyramid_simpleform文档)

def add(self):
  form = Form(request,
              defaults={"name" : "..."},
              schema=MyModelSchema)

  if form.validate():
    obj = form.bind(MyModel())
    # persist model somewhere...
    return HTTPFound(location="/")

  return dict(renderer=FormRenderer(form))

我找不到deform documentation等效方法中的任何地方......或者有没有办法通过变形来做到这一点?

2 个答案:

答案 0 :(得分:4)

Deform不支持​​直接将模式绑定到模型,但如果使用sqlalchemy ColanderAlchemy则完全相同。它从sqlalchemy模型生成漏勺模式(由变形使用),并将表单绑定到模型。

答案 1 :(得分:0)

这是我的150行答案,包括仅查看和编辑表单。对于最简单的用例来说,这可能是不必要的复杂,但是花了一些时间才能让它对我有用。

class FormView:
    """A base class for views which utilize ColanderAlchemy to view/edit SQLAlchemy model instances."""

    #: If the child class is not overriding the rendering loop, point this to a template which provides the page frame and ``crud_content`` block.
    base_template = None

    #: List of SQLAlchemy and JSONProperty field names automatically mapped to a form
    includes = ["id",]

    def __init__(self, context, request):
        self.context = context
        self.request = request

    def create_form(self, buttons=()):
        """Automatically create a read-only collander schema + deform form based on the underlying SQLALchemy model.

        :param buttons: Passed to Deform as form buttons
        """
        obj = self.get_object()
        includes = self.includes
        schema = PropertyAwareSQLAlchemySchemaNode(obj.__class__, includes=includes)
        self.customize_schema(schema)
        schema = self.bind_schema(schema)
        form = deform.Form(schema, buttons=buttons)
        return form

    def bind_schema(self, schema):
        """Initialize Colander field dynamic default values. By default, don't do anything."""
        return schema

    def get_crud(self):
        """Get CRUD manager object for this view."""
        return self.context.__parent__

    def get_object(self):
        """Get underlying SQLAlchemy model instance from current Pyramid traversing context."""
        return self.context.get_object()

    def get_title(self):
        """Get human-readable title for for template page title."""
        return "#{}".format(self.get_object().id)

    def customize_schema(self, schema):
        """After Colander schema is automatically generated from the SQLAlchemy model, edit it in-place for fine-tuning.

        Override this in your view subclass for schema customizations.
        """
        return



class Show(FormView):
    """Read-only view to SQLAlchemy model instance using Deform form generated by ColanderAlchemy.
    """

    def get_title(self):
        return "#{}".format(self.get_object().id)

    @view_config(context=sqlalchemy.Resource, name="show", renderer="crud/show.html", permission='view')
    def show(self):
        """View for showing an individual object."""

        obj = self.context.get_object()
        base_template = self.base_template

        form = self.create_form()
        appstruct = form.schema.dictify(obj)
        rendered_form = form.render(appstruct, readonly=True)

        crud = self.get_crud()

        resource_buttons = dict(edit=self.request.resource_url(self.context, "edit"), delete=False)

        title = current_view_name = self.get_title()

        return dict(form=rendered_form, context=self.context, obj=obj, title=title, crud=crud, base_template=base_template, resource_buttons=resource_buttons)


class Edit(FormView):
    """Edit SQLAlchemy model instance using Deform form generated by ColanderAlchemy.
    """

    # We display id field on the edit form and it needs special handling, because it is read-only
    # See http://deformdemo.repoze.org/readonly_value_nonvalidation/
    includes = [
        colander.SchemaNode(colander.String(),
            name="id",
            missing=lambda node, kw: kw["obj"].id,
            widget=deform.widget.TextInputWidget(readonly=True),
        )
    ]

    def get_title(self):
        return "Editing #{}".format(self.get_object().id)

    def create_form(self):
        return super(Edit, self).create_form(buttons=("save", "cancel",))

    def bind_schema(self, schema):
        return schema.bind(obj=self.context.get_object())

    @view_config(context=sqlalchemy.Resource, name="edit", renderer="crud/edit.html", permission='edit')
    def edit(self):
        """View for showing an individual object."""

        # SQLAlchemy model instance
        obj = self.context.get_object()
        base_template = self.base_template

        # Create form, convert instance to Colander structure for Deform
        form = self.create_form()

        crud = self.get_crud()

        resource_buttons = dict(show=self.request.resource_url(self.context, "show"), delete=False)

        title = current_view_name = self.get_title()

        if "save" in self.request.POST:

            controls = self.request.POST.items()

            try:
                appstruct = form.validate(controls)

                # Cannot update id, as it is read-only
                del appstruct["id"]

                form.schema.objectify(appstruct, obj)

                # We do not need to explicitly call save() or commit() as we are using Zope transaction manager

                messages.add(self.request, kind="success", msg="Changes saved.")

                # Redirect back to view page after edit page has succeeded
                return HTTPFound(self.request.resource_url(self.context, "show"))

            except deform.ValidationFailure as e:
                # Whoops, bad things happened, render form with validation errors
                rendered_form = e.render()

        elif "cancel" in self.request.POST:
            # User pressed cancel
            return HTTPFound(self.request.resource_url(self.context, "show"))
        else:
            # Render initial form view with populated values
            appstruct = form.schema.dictify(obj)
            rendered_form = form.render(appstruct)

        return dict(form=rendered_form, context=self.context, obj=obj, title=title, crud=crud, base_template=base_template, resource_buttons=resource_buttons)