Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

django form dynamic attribute lookup

I'm facing an issue, and can't figure out how to solve it.

I have the following form in my application:

class ContentForm(ModelForm):
    class Meta:
        model = Content
        fields = ('url_1','url_2','url_3','url_4','url_5',)
        widgets = {
            'url_1': forms.URLInput(attrs={'class': 'form-control', 'maxlength': 100}),
            'url_2': forms.URLInput(attrs={'class': 'form-control', 'maxlength': 100}),
            'url_3': forms.URLInput(attrs={'class': 'form-control', 'maxlength': 100}),
            'url_4': forms.URLInput(attrs={'class': 'form-control', 'maxlength': 100}),
            'url_5': forms.URLInput(attrs={'class': 'form-control', 'maxlength': 100}),
        }

What I'm trying to do is to generate those url fields dynamically through a loop. I took this approach (which implements a template tag for dynamic attribute lookup):

{% for i in 12345|make_list %}
    {% with url='url_'|add:i %}
      {{ form|getattribute:url }}
    {% endwith %}
{% endfor %}

However it's not working. Django doesn't render the input field and complains that my form object doesn't have an attribute called url_1 for example. If I call the url_1 attribute for the same form directly it works.

The implementation of the getattribute template tag is the same as here.

[UPDATE: posted my code below]

views.py

@login_required
def new(request):
    form = ContentForm()
    return render(request, "new.html", {'form': form})

new.html

<form action="{% url 'create_content' %}" method="POST">
...
{% include 'partials/urls.html' %}
...
</form>

urls.html

{% load getattribute %}

{% for i in 12345|make_list %}
    {% with url='url_'|add:i %}
      <label>URL {{i}}</label>
      {{ form|getattribute:url }}
    {% endwith %}
{% endfor %}

getattribute.py

import re
from django import template
from django.conf import settings

numeric_test = re.compile("^\d+$")
register = template.Library()

def getattribute(value, arg):
        """Gets an attribute of an object dynamically from a string name"""

        return getattr(value, arg)

    if hasattr(value, str(arg)):
        return getattr(value, arg)
    elif hasattr(value, 'has_key') and value.has_key(arg):
        return value[arg]
    elif numeric_test.match(str(arg)) and len(value) > int(arg):
        return value[int(arg)]
    else:
        return settings.TEMPLATE_STRING_IF_INVALID

register.filter('getattribute', getattribute)

ps.: django version running is 1.9.2

like image 897
Igor Belo Avatar asked Mar 11 '26 20:03

Igor Belo


1 Answers

Change the getattribute.py as below:

import re
from django.forms import Form, ModelForm
from django import template
from django.conf import settings

numeric_test = re.compile("^\d+$")
register = template.Library()

def getattribute(value, arg):
    """Gets an attribute of an object dynamically from a string name"""
    if hasattr(value, str(arg)):
        return getattr(value, arg)
    elif hasattr(value, 'has_key') and value.has_key(arg):
        return value[arg]
    elif numeric_test.match(str(arg)) and len(value) > int(arg):
        return value[int(arg)]
    elif issubclass(value.__class__, (Form, ModelForm)) and arg in value.fields:
        return value[arg]
    else:
        return settings.TEMPLATE_STRING_IF_INVALID

register.filter('getattribute', getattribute)

You can see in 17th and 18th lines that expected for special condition, related to forms and returned related rendered widget ;)

like image 185
M.javid Avatar answered Mar 14 '26 09:03

M.javid