I'm trying to create a form where I'm getting certain details from the user.
I have defined fields in forms.py
and I'm also defining other attributes like placeholder and css class using django widget
system. But it is showing me a TypeError
:
TypeError: __init__() got an unexpected keyword argument 'attrs'
Following is my code:
models.py
from django.db import models
class Contact(models.Model):
your_name = models.CharField(max_length=100)
your_email = models.EmailField()
your_subject = models.CharField(max_length=100)
your_comment = models.TextField(max_length=200)
def __str__(self):
return self.name
forms.py
from django.forms import ModelForm, TextInput, TextInput, EmailField
from .models import Contact
class ContactForm(ModelForm):
class Meta:
model = Contact
fields = ('your_name', 'your_email', 'your_subject', 'your_comment')
widgets = {
'your_name' : TextInput(attrs={'placeholder': 'Name *', 'class': 'form-control'}),
'your_email' : EmailField(attrs={'placeholder': 'Email *', 'class': 'form-control'}),
'your_subject' : TextInput(attrs={'placeholder': 'Subject *', 'class': 'form-control'}),
'your_comment' : Textarea(attrs={'placeholder': 'Comment *', 'class': 'form-control'}),
}
I've read Django docs for Overriding default fields and also this question init() got an unexpected keyword argument 'attrs' but cannot fix the error.
I am quite new to Python and Django and would appreciate any help, thank you.
TL;DR: EmailField
is a just that a Field
which can't be set as a widget, if you tried you'd run into the below problem, you want EmailInput
which is the widget for EmailField
.
First, TextInput
and Textarea
accept the keyword argument attrs
in their __init__
. So, these are fine.
Look at this line:
EmailField(attrs={'placeholder': 'Email *', 'class': 'form-control'}),
EmailField
is a subclass of CharField
which in turn is a subclass of Field
. Throughout this hierarchy attrs
will be passed along until it hits Field
which doesn't accept attrs
.
For reference here's the __init__
for Field
:
def __init__(self, required=True, widget=None, label=None, initial=None,
help_text='', error_messages=None, show_hidden_initial=False,
validators=(), localize=False, disabled=False, label_suffix=None):
The __init__
for CharField
:
def __init__(self, max_length=None, min_length=None, strip=True, empty_value='', *args, **kwargs)
....
super(CharField, self).__init__(*args, **kwargs)
# attrs is passed to Field -> error
The __init__
for EmailField
:
def __init__(self, *args, **kwargs):
super(EmailField, self).__init__(*args, strip=True, **kwargs)
# attrs is passed to CharField
There is a widget argument that is accepted in which you can place a widget that does accept the attrs
keyword.