Search code examples
djangodjango-widget

Django - custom widget - why does Django think I don't have 'attrs'?


EDIT: Using Django 1.3

I've built a Custom Widget to educate myself but I can't get past a problem where when the page is fetched Django says that:

'FooTestWidget' object has no attribute 'attrs'

I don't want to use the 'attrs' argument and I've set it to default to None (also tried an empty dictionary, eg {}) so I'm confused about why Django is complaining.

widgets.py

class FooTestWidget(Widget):
    """
    A very silly widget to test I can do anything
    """
    def __init__(self, attrs=None):
        pass

    def render(self, name, value, attrs=None):
        tpl = Template(u"""<h1>This is here instead of a CharField</h1>""")
        return mark_safe(tpl.substitute(colour=value))

admin.py

class UserAdminForm(ModelForm):
    class Meta:
        model = User
        widgets = {
                'name_family': FooTestWidget,
        }

class UserAdmin(admin.ModelAdmin):
    form = UserAdminForm

model.py

class User(models.Model):
    id = models.AutoField(primary_key=True, db_column='USE_ID')
    name_given = models.CharField(max_length=200, db_column='USE_NAME_GIVEN')
    name_family = models.CharField(max_length=200, db_column='USE_NAME_FAMILY')

WORKING VERSION AFTER HELP FROM DANIEL

Here's a working version of widgets.py after taking on board what Daniel explained in his answer and then me making one or two other small changes (which weren't assocated with the problem described here but which stopped it working as it should). This version now works as I expected it to:

from datetime import date
import re

from django.forms.widgets import Widget, Select
from django.utils.safestring import mark_safe
from django.forms import widgets
from django.template.base import Template

__all__ = ('FooTestWidget',)

RE_DATE = re.compile(r'(\d{4})-(\d\d?)-(\d\d?)$')

class FooTestWidget(Widget):
    """
    A very silly widget to test I can do anything
    """
    #def __init__(self, attrs={}):
    #    pass

    def render(self, name, value, attrs=None):
        sout = u"""<h1>This is here instead of a CharField</h1>"""
        return mark_safe(sout)

Solution

  • The trouble is you've overridden __init__ with a method that does nothing. Since you don't even call the superclass method, none of the setup that Django is expecting will happen: including setting the attrs parameter to the self.attrs attribute.

    Basically, if you really must override __init__, then at least call super(FooTestWidget, self).__init__(attrs) there somewhere. But, if you're not doing anything special in that method, best not to override it at all and let the super method be used automatically.