Repository: zostera/django-bootstrap3

Issue:
attributes of widget removed by FieldRendered
after a few try, I found a bug in the FieldRenderer behaviour.

I wrote 2 unit tests that trigger the problem. for a same form instance, two render of the field with
extra attributes (like "addon_before" or "addon_before") will be different. all attributes are removed from the widget `attrs` during the render.  

``` python

    def test_field_same_render(self):
        form = TestForm()
        rendered_a = render_form_field("addon", form=form)
        rendered_b = render_form_field("addon", form=form)
        self.assertEqual(rendered_a, rendered_b)

    def test_attributes_consistence(self):
        form = TestForm()
        attrs = form.fields['addon'].widget.attrs
        field_alone = render_form_field("addon", form=form)
        self.assertEqual(attrs, form.fields['addon'].widget.attrs)
```

I found some lines that trigger the problem (for "addon_before" or "addon_before") , but I don't understand the meaning of the block, so I don't know how to fix it without breaking the logic. 

in renderer.py : 

``` python

class FieldRenderer(BaseRenderer):
    def __init__(self, field, *args, **kwargs):
        [...]
        self.initial_attrs = self.widget.attrs.copy()
        [...]
        self.addon_before = kwargs.get('addon_before', self.initial_attrs.pop('addon_before', ''))
        self.addon_after = kwargs.get('addon_after', self.initial_attrs.pop('addon_after', ''))
        [...]

    def restore_widget_attrs(self):
        self.widget.attrs = self.initial_attrs
```

It seem you make a copy of widget.attrs and after rendering, you restore attrs with this copy => ok
but, to store the `self.addon_before` and `self.addon_after`, you `pop` from your backup in lieu of the original attrs which will be restored.

in fact, after the first render, all `attrs` are removed. not only the both «addon». 



Discussion:

Resolving patch:
diff --git a/bootstrap3/renderers.py b/bootstrap3/renderers.py
--- a/bootstrap3/renderers.py
+++ b/bootstrap3/renderers.py
@@ -240,8 +240,8 @@ def __init__(self, field, *args, **kwargs):
         else:
             self.placeholder = ''
 
-        self.addon_before = kwargs.get('addon_before', self.initial_attrs.pop('addon_before', ''))
-        self.addon_after = kwargs.get('addon_after', self.initial_attrs.pop('addon_after', ''))
+        self.addon_before = kwargs.get('addon_before', self.widget.attrs.pop('addon_before', ''))
+        self.addon_after = kwargs.get('addon_after', self.widget.attrs.pop('addon_after', ''))
 
         # These are set in Django or in the global BOOTSTRAP3 settings, and
         # they can be overwritten in the template
@@ -275,7 +275,7 @@ def __init__(self, field, *args, **kwargs):
         self.set_disabled = kwargs.get('set_disabled', False)
 
     def restore_widget_attrs(self):
-        self.widget.attrs = self.initial_attrs
+        self.widget.attrs = self.initial_attrs.copy()
 
     def add_class_attrs(self, widget=None):
         if widget is None:


Test patch:
diff --git a/bootstrap3/tests.py b/bootstrap3/tests.py
--- a/bootstrap3/tests.py
+++ b/bootstrap3/tests.py
@@ -427,6 +427,17 @@ def test_datetime(self):
         self.assertIn('vDateField', field)
         self.assertIn('vTimeField', field)
 
+    def test_field_same_render(self):
+        form = TestForm()
+        rendered_a = render_form_field("addon", form=form)
+        rendered_b = render_form_field("addon", form=form)
+        self.assertEqual(rendered_a, rendered_b)
+
+    def test_attributes_consistency(self):
+        form = TestForm()
+        attrs = form.fields['addon'].widget.attrs.copy()
+        field_alone = render_form_field("addon", form=form)
+        self.assertEqual(attrs, form.fields['addon'].widget.attrs)
 
 class ComponentsTest(TestCase):
     def test_icon(self):