Nov 22, 2011

готовим Pylons + WTForms

WTForm простая, но довольно удобная библиотека для создания форм. И еще WTForm очень похожа на формы в Django - одно из немногого что в джанге сделано хорошо. Посмотрим как это работает с Pylons. Для удобства будем хранить формы отдельно:

|+config/
|+controllers/
|~forms/
| |~mycontroller/
| | |-__init__.py
| | `-equipments.py
| |+validators/
| `-__init__.py

Создаем форму для редактирования оборудования equipments.py:

equipments.py
from myapp.model.meta import Session as s
from myapp.model.mymodel import EquipmentType
from wtforms import Form, TextField, validators
from wtforms.ext.sqlalchemy.fields import QuerySelectField

# Выбор всех разновидностей оборудования для списка type в форме
def all_equipment_types():
    return s.query(EquipmentType).all()

class EditForm(Form):
    ip = TextField('ip address')
    netmask = TextField('network mask')
    mac = TextField('mac address')
    type = QuerySelectField('type of equipment',
                            query_factory=all_equipment_types)

QuerySelectField это поле из расширения WTForm для SQLAlchemy, которое позволяет создавать списки на основе выборок. Также есть расширения для Django и GAE. Инициализируем нашу форму в контроллере и передадим шаблону:

from myapp.forms.mycontroller.equipments import EditForm

class EquipmentsController(BaseController):
    ...
    def edit(self, id, format='html'):
        """GET /myapp/equipments/id/edit: Form to edit an existing item"""
        # url('myapp_edit_equipment', id=ID)
        c.equipment = s.query(Equipment).filter(id==id)
        c.form = EditForm(ip=c.equipment.ip, mac=c.equipment.mac,
                        type=c.equipment.equipmenttype,
                        netmask=c.equipment.netmask)

        return render('/myapp/equipments/edit.html')

После передачи одноименных полям параметров в форму, значения этих параметров будут по умолчанию выведены в форме. Напишем шаблон на Jinja:

{% extends "base.html" %}

{% block content %}
   <form action="{{ url(controller='myapp/equipments', action='update', id=c.equipment.id) }}" method="POST">
      <table class="simpletable">
         <caption>
            Edit equipment of {{ c.equipment.equipmenttype }}
             ({{ c.equipment.ip }})
         </caption>
         <tbody>
            {% for field in c.form.data %}
               <tr><td>{{ c.form[field].label }}</td>
                   <td>{{ c.form[field] }}</td>
               </tr>
            {% endfor %}
            <tr><td colspan="5">
            <button><img src="/img/common/save.png" />Save</button>
            <input type="hidden" name="_method" value="PUT" />
            </td></tr>
         </tbody>
      </table>
   </form>
{% endblock %}

В примере поля выводятся в цикле из списка form.data. Я использую REST контроллеры поэтому обновление происходит в методе update:

from myapp.forms.mycontroller.equipments import EditForm

class EquipmentsController(BaseController):
    ...
    def update(self, id):
        """PUT /myapp/equipments/id: Update an existing item"""
        # Forms posted to this method should contain a hidden field:
        #    <input name="_method" value="PUT" type="hidden">
        # Or using helpers:
        #    h.form(url('myapp_equipment', id=ID),
        #           method='put')
        # url('myapp_equipment', id=ID)
        equipment = s.query(Equipment).filter(id=id)
        if request.POST['ip']:
            equipment.ip = request.POST['ip']
        if request.POST['netmask']:
            equipment.netmask = request.POST['netmask']
        if request.POST['mac']:
            equipment.mac = request.POST['mac']
        type = EquipmentType.by_id(request.POST['type'])
        equipment.equipmenttype = type
        s.commit()

        came_from = str(request.environ.get('HTTP_REFERER', '')) or url('/')

        redirect(came_from)

Последние две строки возвращают пользователя обратно на страницу редактирования. Выглядит это как-то так:

../../../_images/wtform_eq.png

Пример WTForm и Pylons


Comments

comments powered by Disqus