Get type of Django form widget from within template

前端 未结 6 1485
你的背包
你的背包 2020-12-01 01:27

I\'m iterating through the fields of a form and for certain fields I want a slightly different layout, requiring altered HTML.

To do this accurately, I just need to

相关标签:
6条回答
  • 2020-12-01 01:50

    Following the answer from Oli and rinti: I used this one and I think it is a bit simpler:

    template code: {{ field|fieldtype }}

    filter code:

    from django import template
    register = template.Library()
    
    @register.filter('fieldtype')
    def fieldtype(field):
        return field.field.widget.__class__.__name__
    
    0 讨论(0)
  • 2020-12-01 01:57

    You can make every view that manages forms inherit from a custom generic view where you load into the context the metadata that you need in the templates. The generic form view should include something like this:

    class CustomUpdateView(UpdateView):
        ...
        def get_context_data(self, **kwargs):
           context = super().get_context_data(**kwargs)
           ...
           for f, value in context["form"].fields.items():
              context["form"].fields[f].type = self.model._meta.get_field(f).get_internal_type()
           ...
           return context
    

    In the template you can access these custom properties through field.field:

    {% if field.field.type == 'BooleanField' %}
         <div class="custom-control custom-checkbox">
         ...
         </div>
    {% endif %}
    

    By using the debugger of PyCharm or Visual Studio Code you can see all the available metadata, if you need something else besides the field type.

    0 讨论(0)
  • 2020-12-01 02:02

    Following up on the accepted answer - the enhanced if tag in Django 1.2 allows you to use filters in if tag comparisons. So you could now do your custom html/logic in the template like so:

    <ul>
    {% for field in form.fields %}
      <li>
        {% if field.field.widget|klass == "Textarea" %}
        <!-- do something special for Textarea -->
        <h2>Text Areas are Special </h2>
        {% else %}      
          {{ field.errors }}
          {{ field.label_tag }}
          {{ field }}
        {% endif %}
    
      </li>
    {% endfor %}
    </ul>
    
    0 讨论(0)
  • 2020-12-01 02:03

    Perhaps worth pointing out to contemporary readers that django-widget-tweaks provides field_type and widget_type template filters for this purpose, returning the respective class names in lowercase. In the example below I also show the output of the input_type property on the field widget (since Django 1.11), which may also be useful.

    forms.py:

    class ContactForm(forms.Form):
        name = forms.CharField(
            max_length=150,
            required=True,
            label='Your name'
        )
    

    template.html:

    {% load widget_tweaks %}
    
    {% for field in form.visible_fields %}
    {{ field.label }}
    {{ field.field.widget.input_type }}
    {{ field|field_type }}
    {{ field|widget_type }})
    {% endfor %}
    

    Result:

    Your name
    text
    charfield
    textinput
    

    Between these various options you should be able to find the right property to target for just about any use-case. If you need to capture the output of one of these filters for use in if statements, you can use the with template tag.

    0 讨论(0)
  • 2020-12-01 02:06

    As of Django 1.11, you can just use widget.input_type. Example:

    {% for field in form.visible_fields %}
        <input type="{{ field.field.widget.input_type }}"
               id="{{ field.id_for_label }}"
               name="{{ field.html_name }}"
               placeholder="{{ field.label }}"
               maxlength="{{ field.field.max_length }}" />
    {% endfor %}
    
    0 讨论(0)
  • 2020-12-01 02:09

    Making a template tag might work? Something like field.field.widget|widget_type

    Edit from Oli: Good point! I just wrote a filter:

    from django import template
    register = template.Library()
    
    @register.filter('klass')
    def klass(ob):
        return ob.__class__.__name__
    

    And now {{ object|klass }} renders correctly. Now I've just got to figure out how to use that inside a template's if statement.

    Edit from Oli #2: I needed to use the result of that in an if statetement in-template, so I just shifted all that logic into the templatetag. Magic. Thanks for poking me in the right direction.

    0 讨论(0)
提交回复
热议问题