Search code examples
pythonsqlalchemypyramid

SQLAlchemy / WTForms - QuerySelectField


I'm using WTForms with the SQLAlchemy extension on a Pyramid application.

My session is:

from zope.sqlalchemy import ZopeTransactionExtension

DBSession = scoped_session(sessionmaker(extension=ZopeTransactionExtension()))
Base = declarative_base()

My model is:

class Client(Base):
    __tablename__ = 'client'
    id = Column(Integer, primary_key=True, nullable=False)
    name = Column(Unicode(48))
    street = Column(Unicode(48))
    city = Column(Unicode(32))
    task = relationship("Task", backref="client")

    @classmethod
    def active(cls):
         return DBSession.query(Client).options(load_only("id", "name")).order_by(sa.desc(Client.name)).filter(Client.status == True)


class Task(Base):
    __tablename__ = 'task'
    id = Column(Integer, primary_key=True, nullable=False)
    name = Column(String(48))
    status = Column(Boolean)
    client_id = Column(Integer, ForeignKey('client.id'))

My form is:

def enabled_client():
     return Client.active()

class TaskCreateForm(ModelForm):
    name = TextField('Task name', [validators.Length(min=1, max=48)], filters=[strip_filter])
    status = BooleanField('Status')
    client_id = QuerySelectField('Client', query_factory=enabled_client, get_label='name', allow_blank=False)

My view is:

@view_config(route_name='task_action', match_param='action=create', renderer='arx:templates/task_edit.mako', permission='edit')
def task_create(request):
    task = Task()
    form = TaskCreateForm(request.POST)
    if request.method == 'POST' and form.validate():
        form.populate_obj(task)
        DBSession.add(task)
        return HTTPFound(location=request.route_url('home'))
    return {'form':form, 'action':request.matchdict.get('action')}

Form displays select box with proper Client names but the problem emerges when I'm trying to submit form. WTForm should use real ID of Client but it passes SQLAlchemy object eg:

   <arx.models.Client object at 0x7fdfb139ddd0>

What am I doing wrong?


Solution

  • My form was too specific (it should be client instead of client_id), so my working code looks like this:

    Session:

    from zope.sqlalchemy import ZopeTransactionExtension
    
    DBSession = scoped_session(sessionmaker(extension=ZopeTransactionExtension()))
    Base = declarative_base()
    

    Model:

    class Client(Base):
         __tablename__ = 'client'
         id = Column(Integer, primary_key=True, nullable=False)
         name = Column(Unicode(48))
         street = Column(Unicode(48))
         city = Column(Unicode(32))
         task = relationship("Task", backref="client")
    
        @classmethod
        def active(cls):
            return DBSession.query(Client).options(load_only("id", "name")).order_by(sa.desc(Client.name)).filter(Client.status == True)
    
    
    class Task(Base):
        __tablename__ = 'task'
        id = Column(Integer, primary_key=True, nullable=False)
        name = Column(String(48))
        status = Column(Boolean)
        client_id = Column(Integer, ForeignKey('client.id'))
    

    Form:

    def enabled_client():
        return Client.active()
    
    class TaskCreateForm(ModelForm):
        name = TextField('Task name', [validators.Length(min=1, max=48)], filters=[strip_filter])
        status = BooleanField('Status')
        client = QuerySelectField('Client', query_factory=enabled_client, get_label='name', allow_blank=False)
    

    View:

    @view_config(route_name='task_action', match_param='action=create', renderer='arx:templates/task_edit.mako', permission='edit')
    def task_create(request):
        task = Task()
        form = TaskCreateForm(request.POST)
        if request.method == 'POST' and form.validate():
            form.populate_obj(task)
            DBSession.add(task)
            return HTTPFound(location=request.route_url('home'))
        return {'form':form, 'action':request.matchdict.get('action')}