Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature request: More powerful filtering of Layouts #1084

Open
bullfest opened this issue Nov 16, 2020 · 3 comments
Open

Feature request: More powerful filtering of Layouts #1084

bullfest opened this issue Nov 16, 2020 · 3 comments

Comments

@bullfest
Copy link

My end goal:

I have a Layout

Layout(
    "field1", 
    "field2", 
    "field3",
    "field4",
)

where I want to wrap all fields in a Field to add an extra css_class to them, as well as wrap one of the fields in a Div, so that the resulting layout would be:

Layout(
    Field("field1", css_class="input-lg"), 
    Field("field2", css_class="input-lg"), 
    Div(Field("field3", css_class="input-lg")),
    Field("field4", css_class="input-lg"), 
)

I've searched for a nice way to do this, but can't seem to find one.

My solution for now is this

self.helper.all().wrap(Field, css_class="input-lg")
field3_index = next(field_tuple[0][0]
    for field_tuple in self.helper.layout.get_field_names()
    if "field3" == field_tuple[1])
self.helper[field3_index].wrap(Div)

which works for this specific case but is something that in my opinion should be easier to do and could .

Feature request:

A way to filter a layout for LayoutObjects with a specific child LayoutObject/field, not too unlike css-selectors maybe?

While not sure how exactly the API would work, to illustrate my idea an API might look something like this in this case:

helper.filter(Field("field3"))

Which i would expect to return a slice with all Field objects containing the field field3.

@cpina
Copy link
Member

cpina commented Dec 9, 2020

I've hardly used filtering in django-crispy-forms (the functionality in https://django-crispy-forms.readthedocs.io/en/latest/dynamic_layouts.html). I think that other people will answer focused on the filtering of layouts and its functionality.

If it helps, in my uses cases I've found it easier to create the layout in the final way that I want with the support of functions. E.g.:

To have this:

Layout(
    Field("field1", css_class="input-lg"), 
    Field("field2", css_class="input-lg"), 
    Div(Field("field3", css_class="input-lg")),
    Field("field4", css_class="input-lg"), 
)

I might have done:

def field_input_lg(name):
    return Field(name, css_class="input-lg")

Layout(
    field_input_lg("field1"),
    field_input_lg("field2"),
    Div(field_input_lg("field3)),
    field_input_lg("field4")
)

Or something along these lines. Would that work for you? It's more "visual" as well. Sometimes I've had wondered which problems really the filtering solves but I haven't looked at the history of the functionality or other use cases.

@smithdc1
Copy link
Member

smithdc1 commented Dec 9, 2020

@cpina should add this approach to the docs / recepies? 🤔

@bullfest
Copy link
Author

bullfest commented Dec 15, 2020

Hi @cpina, not really unfortunately. So I'm using this for a base class for a series of forms that share fields and I want to be formatted similarly (i.e. all fields should receive "input-lg" and a few fields should also be wrapped in another div). I, therefore, don't know what the name of the fields is in the base class.

To expand on my example the classes could be something like this:

class BaseForm(forms.Form):
    f1 = forms.CharField()
    f2 = forms.CharField()
    def __init__(self, *args, **kwargs):
        super().__init__(self, *args, **kwargs)
        self.helper = FormHelper(self)
        ... 
        # Code that sets up the layout 
        # (give all inputs `css_class="input-lg"` and wrap `f2` in `Div(..., css_id="f2")`)

class RealForm(BaseForm):
    f3 = forms.CharField()

...  # more subclasses with other fields

And then I'd expect that the layout of RealForm to be:

Layout(
    Field("f1", css_class="input-lg"),
    Div(Field("f2", css_class="input-lg"), css_id="f2"),
    Field("f3", css_class="input-lg")
)

I guess I could do something along the lines of:

layout = []
for __, field in self.helper.get_field_names():
    if field_name == "f2":
        layout.append(Div(field_input_lg(field), css_id="f2"))
    else:
        layout.append(field_input_lg(field))
Layout(*layout)

Which I believe should preserve the ordering in the layout (I'm assuming that helper.get_field_names() returns the objects in the order they occur in the original layout).
It's not nearly as clean as a potential API with something along the lines of

self.helper.all().wrap(Field, css_class="input-lg")
self.helper.filter(Field("f2")).wrap(Div, css_id="f2")

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants