{"id":1041,"date":"2010-11-08T03:51:16","date_gmt":"2010-11-08T07:51:16","guid":{"rendered":"http:\/\/cd34.com\/blog\/?p=1041"},"modified":"2010-11-08T17:28:36","modified_gmt":"2010-11-08T21:28:36","slug":"using-pyramid-with-deform-to-editcreate-records-in-sqlalchemy-backed-database","status":"publish","type":"post","link":"https:\/\/cd34.com\/blog\/framework\/using-pyramid-with-deform-to-editcreate-records-in-sqlalchemy-backed-database\/","title":{"rendered":"Using Pyramid with Deform to Edit\/Create records in SQLAlchemy backed database"},"content":{"rendered":"<p>While working with Pyramid it was worth taking a good look at <a href=\"http:\/\/docs.repoze.org\/deform\/\">deform<\/a>.  During my brief look before, the one thing that appeared to be missing was a method to quickly integrate with SQLAlchemy backed data.  For a handful of forms, manually creating the appstruct to be passed to the Form wouldn&#8217;t be difficult, but, for some more significant applications, it could be quite cumbersome.  The following is a one page application that allows you to create a new user, or, edit an existing user by specifying the userid in the URL.  The two pieces that do the real work are <strong>record_to_appstruct<\/strong> and <strong>merge_session_with_post<\/strong>.  record_to_appstruct takes the class returned from SQLAlchemy and converts it to an appstruct that deform likes.  Once we get the validated data, we merge the record with the post items using merge_session_with_post, merge the record and present a screen with the post data.<\/p>\n<p>This is more a proof of concept, but, works well enough that we were able to convert quite a few forms and work more closely with Deform and Pyramid as we do more development.<\/p>\n<p><strong>__init.py__:<\/strong><\/p>\n<pre>\r\n\r\nfrom pyramid.configuration import Configurator\r\nfrom paste.deploy.converters import asbool\r\n\r\nfrom defo.models import initialize_sql\r\n\r\ndef app(global_config, **settings):\r\n    \"\"\" This function returns a WSGI application.\r\n    \r\n    It is usually called by the PasteDeploy framework during \r\n    ``paster serve``.\r\n    \"\"\"\r\n    db_string = settings.get('db_string')\r\n    if db_string is None:\r\n        raise ValueError(\"No 'db_string' value in application configuration.\")\r\n    db_echo = settings.get('db_echo', 'false')\r\n    initialize_sql(db_string, asbool(db_echo))\r\n    config = Configurator(settings=settings)\r\n    config.begin()\r\n    config.add_static_view('static', 'defo:static')\r\n    config.add_route('home', '\/', view='defo.views.edit',\r\n                     view_renderer='test.mako')\r\n    config.add_route('homeid', '\/:id', view='defo.views.edit',\r\n                     view_renderer='test.mako')\r\n    config.end()\r\n    return config.make_wsgi_app()\r\n<\/pre>\n<p><strong>views.py:<\/strong><\/p>\n<pre>\r\nfrom defo.models import DBSession\r\nfrom defo.models import MyModel\r\n\r\nfrom sqlalchemy.ext.declarative import declarative_base\r\nBase = declarative_base()\r\n\r\nfrom sqlalchemy import *\r\nfrom sqlalchemy.databases import mysql\r\nfrom sqlalchemy.orm import relation, backref, synonym\r\nfrom sqlalchemy.orm.exc import NoResultFound\r\n\r\nimport deform\r\nimport colander\r\nfrom webhelpers import constants\r\n\r\nclass UserSchema(colander.Schema):\r\n    username = colander.SchemaNode(colander.String())\r\n    contact = colander.SchemaNode(colander.String())\r\n    email = colander.SchemaNode(colander.String())\r\n    company = colander.SchemaNode(colander.String())\r\n    addr1 = colander.SchemaNode(colander.String())\r\n    addr2 = colander.SchemaNode(colander.String(), missing=u'',)\r\n    city = colander.SchemaNode(colander.String())\r\n    state = colander.SchemaNode(colander.String())\r\n    zip = colander.SchemaNode(colander.String())\r\n    country = colander.SchemaNode(\r\n        colander.String(),\r\n        widget = deform.widget.SelectWidget(values=constants.country_codes()),\r\n    )\r\n    phone = colander.SchemaNode(colander.String())\r\n\r\nclass AuthUser(Base):\r\n    __tablename__ = 'auth_users'\r\n\r\n    id = Column(mysql.BIGINT(20, unsigned=True), primary_key=True, autoincrement=True)\r\n    username = Column(Unicode(80), nullable=False)\r\n    email = Column(Unicode(80), nullable=False)\r\n    contact = Column(Unicode(80), nullable=False)\r\n    company = Column(Unicode(80), nullable=False)\r\n    addr1 = Column(Unicode(80), nullable=False)\r\n    addr2 = Column(Unicode(80))\r\n    city = Column(Unicode(80), nullable=False)\r\n    state = Column(Unicode(80), nullable=False)\r\n    zip = Column(Unicode(80), nullable=False)\r\n    country = Column(Unicode(80), nullable=False)\r\n    phone = Column(Unicode(80), nullable=False)\r\n\r\ndef record_to_appstruct(self):\r\n    return dict([(k, self.__dict__[k]) for k in sorted(self.__dict__) if '_sa_' != k[:4]])\r\n\r\ndef merge_session_with_post(session, post):\r\n    for key,value in post:\r\n        setattr(session, key, value)\r\n    return session\r\n\r\ndef edit(request):\r\n    dbsession = DBSession()\r\n    if request.matchdict.has_key('id'):\r\n        record = dbsession.query(AuthUser). \\\r\n                 filter_by(id=request.matchdict['id']).first()\r\n    else:\r\n        record = AuthUser()\r\n\r\n    schema = UserSchema()\r\n    form = deform.Form(schema, buttons=('submit',))\r\n    if request.POST:\r\n        try:\r\n            appstruct = form.validate(request.POST.items())\r\n        except deform.ValidationFailure, e:\r\n            return {'form':e.render()}\r\n        record = merge_session_with_post(record, request.POST.items())\r\n        dbsession.merge(record)\r\n        dbsession.flush()\r\n        return {'formdata':appstruct}\r\n    else:\r\n        appstruct = record_to_appstruct(record)\r\n    return {'form':form.render(appstruct=appstruct)}\r\n<\/pre>\n<p><strong>test.mako:<\/strong><\/p>\n<pre>\r\n&lt;html>\r\n&lt;head>\r\n  &lt;title>\r\n    Deform Demo Site\r\n  &lt;\/title>\r\n  &lt;!-- Meta Tags -->\r\n  &lt;meta http-equiv=\"Content-Type\" content=\"text\/html; charset=utf-8\" \/>\r\n  &lt;!-- CSS -->\r\n  &lt;link rel=\"stylesheet\" href=\"\/static\/css\/form.css\" type=\"text\/css\" \/>\r\n  &lt;link rel=\"stylesheet\" href=\"\/static\/css\/theme.css\" type=\"text\/css\" \/>\r\n  &lt;!-- JavaScript -->\r\n  &lt;script type=\"text\/javascript\"\r\n          src=\"\/static\/scripts\/jquery-1.4.2.min.js\">&lt;\/script>\r\n  &lt;script type=\"text\/javascript\"\r\n          src=\"\/static\/scripts\/deform.js\">&lt;\/script>\r\n&lt;\/head>\r\n&lt;body>\r\nthis is a test template in mako\r\n&lt;p>\r\n% if form:\r\n  ${form|n}\r\n% else:\r\nWe got our form data: ${formdata}\r\n% endif\r\n&lt;script type=\"text\/javascript\">\r\n   deform.load()\r\n&lt;\/script>\r\n&lt;\/body>\r\n&lt;\/html>\r\n<\/pre>\n<div style=\"float:left;\">\n<div id=\"fb-root\"><\/div>\n<fb:like href=\"https:\/\/cd34.com\/blog\/framework\/using-pyramid-with-deform-to-editcreate-records-in-sqlalchemy-backed-database\/\" width=\"250\" send=\"false\" show_faces=\"false\" layout=\"button_count\" action=\"recommend\"><\/fb:like>\n<\/div><div style=\"clear:both;\"><\/div>","protected":false},"excerpt":{"rendered":"<p>While working with Pyramid it was worth taking a good look at deform. During my brief look before, the one thing that appeared to be missing was a method to quickly integrate with SQLAlchemy backed data. For a handful of forms, manually creating the appstruct to be passed to the Form wouldn&#8217;t be difficult, but, [&hellip;]<\/p>\n<div style=\"float:left;\">\n<div id=\"fb-root\"><\/div>\n<fb:like href=\"https:\/\/cd34.com\/blog\/framework\/using-pyramid-with-deform-to-editcreate-records-in-sqlalchemy-backed-database\/\" width=\"250\" send=\"false\" show_faces=\"false\" layout=\"button_count\" action=\"recommend\"><\/fb:like>\n<\/div><div style=\"clear:both;\"><\/div>","protected":false},"author":15,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[6],"tags":[149,148,147,49],"class_list":["post-1041","post","type-post","status-publish","format-standard","hentry","category-framework","tag-deform","tag-pyramid","tag-repoze","tag-sqlalchemy"],"_links":{"self":[{"href":"https:\/\/cd34.com\/blog\/wp-json\/wp\/v2\/posts\/1041","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/cd34.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/cd34.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/cd34.com\/blog\/wp-json\/wp\/v2\/users\/15"}],"replies":[{"embeddable":true,"href":"https:\/\/cd34.com\/blog\/wp-json\/wp\/v2\/comments?post=1041"}],"version-history":[{"count":2,"href":"https:\/\/cd34.com\/blog\/wp-json\/wp\/v2\/posts\/1041\/revisions"}],"predecessor-version":[{"id":1043,"href":"https:\/\/cd34.com\/blog\/wp-json\/wp\/v2\/posts\/1041\/revisions\/1043"}],"wp:attachment":[{"href":"https:\/\/cd34.com\/blog\/wp-json\/wp\/v2\/media?parent=1041"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/cd34.com\/blog\/wp-json\/wp\/v2\/categories?post=1041"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/cd34.com\/blog\/wp-json\/wp\/v2\/tags?post=1041"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}