Question

Using django-crispy-forms I want to combine two (or more) widgets on a single row. See also the attached example. I think it should be possible using that library, although the documentation does include examples on this issue and the source code didn't help either. So has anyone managed to get similar results using django-crispy-forms?

Example controls-row

The HTML required for such a form looks like this:

<div class="control-group">
    <label for="desc" class="control-label">
        Description
    </label>
    <div class="controls controls-row">
        <input class="span2" maxlength="255" type="text" id="desc">
        <input class="span3" maxlength="255" type="text">
    </div>
</div>
Was it helpful?

Solution 2

You could do it with defining HTML object in `def init(self, *args, **kwargs): in layout object. This HTML will give you all the freedom you want for your needs.

There is another way too. To actually make your own template in in your templates folder and then in your layout object define the path to that template Example:

Field('name', template='path/to/template/single_line_input.html'),

Where 'name' is actually a widget.

Of course you could always try to do it with playing around in the CSS files for your app, something like float: left or display: inline might help, but you would have to define the classes on the widgets which should be displayed inline. This could be a bit tricky for someone who is not skilled in frontend CSS (for result could be various in different browsers and on different resolutions, so needless to say some testing is needed). The problem you have is mainly the fact that browsers are rendering input fields as block objects by default, so they take up all the space in one line even if their width is less.

OTHER TIPS

Yes. Use Layouts

Here's an example snippet to get you going.

def __init__(self, *args, **kwargs):
    self.helper = FormHelper()
    self.helper.form_method = 'get'
    self.helper.form_id = 'id_search'
    self.helper.layout = Layout(
            Div(
                Div(Field('arrival_date', css_class='span12 input-large calendar',
                    placeholder='dd/mm/yyyy'), css_class='span5'),
                Div(Field('departure_date', css_class='span12 input-large calendar',
                    placeholder='dd/mm/yyyy'), css_class='span5'),
                Div(Field('rooms', css_class='span12'), css_class='span2 styled-rooms'),
                css_class='row-fluid',
            ),
        )

You can use MultiValueField and MultiWidget to get this behavior. You'll need to think about and modify the compress and decompress methods, but something like the following should get you part way there.

from django import forms
from crispy_forms.helper import FormHelper

class MyWidget(forms.MultiWidget):
    widgets = (forms.TextInput(), forms.TextInput())
    super(ExpirationDateWidget, self).__init__(widgets)

    def decompress(self, value):
        if value:
            return value.split('|')  # or however you combined the two values
        return [None, None]


class MyMultiField(forms.MultiValueField):
    def __init__(self, *args, **kwargs):
        self.widget = MyWidget(*args, **kwargs)

    def compress(self, data_list):
        return data_list[0] + '|' + data_list[1]  # or other logical compression


class MyForm(forms.Form):
    multi_field = MyMultiField()
    # other fields like category and category_new

    def __init__(self, *args, **kwargs):
        self.helper = FormHelper()
        self.helper.form_class = 'form-horizontal'
        self.helper.layout = Layout('multi_field', 'category', 'category_new')

This will result in something like:

 <div id="div_id_multi_field" class="control-group">
     <label for="id_multi_field_0" class="control-label">Multi Field</label>
     <div class="controls">
         <input id="id_multi_field_0">
         <input id="id_multi_field_1">
     </div>
 </div>
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top