1
<here all loading of static , template_filters, crispy_forms >

<form>
{% for i in artifact_length %}
   {% with artifact_name="artifact"|artifact_name:forloop.counter0 %}
        {{form.artifact_name|as_crispy_field}}
   {% endwith %}
{%endfor%}
</form>

This is related template code. Here i want to render form fields with names artifact_0, artifact_1 as coming from form. The variable artifact_name inside with is working fine and returning expected identifiers artifact_0 , artifact_1, but i want to use these variables as form fields to render as as_crispy_field. The code {{form.artifact_name|as_crispy_field}} does not print anything because it is assuming form as field with name artifact_name which is not. Instead i want to use the value of variable here.

forms.py

  class Someform(forms.form):
    def __init__(self, artifact_obj):
        super().__init__()
        count = 0
        for artifact in artifact_obj:
            self.fields[f'artifact_{count}'] = forms.CharField(widget=forms.NumberInput())
                count += 1
tags.py

@register.filter('artifact_name')
def get_artifact_name(artifact_prefix: str, counter: int):
    print('method', 'prefix', artifact_prefix, 'counter', counter)
    return f'{artifact_prefix}_{counter}'

There is variable length form being created. As informs.py form fields are being created with artifact_count where count can range from 0 to len of obj.

5
  • Are those the only fields in your form and is len(artifact_obj) the same as artifact_length? Commented Nov 27, 2021 at 9:18
  • there are more fields , i could rander them by name. But these are variable fields and cant estimate how much it will be. Need loop to iterate. . Yes, artifact_length is same as artifact_obj. Commented Nov 27, 2021 at 9:20
  • it is being passed in context as {'artifact_length':range(len(artifact_obj))} Commented Nov 27, 2021 at 9:21
  • What about the order you want to render the other fields in? Commented Nov 27, 2021 at 9:21
  • Order does not matter , i just rendered them above all these variable fields. Now need to render these fields too Commented Nov 27, 2021 at 9:21

1 Answer 1

1

You don't need to use filters / template tags, etc. for this purpose. The simplest solution would be to loop over the form fields to render them:

<form>
{% for field in form %}
    {{ field|as_crispy_field }}
{%endfor%}
</form>

This will loop over all the fields in your form.

If you particularly care about the order of these fields you can call the forms order_fields method:

class Someform(forms.form):
    def __init__(self, artifact_obj, *args, **kwargs):
        super().__init__(*args, **kwargs)
        for count, artifact in enumerate(artifact_obj):
            self.fields[f'artifact_{count}'] = forms.CharField(widget=forms.NumberInput())
        self.order_fields(["field_1", "field_2", ...] + [f"artifact_{i}" for i, _ in enumerate(artifact_obj)] + [..., "field_n"])

If you particularly want to render the other fields separately you can add a method to your form that will allow you to loop over these fields:

class Someform(forms.form):
    def __init__(self, artifact_obj, *args, **kwargs):
        super().__init__(*args, **kwargs)
        for count, artifact in enumerate(artifact_obj):
            self.fields[f'artifact_{count}'] = forms.CharField(widget=forms.NumberInput())
        self.artifact_length = len(artifact_obj)
    
    def artifact_fields(self):
        return [self[f'artifact_{i}'] for i in range(self.artifact_length)]

And then loop over these in the template:

<form>
{% for field in form.artifact_fields %}
    {{ field|as_crispy_field }}
{%endfor%}
</form>
Sign up to request clarification or add additional context in comments.

4 Comments

Thanks a lot. It works. I found a workaround by having template tags, filters but that much lengthy. Having addiional method to print artifact is a good idea.
there is one error now . When i submit the form and did this if request.method == 'POST': form = Someform(request.POST) if form.is_valid(): It throw error now, which i could understand as constructor taking artifact_obj and it got request.POST. How to resolve this? Do i need to have args and **kwargs?
@JohnByro see my edit, yes you should use *args, **kwargs. Also you should pass artifact_obj regardless of the request method so Someform(artifact_obj, request.POST)
can you suggest how can we delete the fields dynamically , as we added them in above post.?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.