TurboGears2 - 如何为新用户表单自定义布局?

时间:2013-07-18 14:45:49

标签: python forms web-frameworks turbogears2 toscawidgets

我目前正在将此用于我的新用户表单:

class UserForm(AdminPage):
    entity = Model.User
    title = 'User'
    class child(ListForm):
        css_class = 'form-horizontal'
        buttons = [SaveButton(),CancelButton()]
        ...
        phone = TextField(
                label = 'Phone',
                validator = twc.Required
        )
        ...

我假设我必须使用除ListForm以外的其他东西来做我想要的事情。这就是我需要的:

我想自定义某些表单字段的长度,将两个表单字段放在一起而不是下面,并将这两个字段上的标签更改为显示在字段上方而不是左侧。

我花了几个小时浏览不同版本的tg docs和1.0 API,但我找不到任何有用的东西。我尝试添加:

__field_attrs__={'phone':{'rows':'2'}}

但没有改变。我假设ListForm没有 field_attrs !?任何人都可以指出我如何实现我正在寻找的正确方向吗?

非常感谢!

1 个答案:

答案 0 :(得分:2)

您可以在字段中添加CSS类和样式,如下所示:

phone = TextField(label='Phone',
                  validator=twc.Required,
                  css_class='MyTextFieldClass',
                  attrs=dict(style='display:block;width:8em', maxlength='12'))

对于完全不同的布局,您需要子类化BaseLayout并引用您自己的模板,如下所述:http://tw2core.readthedocs.org/en/latest/design/#template

例如,我创建了一个名为FloatLayout的更灵活的Layout类:

from itertools import groupby
from tw2.core import Param
from tw2.forms.widgets import BaseLayout

class FloatLayout(BaseLayout):

    template = "widgets.templates.float_layout"

    aside = Param('All fields aside', default=False)

    def rows(self, children):
        """Create the rows."""
        def row_no(child, no=[0]):
            if not self.aside and not getattr(child, 'aside', False):
                no[0] += 1
            return no[0]
        return groupby(children, row_no)

它可以与此FloatForm类一起使用:

from tw2.core import Variable
from tw2.forms import Form

class FloatForm(Form):
    """Form using floating divisions allowing multiple fields per row.

    Fields having the 'aside' attribute set appear on the same row.

    Something like the following should be included in the site CSS file:

    form.floatform {
        margin-bottom: 1ex;
    }
    form.floatform div.row {
        clear: left;
        overflow: hidden;
        height: 100%;
        margin-top: 1.5ex;
    }
    form.floatform div.field {
        float: left;
        margin-right: 1em;
    }
    form.floatform label.fieldlabel {
        display: block;
    }
    form.floatform div.submit {
        margin-top: 3ex;
    }

    """

    template = "widgets.templates.float_form"

    child = Variable(default=FloatLayout)

    css_class = "floatform"

FloatLayout的Genshi模板float_layout.html是:

<div xmlns:py="http://genshi.edgewall.org/" py:attrs="w.attrs" py:strip="True">
    <div py:for="row_no, row in w.rows(w.children_non_hidden)"
            class="${row_no % 2 and 'odd' or 'even'} row">
        <div py:for="child in row" py:attrs="child.container_attrs"
            class="field${child.validator and
                getattr(child.validator, 'required', None) and ' required' or ''}"
            title="${w.hover_help and w.help_text or ''}">
            <label py:if="child.label" for="${child.attrs.get('id')}"
                class="fieldlabel" py:content="child.label"/>
            <span py:replace="child.display()"/>
            <span py:if="not w.hover_help and child.help_text"
                class="fieldhelp" py:content="child.help_text"/>
            <span py:if="child.error_msg"
                class="fielderror" py:content="child.error_msg"/>
        </div>
    </div>
    <div py:if="w.children_hidden" style="display:none">
        <div py:for="child in w.children_hidden" py:replace="child.display()"/>
    </div>
</div>

FloatForm的Genshi模板float_form.html是:

<form xmlns:py="http://genshi.edgewall.org/"
    class="floatform" py:attrs="w.attrs">
    <div py:if="w.error_msg" class="formerror" py:content="w.error_msg"/>
    <div py:if="w.help_msg" class="formhelp"><p py:content="w.help_msg"/></div>
    <div py:replace="w.child.display()"/>
    <div py:for="button in w.buttons" class="field" py:content="button.display()"/>
</form>

具体表单现在看起来像这样:

class UserForm(FloatForm):
    action = url('save_user')
    submit = SubmitButton('Save user')
    user_id = HiddenField(validator=IntValidator())
    user_name = TextField(validator=UserNameValidator(max=16),
        size=20, maxlength=16, label=u'User name:')
    remote_account = CheckBox(validator=BoolValidator(),
        label=u'Remote account:', aside=True)
    new_password = PasswordField(
        validator=PasswordValidator(required=False),
        size=20, maxlength=16, label=u'Password:', aside=True)
    group_id = CheckBoxList(item_validator=IntValidator(),
        label=u'Roles:', css_class='inline')
    display_name = TextField(validator=NameValidator(max=255),
        size=64, maxlength=255, label=u'Real name:')
    mail = TextField(validator=EmailIfLocalValidator(),
        size=64, maxlength=255, label=u'Email address:')

如您所见,字段remote_accountnew_password具有属性aside,这使得它们与user_name显示在同一行。