Giter Site home page Giter Site logo

django-widget-tweaks's Introduction

django-widget-tweaks

Jazzband

PyPI Version

GitHub Actions

Coverage

Tweak the form field rendering in templates, not in python-level form definitions. Altering CSS classes and HTML attributes is supported.

That should be enough for designers to customize field presentation (using CSS and unobtrusive javascript) without touching python code.

License is MIT.

Installation

You can get Django Widget Tweaks by using pip:

$ pip install django-widget-tweaks

To enable widget_tweaks in your project you need to add it to INSTALLED_APPS in your projects settings.py file:

INSTALLED_APPS += [
    'widget_tweaks',
]

Usage

This app provides two sets of tools that may be used together or standalone:

  1. a render_field template tag for customizing form fields by using an HTML-like syntax.
  2. several template filters for customizing form field HTML attributes and CSS classes

The render_field tag should be easier to use and should make form field customizations much easier for designers and front-end developers.

The template filters are more powerful than the render_field tag, but they use a more complex and less HTML-like syntax.

render_field

This is a template tag that can be used as an alternative to aforementioned filters. This template tag renders a field using a syntax similar to plain HTML attributes.

Example:

{% load widget_tweaks %}

<!-- change input type (e.g. to HTML5) -->
{% render_field form.search_query type="search" %}

<!-- add/change several attributes -->
{% render_field form.text rows="20" cols="20" title="Hello, world!" %}

<!-- append to an attribute -->
{% render_field form.title class+="css_class_1 css_class_2" %}

<!-- template variables can be used as attribute values -->
{% render_field form.text placeholder=form.text.label %}

<!-- double colon -->
{% render_field form.search_query v-bind::class="{active:isActive}" %}

For fields rendered with {% render_field %} tag it is possible to set error class and required fields class by using WIDGET_ERROR_CLASS and WIDGET_REQUIRED_CLASS template variables:

{% with WIDGET_ERROR_CLASS='my_error' WIDGET_REQUIRED_CLASS='my_required' %}
    {% render_field form.field1 %}
    {% render_field form.field2 %}
    {% render_field form.field3 %}
{% endwith %}

You can be creative with these variables: e.g. a context processor could set a default CSS error class on all fields rendered by {% render_field %}.

attr

Adds or replaces any single html attribute for the form field.

Examples:

{% load widget_tweaks %}

<!-- change input type (e.g. to HTML5) -->
{{ form.search_query|attr:"type:search" }}

<!-- add/change several attributes -->
{{ form.text|attr:"rows:20"|attr:"cols:20"|attr:"title:Hello, world!" }}

<!-- attributes without parameters -->
{{ form.search_query|attr:"autofocus" }}


<!-- attributes with double colon Vuejs output: v-bind:class="{active:ValueEnabled}" -->
{{ form.search_query|attr:"v-bind::class:{active:ValueEnabled}" }}

add_class

Adds CSS class to field element. Split classes by whitespace in order to add several classes at once.

Example:

{% load widget_tweaks %}

<!-- add 2 extra css classes to field element -->
{{ form.title|add_class:"css_class_1 css_class_2" }}

set_data

Sets HTML5 data attribute ( http://ejohn.org/blog/html-5-data-attributes/ ). Useful for unobtrusive javascript. It is just a shortcut for 'attr' filter that prepends attribute names with 'data-' string.

Example:

{% load widget_tweaks %}

<!-- data-filters:"OverText" will be added to input field -->
{{ form.title|set_data:"filters:OverText" }}

append_attr

Appends attribute value with extra data.

Example:

{% load widget_tweaks %}

<!-- add 2 extra css classes to field element -->
{{ form.title|append_attr:"class:css_class_1 css_class_2" }}

'add_class' filter is just a shortcut for 'append_attr' filter that adds values to the 'class' attribute.

remove_attr

Removes any single html attribute for the form field.

Example:

{% load widget_tweaks %}

<!-- removes autofocus attribute from field element -->
{{ form.title|remove_attr:"autofocus" }}

add_label_class

The same as add_class but adds css class to form labels.

Example:

{% load widget_tweaks %}

<!-- add 2 extra css classes to field label element -->
{{ form.title|add_label_class:"label_class_1 label_class_2" }}

add_error_class

The same as 'add_class' but adds css class only if validation failed for the field (field.errors is not empty).

Example:

{% load widget_tweaks %}

<!-- add 'error-border' css class on field error -->
{{ form.title|add_error_class:"error-border" }}

add_error_attr

The same as 'attr' but sets an attribute only if validation failed for the field (field.errors is not empty). This can be useful when dealing with accessibility:

{% load widget_tweaks %}

<!-- add aria-invalid="true" attribute on field error -->
{{ form.title|add_error_attr:"aria-invalid:true" }}

add_required_class

The same as 'add_error_class' adds css class only for required field.

Example:

{% load widget_tweaks %}

<!-- add 'is-required' css class on field required -->
{{ form.title|add_required_class:"is-required" }}

field_type and widget_type

'field_type' and 'widget_type' are template filters that return field class name and field widget class name (in lower case).

Example:

{% load widget_tweaks %}

<div class="field {{ field|field_type }} {{ field|widget_type }} {{ field.html_name }}">
    {{ field }}
</div>

Output:

<div class="field charfield textinput name">
    <input id="id_name" type="text" name="name" maxlength="100" />
</div>

Mixing render_field and filters

The render_field tag and filters mentioned above can be mixed.

Example:

{% render_field form.category|append_attr:"readonly:readonly" type="text" placeholder="Category" %}

returns:

<input name="category" placeholder="Profession" readonly="readonly" type="text">

Filter chaining

The order django-widget-tweaks filters apply may seem counter-intuitive (leftmost filter wins):

{{ form.simple|attr:"foo:bar"|attr:"foo:baz" }}

returns:

<input foo="bar" type="text" name="simple" id="id_simple" />

It is not a bug, it is a feature that enables creating reusable templates with overridable defaults.

Reusable field template example:

{# inc/field.html #}
{% load widget_tweaks %}
<div>{{ field|attr:"foo:default_foo" }}</div>

Example usage:

{# my_template.html #}
{% load widget_tweaks %}
<form method='POST' action=''> {% csrf_token %}
    {% include "inc/field.html" with field=form.title %}
    {% include "inc/field.html" with field=form.description|attr:"foo:non_default_foo" %}
</form>

With 'rightmost filter wins' rule it wouldn't be possible to override |attr:"foo:default_foo" in main template.

Contributing

If you've found a bug, implemented a feature or have a suggestion, do not hesitate to contact me, fire an issue or send a pull request.

Testing

Make sure you have tox installed, then type

tox

from the source checkout.

NOT SUPPORTED

MultiWidgets: SplitDateTimeWidget, SplitHiddenDateTimeWidget

django-widget-tweaks's People

Contributors

adamchainz avatar aleksihakli avatar bashu avatar camilonova avatar danielrozenberg avatar deeprave avatar etienned avatar georgek avatar hartwork avatar huyx avatar illia-v avatar jazzband-bot avatar jezdez avatar jramnai avatar kmike avatar martinburchell avatar osantana avatar pahaz avatar raisoblast avatar shwoop avatar simhnna avatar skyl avatar slav0nic avatar tomcounsell avatar treyhunner avatar yanxun827 avatar zodman avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

django-widget-tweaks's Issues

Support for Django 2.1?

Hi!

Judging from tox.ini line 13 and the traceback I get with Django 2.1(.2 but not with 2.0.9), `django-widget-tweaks does not seem ready for Django 2.1. Are there plans to add support for it?

Thanks in advance!

Best, Sebastian

PS: The traceback is this:

[..]
  File "/usr/local/lib/python3.7/site-packages/widget_tweaks/templatetags/widget_tweaks.py", line 31, in as_widget
    html = old_as_widget(widget, attrs, only_initial)
  File "/usr/local/lib/python3.7/site-packages/django/forms/boundfield.py", line 93, in as_widget
    renderer=self.form.renderer,
TypeError: render() got an unexpected keyword argument 'renderer'

This related fix could be of interest: https://github.com/stuartaccent/django-autocomplete-light/commit/cfc5f4a25fcb4937cf07fc65ef4ed549ca0d1338

How to use django-widget-tweaks with MultipleChoiceField field?

1 QUESTION: How to use django-tweaks with MultipleChoiceField field?

2QUESTION: I have form with MultipleChoiceField field which has dynamic list for choices. Sometimes dynamic list can be empty []. So I want to show message in template when its empty but next code didnt show message.

forms.py:

class RequirementForm(forms.ModelForm):
    symbol = forms.MultipleChoiceField(widget=forms.CheckboxSelectMultiple)

    class Meta:
        model = Requirement
        fields = ('symbol',)

requirement_add.html:

{% load widget_tweaks %}
<form method="post" action="{% url 'project:requirement_add' project_code=project.code %}">
        {% for field in form %}
                {% render_field field class="form-control" %}
        {% empty %}
            <p>Form is empty!</p>
        {% endfor %}
</form>

SplitDateTimeWidget bug

Widget tweaks cuts off initial classes provided to subwidgets.

Used both directly(not through custom widget, and with custom widget). Result is same.

Consider following usage:

Template:
{% render_field field class+='validate' %}

Form:

class MySparEditForm(forms.ModelForm):
    posting_start = forms.SplitDateTimeField(widget=SplitDateTimeWidget(time_attrs={'class': 'datepicker'}, date_attrs={'class': 'timepicker'}))

    class Meta:
        model = Spar
        widgets = {
            'posting_end':  DateTimePicker(),
            'main_text': TextArea(),
            'image': forms.FileInput(),
            'active': CheckBox()
        }
        fields = [
            'active',
            'name',
            'type',
            'description',
            'main_text',
            'image',
            'participants',
            'posting_start',
            'posting_end',
        ]

And DateTimePicker widget code:

def add_classes(attrs, classes):
    if 'class' in attrs:
        attrs['class'] += f' {classes}'
    else:
        attrs['class'] = classes


class DateTimePicker(SplitDateTimeWidget):
    datepicker_classes = 'datepicker'
    timepicker_classes = 'timepicker'

    def __init__(self, attrs=None, date_format=None, time_format=None, date_attrs=None, time_attrs=None):
        date_attrs, time_attrs = date_attrs or {}, time_attrs or {}
        add_classes(date_attrs, self.datepicker_classes)
        add_classes(time_attrs, self.timepicker_classes)
        super().__init__(attrs, date_format, time_format, date_attrs, time_attrs)

Then result is:
http://joxi.ru/MAjBv7I40kDdAe.png

It replaces initial classes on subwidgets with provided via += instead of concatenating them.

At wits end with django refusing to use widget-tweaks tags

So I've been troubleshooting this for many hours now, without avail.

I've pip-installed django-widget-tweaks, and included 'widget_tweaks' in my settings.py file.

I also have this in my base.html file:

{% load static %}
{% load i18n %}
{% load compress %}
{% load widget_tweaks %}

I've tried a gazillion ways to {{ field|add_class:"form-control" }} or {% render_field...%}, and each time it will throw an error along the lines of "did you forget to register this tag?

My .pug file which extends base.html:

div(class="col-lg-4 col-md-6 cold-sm-12")
                    - var da_form = form
                    H3 Bottle Form
                    //- TODO: fix fields to dynamically adjust
                    form(method="post" action=".")
                        | {% csrf_token %}
                        for field in da_form.visible_fields
                            div(class="form-group row")
                                label(class="col-lg-4 col-md-3 col-sm-6 col-form-label") {{field.label_tag}}
                                div(class="col-lg-8 col-md-3 col-sm-6")
                                 | {{ field|add_class:"form-control" }}
                        input(class="form-control")(type="submit" value="submit")

Error when using add_class:

Invalid filter: 'add_class'

Error when using render_field:

Invalid block tag on line 54: 'render_field', expected 'empty' or 'endfor'. Did you forget to register or load this tag?

Notice that while this is a .pug file, the | basically means this is treated the very same like HTML/django variable.

Things I've tried and didn't help:

  1. Uninstalling widget_tweaks and re-installing
  2. doing for field in da_form instead of for field in da_form.visible_fields
  3. Loading both in .pug file and base.html, either, and both.
  4. loading core.widget_tweaks (where core is the app where my settings.py file is, that threw an error that core.widget_tweaks isn't a registered tag)
  5. Restarting the server

render_field doesn`t accept attr value which contain '

I tried to add angular.js ng-class attr.
for example:

{% render_field form.name ng-class="{'form-control form-white actuator_name':true, 'form-error': errors.name}" %}

And it fails. this one approach works fine:

{{ form.name|attr:"ng-class:{'form-control form-white actuator_name':true, 'form-error': errors.name}" }}

It seems that the render_field fails because of this
https://github.com/kmike/django-widget-tweaks/blob/master/widget_tweaks/templatetags/widget_tweaks.py#L113

It matches the end of value in the wrong place (right after { in my case)

Select other kind of widget

Is there any way to render a field with a different widget type?
I need to render a select input into a text input.

In the django Form class, for specific reason, I can't set widget=forms.TextInput, but I should be able to do it in a smart way like that:

{% render_field form.start_date class+="form-control" type="text" %}

But what I got is a HTML tag instead.

Can't override `type="search"` for text field anymore

Hi!

I'm migrating my project from Django 1.9 to 1.11. I have the following code which was working great in Django 1.9 but doesn't work in Django 1.11:

{% render_field form.q type='search' required='required' class='term-input' %}

And here's my Django form:

class SearchForm(forms.Form):
    q = forms.CharField(label='Search')

Only if I explicitly override the field widget's type atribute - it works:

class SearchForm(forms.Form):
    q = forms.CharField(label='Search', widget=TextInput(attrs={'type': 'search'}))

Investigation

AFAIU, Django 1.11 has moved widgets rendering from Python code into templates (which is 100% positive change IMO), but now they treat type attribute in a special way:

{# django-1.11.7/django/forms/templates/django/forms/widgets/input.html #}
<input type="{{ widget.type }}" name="{{ widget.name }}"{% if widget.value != None %} value="{{ widget.value|stringformat:'s' }}"{% endif %}{% include "django/forms/widgets/attrs.html" %} />

So when I override

{% render_field form.q required='required' class='term-input' data-x=1 %}

... - everything works great, but not when I change type :(

Initial value in field?

Hi,

How can I get to set a initial value like:

{% render_field form.data_entrega attr='required' value={{data_entrega}} required='required' class='form-control form-control-inline input-medium date-picker' %}

Thanks

Django widget tweaks 'render_field' not working

I have this form rendering template in django, and render_field is not working inside if-else:

{% load widget_tweaks %} 
{% for field in form %}
    <div class="form-group">
        {{ field.label_tag }} 
        {% if form.is_bound %} 
            {% if field.errors %} 
                {% render_field field class="form-control is-invalid" %} 
                {% for error in field.errors %}
                    <div class="invalid-feedback">
                        {{error}}
                    </div>
                {% endfor %} 
            {% else %} 
                {% render_field field class="form-control is-valid" %} 
            {% endif %} 
        {% else %} 
            {% render_field field class="form-control" %} 
        {% endif %} 

        {% if field.help_text %}
            <small class="form-text text-muted">
               {{ field.help_text }}
            </small>
        {% endif %}
    </div>
{% endfor %}

And it renders this:

But when I try a smaller version of the above code like following, then also it still doesn't work:

{% load widget_tweaks %} 
{% for field in form %}
        <div class="form-group">

            {% if field.errors %}
                {% render_field field class="form-control is-invalid" %}
            {% else %}
                {% render_field field class="form-control is-valid" %}
            {% endif %}

            {% if field.help_text %}
                <small class="form-text text-muted">
                    {{ field.help_text }}
                </small>
            {% endif %}

        </div>
{% endfor %}

And renders this:

But when I remove all if-else's:

{% load widget_tweaks %} 
{% for field in form %}
    <div class="form-group">
        {{ field.label_tag }} 
        {% render_field field class="form-control" %} 
        {% if field.help_text %}
            <small class="form-text text-muted">
               {{ field.help_text }}
            </small>
        {% endif %}
    </div>
{% endfor %}

Then it renders correctly:

But I need the if-else's to check for form errors and add error messages to form accordingly, will appreciate any help. So why is render_field not working with if-else ? How to resolve this ? Any other ways to use widget_tweaks to render error ?

How to set the value of a textarea widget?

Hi, thanks for the great repo! I am trying to add a textarea field and set the value with the render_field tag. I am unable to do this, and not sure if it is supported. Is so, please explain. Thanks!

from my django template

    {% render_field my_form.my_text_field rows='10' value='foobar' %}

from my forms.py

    class MyForm(forms.Form):
        my_text_field = forms.CharField(widget=forms.Textarea())

What I want rendered

<textarea rows="10" name="my_field" id="id_my_field">foobar</textarea>

add_class appending a new class in every refresh

I don't know if I'm doing something stupid, but when I use
{{ user_form.password1|add_class:"form-control pull-right" }} ,
a new "form-control pull-right" is added to the HTML output every time I refresh the page, so eventually I get something like

<input class="form-control pull-right form-control pull-right form-control pull-right form-control pull-right form-control pull-right ... />

Any ideas?

Attribute without parameters

<!-- attributes without parameters --> {{ form.search_query|attr:"required" }}

inserts required="" instead required

Support for Jinja2 templates

I'm using django v1.11.7 with Jinja2 v2.10 as the template engine. I want to use django-widget-tweaks to integrate bootstrap, so I can style form elements in my website.

This package won't work with Jinja templates, since it needs to load a custom tag set into the Jinja environment. Loading tag sets can be complex, since I may need to write an extension. I don't want to switch from Jinja2 since it offers more flexibility compared to django templates.

Is there some way to get django-widget-tweaks to work with Jinja?

render_field issue with i18n trans variable passed in his context

I have this problem:

For my responsive html page i have to replicate my content 2 times with different css class and placeholder for my input field:

Here is the code:

{% trans "Search with keywords" as search_q_mobile_token %}

{% render_field form.q placeholder=search_q_mobile_token class="mobile-friendly" %}

{% trans "Search with keywords, name or email" as search_q_desktop_token %}

{% render_field form.q placeholder=search_q_mobile_token class="desktop-friendly" %}

Expected result:

<input class="mobile-friendly" id="id_q" name="q" placeholder="Search with keywords" type="search">
<input class="desktop-friendly" id="id_q" name="q" placeholder="Search with keywords, name or email" type="search">

What i see:

<input class="mobile-friendly" id="id_q" name="q" placeholder="Search with keywords" type="search">
<input class="desktop-friendly" id="id_q" name="q" placeholder="Search with keywords" type="search">

As you can see the first output is as I expected, instead the second have a correct css class but the same placeholder of the first.
I thought it was a {%trans%} templatetag problem but if I print it on my html page using {{search_q_desktop_token}} just before the second {% render_field ..%} I see the correct item..

Someone could helps me to resolve this strange problem?

Chained attributes are assigned in reverse order

I noticed this possible bug while writing tests for the render_field tag.

Intuitively I think {{ form.simple|attr:"foo:bar"|attr:"foo:baz" }} should return this:

<input foo="baz" type="text" name="simple" id="id_simple" />

Instead it returns

<input foo="bar" type="text" name="simple" id="id_simple" />

Test case to demonstrate this issue: treyhunner/widget-tweaks@a61c08d28150560da140d2480f239798e7ffa3df

Button is not vertically aligned when using Bootstrap

I am using the following the code to create a form.
Without col-md-6, the button will be aligned on vertically. But with it, the button floats to the right.
Any idea to fix this?

{% load widget_tweaks %}
<form class="form" classaction="" method="post">{% csrf_token %}
        <div class="form-group col-md-6">
            <label for="title">Title</label>
            {%render_field form.title class="form-control" %}
        </div>

      <button type="submit" class="btn btn-success">Save</button>


</form>

Optionally add attributes

Some attributes trigger behaviors and meanings simply by their presence, such as the readonly attribute. In these cases even an empty string passed to render_field will cause the field to have the readonly attribute and be read-only, so there is no way to do this and pass 'false' in any form.

In the way that render_field supports both = and += to set or append an attribute, a syntax to optionally add would be great. OR, explicit support for fields like readonly that would just ignore the attribute if the value given was false.

tox basepython

All test environments except py26-dj12 using python 2.7 specified in testenv.

Trans usage

How do I use trans in a placeholder as an optional attr?

Internal Server Error - RecursionError

I've originally posted this on the SO, however it seems that bug lays on the django-widget-tweaks side.


I've tried a very basic load test on my django app, something among the lines:

for _ in {1..50}; do for x in {1..50}; do curl http://example.com &> /dev/null; done & done

After a while server started returning http 500, the reason for that was RecursionError:

Serving on http://unix:/tmp/waitress/socket
WARNING:django.template:Exception raised while rendering {% include %} for template 'django/forms/widgets/email.html'. Empty string rendered instead.
Traceback (most recent call last):
  File "/usr/local/lib/python3.6/site-packages/django/template/loader_tags.py", line 216, in render
    return template.render(context)
  File "/usr/local/lib/python3.6/site-packages/django/template/base.py", line 209, in render
    return self._render(context)
  File "/usr/local/lib/python3.6/site-packages/django/template/base.py", line 199, in _render
    return self.nodelist.render(context)
  File "/usr/local/lib/python3.6/site-packages/django/template/base.py", line 990, in render
    bit = node.render_annotated(context)
  File "/usr/local/lib/python3.6/site-packages/django/template/base.py", line 957, in render_annotated
    return self.render(context)
  File "/usr/local/lib/python3.6/site-packages/django/template/defaulttags.py", line 166, in render
    values = self.sequence.resolve(context, True)
  File "/usr/local/lib/python3.6/site-packages/django/template/base.py", line 708, in resolve
    obj = self.var.resolve(context)
  File "/usr/local/lib/python3.6/site-packages/django/template/base.py", line 849, in resolve
    value = self._resolve_lookup(context)
  File "/usr/local/lib/python3.6/site-packages/django/template/base.py", line 882, in _resolve_lookup
    current = current[bit]
  File "/usr/local/lib/python3.6/site-packages/django/template/context.py", line 84, in __getitem__
    for d in reversed(self.dicts):
RecursionError: maximum recursion depth exceeded while calling a Python object
WARNING:django.template:Exception raised while rendering {% include %} for template 'django/forms/widgets/text.html'. Empty string rendered instead.
Traceback (most recent call last):
  File "/usr/local/lib/python3.6/site-packages/django/template/loader_tags.py", line 216, in render
    return template.render(context)
  File "/usr/local/lib/python3.6/site-packages/django/template/base.py", line 209, in render
    return self._render(context)
  File "/usr/local/lib/python3.6/site-packages/django/template/base.py", line 199, in _render
    return self.nodelist.render(context)
  File "/usr/local/lib/python3.6/site-packages/django/template/base.py", line 990, in render
    bit = node.render_annotated(context)
  File "/usr/local/lib/python3.6/site-packages/django/template/base.py", line 957, in render_annotated
    return self.render(context)
  File "/usr/local/lib/python3.6/site-packages/django/template/defaulttags.py", line 166, in render
    values = self.sequence.resolve(context, True)
  File "/usr/local/lib/python3.6/site-packages/django/template/base.py", line 708, in resolve
    obj = self.var.resolve(context)
  File "/usr/local/lib/python3.6/site-packages/django/template/base.py", line 849, in resolve
    value = self._resolve_lookup(context)
  File "/usr/local/lib/python3.6/site-packages/django/template/base.py", line 882, in _resolve_lookup
    current = current[bit]
  File "/usr/local/lib/python3.6/site-packages/django/template/context.py", line 84, in __getitem__
    for d in reversed(self.dicts):
RecursionError: maximum recursion depth exceeded while calling a Python object
WARNING:django.template:Exception raised while rendering {% include %} for template 'django/forms/widgets/email.html'. Empty string rendered instead.
<...>

After a little more time (and requests) this looks like the following:

RecursionError: maximum recursion depth exceeded in comparison
ERROR:django.request:Internal Server Error: /
Traceback (most recent call last):
  File "/usr/local/lib/python3.6/site-packages/django/core/handlers/exception.py", line 41, in inner
    response = get_response(request)
  File "/usr/local/lib/python3.6/site-packages/django/core/handlers/base.py", line 187, in _get_response
    response = self.process_exception_by_middleware(e, request)
  File "/usr/local/lib/python3.6/site-packages/django/core/handlers/base.py", line 185, in _get_response
    response = wrapped_callback(request, *callback_args, **callback_kwargs)
  File "/usr/local/lib/python3.6/site-packages/django/views/generic/base.py", line 68, in view
    return self.dispatch(request, *args, **kwargs)
  File "/usr/local/lib/python3.6/site-packages/django/views/generic/base.py", line 88, in dispatch
    return handler(request, *args, **kwargs)
  File "/opt/django/portal/views.py", line 37, in get
    return render(request, self.template_name, ctx)
  File "/usr/local/lib/python3.6/site-packages/django/shortcuts.py", line 30, in render
    content = loader.render_to_string(template_name, context, request, using=using)
  File "/usr/local/lib/python3.6/site-packages/django/template/loader.py", line 68, in render_to_string
    return template.render(context, request)
  File "/usr/local/lib/python3.6/site-packages/django/template/backends/django.py", line 66, in render
    return self.template.render(context)
  File "/usr/local/lib/python3.6/site-packages/django/template/base.py", line 207, in render
    return self._render(context)
  File "/usr/local/lib/python3.6/site-packages/django/template/base.py", line 199, in _render
    return self.nodelist.render(context)
  File "/usr/local/lib/python3.6/site-packages/django/template/base.py", line 990, in render
    bit = node.render_annotated(context)
  File "/usr/local/lib/python3.6/site-packages/django/template/base.py", line 957, in render_annotated
    return self.render(context)
  File "/usr/local/lib/python3.6/site-packages/django/template/loader_tags.py", line 177, in render
    return compiled_parent._render(context)
  File "/usr/local/lib/python3.6/site-packages/django/template/base.py", line 199, in _render
    return self.nodelist.render(context)
  File "/usr/local/lib/python3.6/site-packages/django/template/base.py", line 990, in render
    bit = node.render_annotated(context)
  File "/usr/local/lib/python3.6/site-packages/django/template/base.py", line 957, in render_annotated
    return self.render(context)
  File "/usr/local/lib/python3.6/site-packages/django/template/loader_tags.py", line 72, in render
    result = block.nodelist.render(context)
  File "/usr/local/lib/python3.6/site-packages/django/template/base.py", line 993, in render
    bits.append(force_text(bit))
  File "/usr/local/lib/python3.6/site-packages/django/utils/encoding.py", line 76, in force_text
    s = six.text_type(s)
  File "/usr/local/lib/python3.6/site-packages/django/utils/html.py", line 385, in <lambda>
    klass.__str__ = lambda self: mark_safe(klass_str(self))
  File "/usr/local/lib/python3.6/site-packages/django/forms/boundfield.py", line 41, in __str__
    return self.as_widget()
  File "/usr/local/lib/python3.6/site-packages/widget_tweaks/templatetags/widget_tweaks.py", line 28, in as_widget
    html = old_as_widget(widget, attrs, only_initial)
  File "/usr/local/lib/python3.6/site-packages/widget_tweaks/templatetags/widget_tweaks.py", line 28, in as_widget
    html = old_as_widget(widget, attrs, only_initial)
  File "/usr/local/lib/python3.6/site-packages/widget_tweaks/templatetags/widget_tweaks.py", line 28, in as_widget
    html = old_as_widget(widget, attrs, only_initial)
  [Previous line repeated 902 more times]
  File "/usr/local/lib/python3.6/site-packages/django/forms/boundfield.py", line 101, in as_widget
    attrs = self.build_widget_attrs(attrs, widget)
  File "/usr/local/lib/python3.6/site-packages/django/forms/boundfield.py", line 257, in build_widget_attrs
    if widget.use_required_attribute(self.initial) and self.field.required and self.form.use_required_attribute:
  File "/usr/local/lib/python3.6/site-packages/django/forms/widgets.py", line 258, in use_required_attribute
    return not self.is_hidden
RecursionError: maximum recursion depth exceeded while calling a Python object
ERROR:django.request:Internal Server Error: /
Traceback (most recent call last):
  File "/usr/local/lib/python3.6/site-packages/django/core/handlers/exception.py", line 41, in inner
    response = get_response(request)
  File "/usr/local/lib/python3.6/site-packages/django/core/handlers/base.py", line 187, in _get_response
    response = self.process_exception_by_middleware(e, request)
  File "/usr/local/lib/python3.6/site-packages/django/core/handlers/base.py", line 185, in _get_response
    response = wrapped_callback(request, *callback_args, **callback_kwargs)
  File "/usr/local/lib/python3.6/site-packages/django/views/generic/base.py", line 68, in view
    return self.dispatch(request, *args, **kwargs)
  File "/usr/local/lib/python3.6/site-packages/django/views/generic/base.py", line 88, in dispatch
    return handler(request, *args, **kwargs)
  File "/opt/django/portal/views.py", line 37, in get
    return render(request, self.template_name, ctx)
  File "/usr/local/lib/python3.6/site-packages/django/shortcuts.py", line 30, in render
    content = loader.render_to_string(template_name, context, request, using=using)
  File "/usr/local/lib/python3.6/site-packages/django/template/loader.py", line 68, in render_to_string
    return template.render(context, request)
  File "/usr/local/lib/python3.6/site-packages/django/template/backends/django.py", line 66, in render
    return self.template.render(context)
  File "/usr/local/lib/python3.6/site-packages/django/template/base.py", line 207, in render
    return self._render(context)
  File "/usr/local/lib/python3.6/site-packages/django/template/base.py", line 199, in _render
    return self.nodelist.render(context)
  File "/usr/local/lib/python3.6/site-packages/django/template/base.py", line 990, in render
    bit = node.render_annotated(context)
  File "/usr/local/lib/python3.6/site-packages/django/template/base.py", line 957, in render_annotated
    return self.render(context)
  File "/usr/local/lib/python3.6/site-packages/django/template/loader_tags.py", line 177, in render
    return compiled_parent._render(context)
  File "/usr/local/lib/python3.6/site-packages/django/template/base.py", line 199, in _render
    return self.nodelist.render(context)
  File "/usr/local/lib/python3.6/site-packages/django/template/base.py", line 990, in render
    bit = node.render_annotated(context)
  File "/usr/local/lib/python3.6/site-packages/django/template/base.py", line 957, in render_annotated
    return self.render(context)
  File "/usr/local/lib/python3.6/site-packages/django/template/loader_tags.py", line 72, in render
    result = block.nodelist.render(context)
  File "/usr/local/lib/python3.6/site-packages/django/template/base.py", line 993, in render
    bits.append(force_text(bit))
  File "/usr/local/lib/python3.6/site-packages/django/utils/encoding.py", line 76, in force_text
    s = six.text_type(s)
  File "/usr/local/lib/python3.6/site-packages/django/utils/html.py", line 385, in <lambda>
    klass.__str__ = lambda self: mark_safe(klass_str(self))
  File "/usr/local/lib/python3.6/site-packages/django/forms/boundfield.py", line 41, in __str__
    return self.as_widget()
  File "/usr/local/lib/python3.6/site-packages/widget_tweaks/templatetags/widget_tweaks.py", line 28, in as_widget
    html = old_as_widget(widget, attrs, only_initial)
  File "/usr/local/lib/python3.6/site-packages/widget_tweaks/templatetags/widget_tweaks.py", line 28, in as_widget
    html = old_as_widget(widget, attrs, only_initial)
  File "/usr/local/lib/python3.6/site-packages/widget_tweaks/templatetags/widget_tweaks.py", line 28, in as_widget
    html = old_as_widget(widget, attrs, only_initial)
  [Previous line repeated 904 more times]
  File "/usr/local/lib/python3.6/site-packages/django/forms/boundfield.py", line 101, in as_widget
    attrs = self.build_widget_attrs(attrs, widget)
RecursionError: maximum recursion depth exceeded
ERROR:django.request:Internal Server Error: /
Traceback (most recent call last):
  File "/usr/local/lib/python3.6/site-packages/django/core/handlers/exception.py", line 41, in inner
    response = get_response(request)
  File "/usr/local/lib/python3.6/site-packages/django/core/handlers/base.py", line 187, in _get_response
    response = self.process_exception_by_middleware(e, request)
  File "/usr/local/lib/python3.6/site-packages/django/core/handlers/base.py", line 185, in _get_response
    response = wrapped_callback(request, *callback_args, **callback_kwargs)
  File "/usr/local/lib/python3.6/site-packages/django/views/generic/base.py", line 68, in view
    return self.dispatch(request, *args, **kwargs)
  File "/usr/local/lib/python3.6/site-packages/django/views/generic/base.py", line 88, in dispatch
    return handler(request, *args, **kwargs)
  File "/opt/django/portal/views.py", line 37, in get
    return render(request, self.template_name, ctx)
  File "/usr/local/lib/python3.6/site-packages/django/shortcuts.py", line 30, in render
    content = loader.render_to_string(template_name, context, request, using=using)
  File "/usr/local/lib/python3.6/site-packages/django/template/loader.py", line 68, in render_to_string
    return template.render(context, request)
  File "/usr/local/lib/python3.6/site-packages/django/template/backends/django.py", line 66, in render
    return self.template.render(context)
  File "/usr/local/lib/python3.6/site-packages/django/template/base.py", line 207, in render
    return self._render(context)
  File "/usr/local/lib/python3.6/site-packages/django/template/base.py", line 199, in _render
    return self.nodelist.render(context)
  File "/usr/local/lib/python3.6/site-packages/django/template/base.py", line 990, in render
    bit = node.render_annotated(context)
  File "/usr/local/lib/python3.6/site-packages/django/template/base.py", line 957, in render_annotated
    return self.render(context)
  File "/usr/local/lib/python3.6/site-packages/django/template/loader_tags.py", line 177, in render
    return compiled_parent._render(context)
  File "/usr/local/lib/python3.6/site-packages/django/template/base.py", line 199, in _render
    return self.nodelist.render(context)
  File "/usr/local/lib/python3.6/site-packages/django/template/base.py", line 990, in render
    bit = node.render_annotated(context)
  File "/usr/local/lib/python3.6/site-packages/django/template/base.py", line 957, in render_annotated
    return self.render(context)
  File "/usr/local/lib/python3.6/site-packages/django/template/loader_tags.py", line 72, in render
    result = block.nodelist.render(context)
  File "/usr/local/lib/python3.6/site-packages/django/template/base.py", line 993, in render
    bits.append(force_text(bit))
  File "/usr/local/lib/python3.6/site-packages/django/utils/encoding.py", line 76, in force_text
    s = six.text_type(s)
  File "/usr/local/lib/python3.6/site-packages/django/utils/html.py", line 385, in <lambda>
    klass.__str__ = lambda self: mark_safe(klass_str(self))
  File "/usr/local/lib/python3.6/site-packages/django/forms/boundfield.py", line 41, in __str__
    return self.as_widget()
  File "/usr/local/lib/python3.6/site-packages/widget_tweaks/templatetags/widget_tweaks.py", line 28, in as_widget
    html = old_as_widget(widget, attrs, only_initial)
  File "/usr/local/lib/python3.6/site-packages/widget_tweaks/templatetags/widget_tweaks.py", line 28, in as_widget
    html = old_as_widget(widget, attrs, only_initial)
  File "/usr/local/lib/python3.6/site-packages/widget_tweaks/templatetags/widget_tweaks.py", line 28, in as_widget
    html = old_as_widget(widget, attrs, only_initial)
  [Previous line repeated 904 more times]
  File "/usr/local/lib/python3.6/site-packages/widget_tweaks/templatetags/widget_tweaks.py", line 27, in as_widget
    process(widget or self.field.widget, attrs, attribute, value)
RecursionError: maximum recursion depth exceeded
ERROR:django.request:Internal Server Error: /

Now it seems that the culprit might be django-widget-tweaks, but is it? The way I use widget-tweaks is more or less copy/paste from their docs.

<div class="form-group{% if usr_form.email.errors %} has-error{% endif %}">
    {{ usr_form.email.errors }}
    {% render_field usr_form.email class+="form-control" placeholder="Email Address" %}
</div>

Below is the snipped from requirements.txt:

Django==1.11.4
django-widget-tweaks==1.4.1

EDIT

I've refactored my forms to the:

class UserModelForm(ModelForm):
    class Meta:
        model = models.User
        fields = ['name', 'email']
        widgets = {
            'name': TextInput(attrs={'class': 'form-control', 'placeholder': 'Full Name'}),
            'email': EmailInput(attrs={'class': 'form-control', 'placeholder': 'Email Address'}),
        }

And HTML:

<div class="form-group{% if usr_form.name.errors %} has-error{% endif %}">
    {{ usr_form.name.errors }}
    {{ usr_form.name }}
</div>
<div class="form-group{% if usr_form.email.errors %} has-error{% endif %}">
    {{ usr_form.email.errors }}
    {{ usr_form.email }}
</div>

Haven't seen http 500 since, so it's definitely django-widget-tweaks bug.

how to pass dynamic value in render_field method

I am using render_field inside loop how to pass loop counter value to render field methods

I tried with following code but loop counter taking as string

{% for u in formset.forms %}
     {% render_field u.name class+="form-control" id="name-{{forloop.counter0}}" %}
{% endfor %}

add_class overrides rather than appending in DateTime fields

add_class is working fine with DateField but it is overriding the class when using it on a DateTimeField and after that, the calendar widgets do not appear. My guess is because DateTimeField is formed by two different inputs and when it executes the append_attr function it doesn't detect their class so its lost during the next function calls.

add event

how about adding events dynamically i.e :
{% render_field field onchange='"function('+object.id +')"' %}
while object.id comes from server side.
is this possible?

forloop counter inside the the templatetag

Hi I would like to know if it is possible to put a forloop counter inside the template tag something like:

{% for emergencycontact_form in emergency %}

{{ emergencycontact_form.emergency_province|add_class:"form-control first-choice class_province"|attr:"data-toggle:tooltip"|attr:"data-address:form-forloop.counter-emergency"}}

{% endfor %}

P.S. the issue of the forloopcounter is in the last attribute

object.__new__(cStringIO.StringO) is not safe, use cStringIO.StringO.__new__()

Version 1.3 works fine, this only happens in 1.4.

ERROR Internal Server Error: /basket/
Traceback (most recent call last):
  File "/virtenvs/test/lib/python2.7/site-packages/django/core/handlers/base.py", line 164, in get_response
    response = response.render()
  File "/virtenvs/test/lib/python2.7/site-packages/django/template/response.py", line 158, in render
    self.content = self.rendered_content
  File "/virtenvs/test/lib/python2.7/site-packages/django/template/response.py", line 135, in rendered_content
    content = template.render(context, self._request)
  File "/virtenvs/test/lib/python2.7/site-packages/django/template/backends/django.py", line 74, in render
    return self.template.render(context)
  File "/virtenvs/test/lib/python2.7/site-packages/django/template/base.py", line 209, in render
    return self._render(context)
  File "/virtenvs/test/lib/python2.7/site-packages/django/template/base.py", line 201, in _render
    return self.nodelist.render(context)
  File "/virtenvs/test/lib/python2.7/site-packages/django/template/base.py", line 903, in render
    bit = self.render_node(node, context)
  File "/virtenvs/test/lib/python2.7/site-packages/django/template/debug.py", line 79, in render_node
    return node.render(context)
  File "/virtenvs/test/lib/python2.7/site-packages/django/template/loader_tags.py", line 135, in render
    return compiled_parent._render(context)
  File "/virtenvs/test/lib/python2.7/site-packages/django/template/base.py", line 201, in _render
    return self.nodelist.render(context)
  File "/virtenvs/test/lib/python2.7/site-packages/django/template/base.py", line 903, in render
    bit = self.render_node(node, context)
  File "/virtenvs/test/lib/python2.7/site-packages/django/template/debug.py", line 79, in render_node
    return node.render(context)
  File "/virtenvs/test/lib/python2.7/site-packages/django/template/loader_tags.py", line 135, in render
    return compiled_parent._render(context)
  File "/virtenvs/test/lib/python2.7/site-packages/django/template/base.py", line 201, in _render
    return self.nodelist.render(context)
  File "/virtenvs/test/lib/python2.7/site-packages/django/template/base.py", line 903, in render
    bit = self.render_node(node, context)
  File "/virtenvs/test/lib/python2.7/site-packages/django/template/debug.py", line 79, in render_node
    return node.render(context)
  File "/virtenvs/test/lib/python2.7/site-packages/django/template/loader_tags.py", line 65, in render
    result = block.nodelist.render(context)
  File "/virtenvs/test/lib/python2.7/site-packages/django/template/base.py", line 903, in render
    bit = self.render_node(node, context)
  File "/virtenvs/test/lib/python2.7/site-packages/django/template/debug.py", line 79, in render_node
    return node.render(context)
  File "/virtenvs/test/lib/python2.7/site-packages/django/template/loader_tags.py", line 65, in render
    result = block.nodelist.render(context)
  File "/virtenvs/test/lib/python2.7/site-packages/django/template/base.py", line 903, in render
    bit = self.render_node(node, context)
  File "/virtenvs/test/lib/python2.7/site-packages/django/template/debug.py", line 79, in render_node
    return node.render(context)
  File "/virtenvs/test/lib/python2.7/site-packages/django/template/loader_tags.py", line 65, in render
    result = block.nodelist.render(context)
  File "/virtenvs/test/lib/python2.7/site-packages/django/template/base.py", line 903, in render
    bit = self.render_node(node, context)
  File "/virtenvs/test/lib/python2.7/site-packages/django/template/debug.py", line 79, in render_node
    return node.render(context)
  File "/virtenvs/test/lib/python2.7/site-packages/django/template/loader_tags.py", line 159, in render
    return template.render(context)
  File "/virtenvs/test/lib/python2.7/site-packages/django/template/base.py", line 211, in render
    return self._render(context)
  File "/virtenvs/test/lib/python2.7/site-packages/django/template/base.py", line 201, in _render
    return self.nodelist.render(context)
  File "/virtenvs/test/lib/python2.7/site-packages/django/template/base.py", line 903, in render
    bit = self.render_node(node, context)
  File "/virtenvs/test/lib/python2.7/site-packages/django/template/debug.py", line 79, in render_node
    return node.render(context)
  File "/virtenvs/test/lib/python2.7/site-packages/django/template/defaulttags.py", line 329, in render
    return nodelist.render(context)
  File "/virtenvs/test/lib/python2.7/site-packages/django/template/base.py", line 903, in render
    bit = self.render_node(node, context)
  File "/virtenvs/test/lib/python2.7/site-packages/django/template/debug.py", line 79, in render_node
    return node.render(context)
  File "/virtenvs/test/lib/python2.7/site-packages/django/template/loader_tags.py", line 56, in render
    result = self.nodelist.render(context)
  File "/virtenvs/test/lib/python2.7/site-packages/django/template/base.py", line 903, in render
    bit = self.render_node(node, context)
  File "/virtenvs/test/lib/python2.7/site-packages/django/template/debug.py", line 79, in render_node
    return node.render(context)
  File "/virtenvs/test/lib/python2.7/site-packages/django/template/defaulttags.py", line 217, in render
    nodelist.append(node.render(context))
  File "/virtenvs/test/lib/python2.7/site-packages/django/template/defaulttags.py", line 576, in render
    return self.nodelist.render(context)
  File "/virtenvs/test/lib/python2.7/site-packages/django/template/base.py", line 903, in render
    bit = self.render_node(node, context)
  File "/virtenvs/test/lib/python2.7/site-packages/django/template/debug.py", line 79, in render_node
    return node.render(context)
  File "/virtenvs/test/lib/python2.7/site-packages/widget_tweaks/templatetags/widget_tweaks.py", line 196, in render
    bounded_field = append_attr(bounded_field, '%s:%s' % (k,v.resolve(context)))
  File "/virtenvs/test/lib/python2.7/site-packages/widget_tweaks/templatetags/widget_tweaks.py", line 15, in wrapped
    return fn(field, attr)
  File "/virtenvs/test/lib/python2.7/site-packages/widget_tweaks/templatetags/widget_tweaks.py", line 77, in append_attr
    return _process_field_attributes(field, attr, process)
  File "/virtenvs/test/lib/python2.7/site-packages/widget_tweaks/templatetags/widget_tweaks.py", line 31, in _process_field_attributes
    field = copy.deepcopy(field)
  File "/usr/local/Cellar/python/2.7.10/Frameworks/Python.framework/Versions/2.7/lib/python2.7/copy.py", line 190, in deepcopy
    y = _reconstruct(x, rv, 1, memo)
  File "/usr/local/Cellar/python/2.7.10/Frameworks/Python.framework/Versions/2.7/lib/python2.7/copy.py", line 334, in _reconstruct
    state = deepcopy(state, memo)
  File "/usr/local/Cellar/python/2.7.10/Frameworks/Python.framework/Versions/2.7/lib/python2.7/copy.py", line 163, in deepcopy
    y = copier(x, memo)
  File "/usr/local/Cellar/python/2.7.10/Frameworks/Python.framework/Versions/2.7/lib/python2.7/copy.py", line 257, in _deepcopy_dict
    y[deepcopy(key, memo)] = deepcopy(value, memo)
  File "/usr/local/Cellar/python/2.7.10/Frameworks/Python.framework/Versions/2.7/lib/python2.7/copy.py", line 190, in deepcopy
    y = _reconstruct(x, rv, 1, memo)
  File "/usr/local/Cellar/python/2.7.10/Frameworks/Python.framework/Versions/2.7/lib/python2.7/copy.py", line 334, in _reconstruct
    state = deepcopy(state, memo)
  File "/usr/local/Cellar/python/2.7.10/Frameworks/Python.framework/Versions/2.7/lib/python2.7/copy.py", line 163, in deepcopy
    y = copier(x, memo)
  File "/usr/local/Cellar/python/2.7.10/Frameworks/Python.framework/Versions/2.7/lib/python2.7/copy.py", line 257, in _deepcopy_dict
    y[deepcopy(key, memo)] = deepcopy(value, memo)
  File "/usr/local/Cellar/python/2.7.10/Frameworks/Python.framework/Versions/2.7/lib/python2.7/copy.py", line 190, in deepcopy
    y = _reconstruct(x, rv, 1, memo)
  File "/usr/local/Cellar/python/2.7.10/Frameworks/Python.framework/Versions/2.7/lib/python2.7/copy.py", line 334, in _reconstruct
    state = deepcopy(state, memo)
  File "/usr/local/Cellar/python/2.7.10/Frameworks/Python.framework/Versions/2.7/lib/python2.7/copy.py", line 163, in deepcopy
    y = copier(x, memo)
  File "/usr/local/Cellar/python/2.7.10/Frameworks/Python.framework/Versions/2.7/lib/python2.7/copy.py", line 257, in _deepcopy_dict
    y[deepcopy(key, memo)] = deepcopy(value, memo)
  File "/usr/local/Cellar/python/2.7.10/Frameworks/Python.framework/Versions/2.7/lib/python2.7/copy.py", line 190, in deepcopy
    y = _reconstruct(x, rv, 1, memo)
  File "/usr/local/Cellar/python/2.7.10/Frameworks/Python.framework/Versions/2.7/lib/python2.7/copy.py", line 334, in _reconstruct
    state = deepcopy(state, memo)
  File "/usr/local/Cellar/python/2.7.10/Frameworks/Python.framework/Versions/2.7/lib/python2.7/copy.py", line 163, in deepcopy
    y = copier(x, memo)
  File "/usr/local/Cellar/python/2.7.10/Frameworks/Python.framework/Versions/2.7/lib/python2.7/copy.py", line 257, in _deepcopy_dict
    y[deepcopy(key, memo)] = deepcopy(value, memo)
  File "/usr/local/Cellar/python/2.7.10/Frameworks/Python.framework/Versions/2.7/lib/python2.7/copy.py", line 190, in deepcopy
    y = _reconstruct(x, rv, 1, memo)
  File "/usr/local/Cellar/python/2.7.10/Frameworks/Python.framework/Versions/2.7/lib/python2.7/copy.py", line 334, in _reconstruct
    state = deepcopy(state, memo)
  File "/usr/local/Cellar/python/2.7.10/Frameworks/Python.framework/Versions/2.7/lib/python2.7/copy.py", line 163, in deepcopy
    y = copier(x, memo)
  File "/usr/local/Cellar/python/2.7.10/Frameworks/Python.framework/Versions/2.7/lib/python2.7/copy.py", line 257, in _deepcopy_dict
    y[deepcopy(key, memo)] = deepcopy(value, memo)
  File "/usr/local/Cellar/python/2.7.10/Frameworks/Python.framework/Versions/2.7/lib/python2.7/copy.py", line 190, in deepcopy
    y = _reconstruct(x, rv, 1, memo)
  File "/usr/local/Cellar/python/2.7.10/Frameworks/Python.framework/Versions/2.7/lib/python2.7/copy.py", line 334, in _reconstruct
    state = deepcopy(state, memo)
  File "/usr/local/Cellar/python/2.7.10/Frameworks/Python.framework/Versions/2.7/lib/python2.7/copy.py", line 163, in deepcopy
    y = copier(x, memo)
  File "/usr/local/Cellar/python/2.7.10/Frameworks/Python.framework/Versions/2.7/lib/python2.7/copy.py", line 257, in _deepcopy_dict
    y[deepcopy(key, memo)] = deepcopy(value, memo)
  File "/usr/local/Cellar/python/2.7.10/Frameworks/Python.framework/Versions/2.7/lib/python2.7/copy.py", line 190, in deepcopy
    y = _reconstruct(x, rv, 1, memo)
  File "/usr/local/Cellar/python/2.7.10/Frameworks/Python.framework/Versions/2.7/lib/python2.7/copy.py", line 334, in _reconstruct
    state = deepcopy(state, memo)
  File "/usr/local/Cellar/python/2.7.10/Frameworks/Python.framework/Versions/2.7/lib/python2.7/copy.py", line 163, in deepcopy
    y = copier(x, memo)
  File "/usr/local/Cellar/python/2.7.10/Frameworks/Python.framework/Versions/2.7/lib/python2.7/copy.py", line 237, in _deepcopy_tuple
    y.append(deepcopy(a, memo))
  File "/usr/local/Cellar/python/2.7.10/Frameworks/Python.framework/Versions/2.7/lib/python2.7/copy.py", line 163, in deepcopy
    y = copier(x, memo)
  File "/usr/local/Cellar/python/2.7.10/Frameworks/Python.framework/Versions/2.7/lib/python2.7/copy.py", line 257, in _deepcopy_dict
    y[deepcopy(key, memo)] = deepcopy(value, memo)
  File "/usr/local/Cellar/python/2.7.10/Frameworks/Python.framework/Versions/2.7/lib/python2.7/copy.py", line 190, in deepcopy
    y = _reconstruct(x, rv, 1, memo)
  File "/usr/local/Cellar/python/2.7.10/Frameworks/Python.framework/Versions/2.7/lib/python2.7/copy.py", line 329, in _reconstruct
    y = callable(*args)
  File "/virtenvs/test/bin/../lib/python2.7/copy_reg.py", line 93, in __newobj__
    return cls.__new__(cls, *args)
TypeError: object.__new__(cStringIO.StringO) is not safe, use cStringIO.StringO.__new__()
Traceback (most recent call last):
  File "/usr/local/Cellar/python/2.7.10/Frameworks/Python.framework/Versions/2.7/lib/python2.7/wsgiref/handlers.py", line 85, in run
    self.result = application(self.environ, self.start_response)
  File "/virtenvs/test/lib/python2.7/site-packages/django/contrib/staticfiles/handlers.py", line 63, in __call__
    return self.application(environ, start_response)
  File "/virtenvs/test/lib/python2.7/site-packages/django/core/handlers/wsgi.py", line 189, in __call__
    response = self.get_response(request)
  File "/virtenvs/test/lib/python2.7/site-packages/django/core/handlers/base.py", line 218, in get_response
    response = self.handle_uncaught_exception(request, resolver, sys.exc_info())
  File "/virtenvs/test/lib/python2.7/site-packages/django/core/handlers/base.py", line 261, in handle_uncaught_exception
    return debug.technical_500_response(request, *exc_info)
  File "/virtenvs/test/lib/python2.7/site-packages/django/views/debug.py", line 97, in technical_500_response
    html = reporter.get_traceback_html()
  File "/virtenvs/test/lib/python2.7/site-packages/django/views/debug.py", line 383, in get_traceback_html
    c = Context(self.get_traceback_data(), use_l10n=False)
  File "/virtenvs/test/lib/python2.7/site-packages/django/views/debug.py", line 328, in get_traceback_data
    frames = self.get_traceback_frames()
  File "/virtenvs/test/lib/python2.7/site-packages/django/views/debug.py", line 501, in get_traceback_frames
    'vars': self.filter.get_traceback_frame_variables(self.request, tb.tb_frame),
  File "/virtenvs/test/lib/python2.7/site-packages/django/views/debug.py", line 234, in get_traceback_frame_variables
    cleansed[name] = self.cleanse_special_types(request, value)
  File "/virtenvs/test/lib/python2.7/site-packages/django/views/debug.py", line 191, in cleanse_special_types
    value = self.get_request_repr(value)
  File "/virtenvs/test/lib/python2.7/site-packages/django/views/debug.py", line 122, in get_request_repr
    return build_request_repr(request, POST_override=self.get_post_parameters(request))
  File "/virtenvs/test/lib/python2.7/site-packages/django/views/debug.py", line 186, in get_post_parameters
    return request.POST
  File "/virtenvs/test/lib/python2.7/site-packages/django/core/handlers/wsgi.py", line 137, in _get_post
    self._load_post_and_files()
  File "/virtenvs/test/lib/python2.7/site-packages/django/http/request.py", line 246, in _load_post_and_files
    if self.method != 'POST':
AttributeError: 'WSGIRequest' object has no attribute 'method'

Rendering the same field still rembembers attribute

Thanks for wonderful widget-tweaks! Unfortunately I'm currently facing serious problem with multiple-times rendering same field. Every subsequent field rendering repeats "type" attribute from previous rendering. Interestingly it works for all other usual HTML attributes I tried (class, id, ...).

This buggy behavior is the same for render_field tag and filters like attr, add_class. Better to say it with example:

# render_field tag remembers first "type" forever:

{% render_field form.price_per_person type="disabled" class="form-control" %}
<input id="..." name="..." type="disabled" class="form-control" />

# even if not specified (it should be number because field is Django DecimalField):

{% render_field form.price_per_person %}
<input id="..." name="..." step="0.01" type="disabled" />

# the same "always remembered" applies for attr filter:

{{ form.price_per_person|attr:"type:disabled"|add_class:"form-control" }}
<input id="..." name="..." type="disabled" class="form-control" />

{{ form.price_per_person }}
<input id="..." name="..." type="disabled" />

Under some circumstances it will even stops you from manually overwriting "type" attribute to rescue:

# first occurrence is okay:

{% render_field form.price_per_person type="disabled" class="form-control" %}
<input class="form-control" id="..." name="..." type="disabled" />

# but subsequent usage keeps first-time used type value ONLY IF you specify any
# new attribute except "type" like "id". You specify hidden type, but it stays disabled.

{% render_field form.price_per_person id="..." type="hidden" %}
<input id="...." name="..." type="disabled" />

Using Django==1.9.7, django-widget-tweaks==1.4.1.

'widget_tweaks' is not a valid tag library

Trying to use v 1.4.1 with Python 2.7 and 3.4 I can't get it working in Django 1.8
Always receiving:
'widget_tweaks' is not a valid tag library: Template library widget_tweaks not found
on
{% load widget_tweaks %}
Any help?

And yes, it is enabled in my INSTALLES_APPS section in the settings.py

Is this project still being maintained?

I'm relying on this for a couple of small django apps because I didn't find any viable alternatives.

It appears as if the GitHub repository was moved sometime in the last year and since then nothing really happened.

I'd be willing to consider maintaining it, if @jazzband doesn't want to.

Strange behaviour with debug-toolbar and include

I noticed a very strange behaviour when using an {% include %} statement along with the Django debug toolbar enabled. Django-widget-tweaks filters are ignored when using the following (_field.html just contains {{ field }}):

{% include "_field.html" with field=form.foo|attr:"title:hello" %}

While it works fine when using {{ field }} in the main template instead of the include statement or when disabling the debug toolbar. Maybe the widget is rendered by the Django debug toolbar before being rendered in the page, and the original as_widget method is put back before it's rendered again in the template.

I created a project here that demonstrates the bug: https://github.com/sephii/django-widget-tweaks-bug

Just pip install the requirements, run the server, and go to https://localhost:8000/, you'll see the field that's included doesn't have the "title" attribute.

attr doesn't replace type

I have {{ field|add_class:"mdl-textfield__input"|attr:"type:date"}} and I expected <input type="date" name="start_date" value="2016-07-08" class="mdl-textfield__input" required id="id_start_date"> but in fact it produced <input type="text" name="start_date" value="2016-07-08" type="date" class="mdl-textfield__input" required id="id_start_date"> (notice the two types, with Google Chrome ignoring the second type)

copy.deepcopy(field) (Django 1.8.2, Python 2.7.6, on line 31)

So i was getting a weird bug, the template would say:

  • "A server error occurred. Please contact the administrator."

And in the terminal (running the development server):

  • A big stack of errors (you know normal python error).
  • (i'll place the stack at the end of the issue).

Any way, problem appear when using the render_field tag:

  • If use alone with no attr (attr="value"), everything works perfectly.
  • But if you place any attr, it breaks.

Digging in i found the problem on widget_tweaks/templatetags/widget_tweaks.py (line 26, 31):

  • i simply commented those lines and everything works perfectly once again :)
# if not PY26:
    # # See https://bugs.python.org/issue1515.
    # # It is OK to not do it in Python 2.6 because
    # # Django versions which require deepcopy here (1.7+)
    # # don't support Python 2.6 anyways.
    # field = copy.deepcopy(field) 

(doble comment :P)

So the comment says Django (1.7+), but i think there should be a second condition because it looks like in some newer version of Django, that statement stopped working.

My configuration:

  • virtualenv
  • Django 1.8.2
  • Python 2.7.6
  • Mac Os 10.10
  • widget_tweaks 1.4

Thanks for reading! 👍

Ok, terminal stack trace:

Traceback (most recent call last):
  File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/wsgiref/handlers.py", line 85, in run
    self.result = application(self.environ, self.start_response)
  File "/Users/alejandro/Documents/pythonDev/seeds/env/lib/python2.7/site-packages/django/contrib/staticfiles/handlers.py", line 63, in __call__
    return self.application(environ, start_response)
  File "/Users/alejandro/Documents/pythonDev/seeds/env/lib/python2.7/site-packages/django/core/handlers/wsgi.py", line 189, in __call__
    response = self.get_response(request)
  File "/Users/alejandro/Documents/pythonDev/seeds/env/lib/python2.7/site-packages/django/core/handlers/base.py", line 218, in get_response
    response = self.handle_uncaught_exception(request, resolver, sys.exc_info())
  File "/Users/alejandro/Documents/pythonDev/seeds/env/lib/python2.7/site-packages/django/core/handlers/base.py", line 261, in handle_uncaught_exception
    return debug.technical_500_response(request, *exc_info)
  File "/Users/alejandro/Documents/pythonDev/seeds/env/lib/python2.7/site-packages/django/views/debug.py", line 97, in technical_500_response
    html = reporter.get_traceback_html()
  File "/Users/alejandro/Documents/pythonDev/seeds/env/lib/python2.7/site-packages/django/views/debug.py", line 383, in get_traceback_html
    c = Context(self.get_traceback_data(), use_l10n=False)
  File "/Users/alejandro/Documents/pythonDev/seeds/env/lib/python2.7/site-packages/django/views/debug.py", line 328, in get_traceback_data
    frames = self.get_traceback_frames()
  File "/Users/alejandro/Documents/pythonDev/seeds/env/lib/python2.7/site-packages/django/views/debug.py", line 501, in get_traceback_frames
    'vars': self.filter.get_traceback_frame_variables(self.request, tb.tb_frame),
  File "/Users/alejandro/Documents/pythonDev/seeds/env/lib/python2.7/site-packages/django/views/debug.py", line 234, in get_traceback_frame_variables
    cleansed[name] = self.cleanse_special_types(request, value)
  File "/Users/alejandro/Documents/pythonDev/seeds/env/lib/python2.7/site-packages/django/views/debug.py", line 191, in cleanse_special_types
    value = self.get_request_repr(value)
  File "/Users/alejandro/Documents/pythonDev/seeds/env/lib/python2.7/site-packages/django/views/debug.py", line 122, in get_request_repr
    return build_request_repr(request, POST_override=self.get_post_parameters(request))
  File "/Users/alejandro/Documents/pythonDev/seeds/env/lib/python2.7/site-packages/django/views/debug.py", line 186, in get_post_parameters
    return request.POST
  File "/Users/alejandro/Documents/pythonDev/seeds/env/lib/python2.7/site-packages/django/core/handlers/wsgi.py", line 137, in _get_post
    self._load_post_and_files()
  File "/Users/alejandro/Documents/pythonDev/seeds/env/lib/python2.7/site-packages/django/http/request.py", line 246, in _load_post_and_files
    if self.method != 'POST':
AttributeError: 'WSGIRequest' object has no attribute 'method'
[29/Jun/2015 13:54:09]"GET / HTTP/1.1" 500 59

Support for ChoiceField

It's possible to render choice fields this way:

{% for radio in form.my_radio_field %}
                  {{ radio.tag }}
                  {{ radio.choice_label }}
{% endfor %}

This gives more control over the generated HTML. It's not currently possible to use widget tweaks template tags in this case. Eg.:

{% for radio in form.my_radio_field %}
                  {{ radio.tag|add_class:"some-class" }}
                  {{ radio.choice_label }}
{% endfor %}

Django 1.11 incompatibility

Hey,

I discovered a change between Django 1.10.6 and 1.11, which causes set_attr to silently ignore a Select widget with empty choices.

The incriminated line: https://github.com/kmike/django-widget-tweaks/blob/master/widget_tweaks/templatetags/widget_tweaks.py#L10

The underlying problem is that a Select widget with empty choices will evaluate to False as its len will be 0 in Django 1.11, while being 1 in <1.11.

I reported the change to the Django devs too, as this change is undocumented, and I'm not sure if it is intended that way. Link to the ticket: https://code.djangoproject.com/ticket/28058

If the change is intended, you'll have to update that check.

Cheers,

Use variable names for arguments of attr

I would like to do something like this:
{{ form.name|attr:"placeholder:"some_variable }}
So that value of some_variable appears as placeholder of name field.
This obviously throws a Template Syntax Error .
Is there any other way to do this ?

field_type filter is not a valid input for add_class filter

Hi! I try add the field_type filter as a class to a field as a follow:

{% with "{{field|field_type}}" as field_type %} {% render_field field class+="form-control {{field_type}}" required="true" %} {% endwith %}

But this way doesn't work.

Please, anyone could tell me how add this filter as a field's class?

Thanks!

PD: I'm sorry for my English!

Error with `class+="form-control"` - duplicate `class` attribute

The following part of form code:

<div class="form-group">
<label for="id_act_id">Точное направление</label>
{% render_field form.act_id class+="form-control" %}
</div>

produces the error:

<input type="text" class="autocomplete" name="act_id-autocomplete"
      id="id_act_id_text" value=""  class="form-control" />

How solved this?

     {% url 'myurl-upload-os'  as upload_file %}
     {{form_upload.image |attr:"multiple" |attr:'data-url:"{% url upload_file %}' }}

thanks guys!!

Publish v1.4.2 to PyPI

The latest version here on GitHub (v1.4.2) isn't available through PyPI, I assume someone with the correct permissions needs to publish it?

[REQUEST] Change html tag

Would it be possible to change or replace an html tag for a field? An example use case scenario is when I have to use a form element as a radio button. django renders it as a list of choices, but bootstrap does not, and hence the rendered form is ugly to look at.

Implement Jazzband guidelines for project django-widget-tweaks

This issue tracks the implementation of the Jazzband guidelines for the project django-widget-tweaks

It was initiated by @kmike who was automatically assigned in addition to the Jazzband roadies.

See the TODO list below for the generally required tasks, but feel free to update it in case the project requires it.

Feel free to ping a Jazzband roadie if you have any question.

TODOs

  • Fix all links in the docs (and README file etc) from old to new repo
  • Add the Jazzband badge to the README file
  • Add the Jazzband contributing guideline to the CONTRIBUTING.md file
  • Check if continuous testing works (e.g. Travis-CI, CircleCI, AppVeyor, etc)
  • Check if test coverage services work (e.g. Coveralls, Codecov, etc)
  • Add jazzband account to PyPI project as maintainer role (URL: https://pypi.python.org/pypi?:action=role_form&package_name=<PROJECTNAME>)
  • Add jazzband-bot as maintainer to the Read the Docs project (URL: https://readthedocs.org/dashboard/<PROJECTNAME>/users/)
  • Fix project URL in GitHub project description
  • Review project if other services are used and port them to Jazzband

Project details

Description Tweak the form field rendering in templates, not in python-level form definitions. CSS classes and HTML attributes can be altered.
Homepage
Stargazers 730
Open issues 27
Forks 58
Default branch master
Is a fork False
Has Wiki False
Has Pages False

Rendering of multi-widget fields and subwidgets

This is a feature request that may become a pull request if I decide to submit code for these features.

I have a modification of render_field that I have been using (as render_multi_field currently) that allows widgets from multi-widget fields to be rendered individually. This allows finer control over the rendering of fields using multi-widgets such as SplitDateTimeWidget.

Another widget type that often requires more control than Django offers by default is the RadioSelect widget which uses RadioInput subwidgets. This widget could be rendered with more control if subwidgets were rendered individually. RadioInput's tag method could be used to render each radio button when looping over them via the subwidgets method.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.