TurboGears2 - как настроить макет для новой формы пользователя?

В настоящее время я использую это для моей новой формы пользователя:

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 и API 1.0, но ничего не смог найти. Я попытался добавить:

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

но ничего не изменилось. Я предполагаю, что ListForm не имеет field_attrs!? Кто-нибудь может указать мне правильное направление на то, как достичь того, что я ищу?

Большое спасибо!

1 ответ

Решение

Вы можете добавить 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/.

Например, я создал более гибкий класс Layout под названием FloatLayout:

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"

Шаблон Genshi float_layout.html для FloatLayout таков:

<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>

Шаблон Genshi float_form.html для FloatForm выглядит так:

<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_account, new_password иметь атрибут aside что заставляет их появляться в той же строке, что и user_name,

Другие вопросы по тегам