According to the Django tutorial, you should access form fields using cleaned_data dictionary. I'm wondering why I can't access the properties of the form directly? My form validates just fine, but when I try to access it, Django complains that the object does not have the attribute. I added some code below that I hope will help diagnose the problem.
Form:
class CustomForm(forms.Form):
description = forms.CharField(widget = forms.TextInput(attrs = {'placeholder' : 'enter some text'}), label = "My form")
View:
def process_form(request):
if request.method != 'POST':
raise Http404
myForm = CustomForm(request.POST)
if not myForm.is_valid():
c = RequestContext(request)
return render_to_response('home/index.html', {'form' : myForm }, c)
# debug
print 'Description: ' + myForm.description # this does NOT work
# print 'Description: ' + myForm.cleaned_data['description'] # this does work
I get the following error: 'CustomForm' object has no attribute 'description'. Did I miss something in the docs that says I can't do that?
If your form is validated then you can access myForm cleaned_data:
print myForm.cleaned_data.get('description')
If you want to see why you cannot access myForm.description then you can see the data dictionary of your myForm:
print myForm.__dict__
The way you define fields using django.forms is just a convenient, declarative syntax; it's not really representative of what the final Form class, or an instance of it, looks like in terms of attributes.
Forms have a metaclass (without getting too deep into it, a metaclass is to declaring a class using the class keyword as an __init__ method is to creating an instance of a class using parentheses -- a hook to customise the object being created, which in the case of a metaclass, is a class!) which picks off Fields from the form class at definition time and adds them to a base_fields dict. When you instantiate a form, its base_fields are deep-copied to a fields attribute on the instance.
One point of confusion might be that you use . to access fields for display in templates -- what's actually happening there is that Django's template engine first attempts to use dictionary-style [] access to resolve property lookups and the base form class defines a __getitem__ method to take advantage of this, looking up the appropriate field from the form instance's fields dict and wrapping it with a BoundField, a wrapper which knows how to use the field and data from the form for displaying the field.
You can access the fields of a Form instance from its fields attribute.
myForm.fields['description']
And some property like label can be accessed like this:
myForm.fields['description'].label
Not sure how to display the value corresponding. Anybody having idea?
here is my reference
https://docs.djangoproject.com/en/dev/ref/forms/api/#accessing-the-fields-from-the-form
You can access your field trought dict.
form.__dict__["fields"]["description"]
Related
I have a subclass of ModelForm, FamilyDemographicsForm, for which two ChoiceFields are required: point_of_contact and birth_parent. For example, the following tests pass:
class FamilyDemographicsFormTest(TestCase):
def test_empty_form_is_not_valid(self):
'''The choice fields 'point_of_contact' and 'birth_parent' are
the only two required fields of the form'''
form = FamilyDemographicsForm(data={})
# The form is not valid because the required fields have not been provided
self.assertFalse(form.is_valid())
self.assertEqual(form.errors,
{'point_of_contact': ['This field is required.'],
'birth_parent': ['This field is required.']})
def test_form_with_required_fields_is_valid(self):
'''The form's save() method constructs the expected family'''
data = {'point_of_contact': Family.EMPLOYEE,
'birth_parent': Family.PARTNER}
form = FamilyDemographicsForm(data=data)
self.assertTrue(form.is_valid())
# The family returned by saving the form has the expected attributes
family = form.save()
self.assertEqual(family.point_of_contact, Family.EMPLOYEE)
self.assertEqual(family.birth_parent, Family.PARTNER)
# The family exists in the database
self.assertTrue(Family.objects.filter(id=family.id).exists())
In the second test case, a new instance of Family is created upon form.save(). I'd like to try instead to update an existing family. To get me started, I tried the following:
def test_update_existing_family(self):
initial = {'point_of_contact': Family.EMPLOYEE,
'birth_parent': Family.PARTNER}
data = {'employee_phone': '4151234567',
'employee_phone_type': Family.IPHONE,
'partner_phone': '4157654321',
'partner_phone_type': Family.ANDROID}
form = FamilyDemographicsForm(data=data, initial=initial)
import ipdb; ipdb.set_trace()
However, when I dropped into the debugger, I noticed that form.is_valid() is False and form.errors indicates that the required fields are not provided:
ipdb> form.errors
{'point_of_contact': ['This field is required.'], 'birth_parent': ['This field is required.']}
My question is: is there any way to instantiate a valid ModelForm with data that does not include the required fields? E.g. by providing an appropriate initial or instance argument? (This is not immediately clear to me from the source code for BaseModelForm on https://github.com/django/django/blob/master/django/forms/models.py).
You can modify the ModelForm and Form that Django provides to fit them your needs. You can override every method as you wish. The most base and essential prefill would be providing an initial dict with data {field_name: value, ...} that the form accepts without any modification.
So for example you have this
class Model1(models.Model):
name = models.CharField(max_length=100)
and this form
class Model1ModelForm(forms.ModelForm):
class Meta:
model = Model1
fields = ('name', )
and you can provide the initial data in the view as
initial = {'name': 'Initial name'}
form = Model1ModelForm(initial=initial)
so name in this form will be prefilled.
django docs: Providing initial values
stack overflow: Pass initial value to a modelform in django
I try to discover the fields which a django form class has.
I only have a class, not an instance.
The form-class is of type DeclarativeFieldsMetaclass.
If I try this:
class FooForm(forms.Form):
spreadsheet = forms.FileField()
for field in FooForm:
print(field)
I get this exception:
TypeError: 'DeclarativeFieldsMetaclass' object is not iterable
I know that I could do FooForm() instead of FooForm, but in my real use case I only have a class.
You can access FooForm.base_fields.
I have a problem to get back an object from a django form after submission.
I have an object list (filled with MyObject, not a django model) filled by another python package.
In models.py, I have :
class MyObjectForm(forms.Form):
def __init__(self, *args, **kwargs):
# Get the list
myobjects = kwargs.pop('myobjects')
super(MyObjectForm, self).__init__(*args, **kwargs)
choices = [(o, o.name) for o in myobjects]
self.fields["my_objects"] = forms.TypedChoiceField(choices=choices)
For information, the HTML looks OK.
In views.py, form.is_valid() is always False when I click on the submit button. Is there a problem ?
When I change models.py with :
self.fields["my_objects"] = forms.TypedChoiceField(choices=choices, required=False)
In views.py, form.is_valid() is True but I can't get back my objet MyObject (I get an empty value). Is that possible ? And if yes, how can I do that ?
Look at what you used as choices... MyObject instances, really ? How is a MyObject instance supposed to be sent to a browser as part of a HTML form and then back to your server thru a POST request body ?
If you have some persistant unique identifier for each of your MyObject instances, use this for your choices, ie
choices = [(o.some_stable_and_unique_id, o.name) for o in myobjects]
Note that it won't solve all of your issues... You'll then have to subclass TypedChoiceField to retrieve the object based on its "id" etc.
I need a form that has a dynamically created part and a static part to it. So I'm thinking of subclassing ... but can't figure out how this would work with a dynamically created form.
I am creating my dynamic form in this way:
from views.py
def create_legumes_form_class(legumes):
form_fields={}
for legume in legumes:
field_id = 's_{}'.format(legume.id)
form_fields[field_id] = IntegerField(default=0 , validators = [InputRequired()])
return type('OrderForm', (Form,), form_fields)
Then instantiating the form in my view function :
legumes = Legumes.query.filter_by(disponible = True).all()
OrderForm = create_legumes_form_class(legumes)
form = OrderForm()
But to this OrderForm(), I need to add a couple BooleanField(s) that will always be the same (ie. not dynamically created from the Query).
So I am trying to add a (static) form in my forms.py and instantiate it like this in the view function:
form=OrderForm(StaticForm)
But I'm getting
TypeError: formdata should be a multidict-type wrapper that supports the 'getlist' method
And I don't know where to take it from here !
What am I doing wrong/not doing ?
You can't pass another class to the OrderForm constructor and have it subclass that class. You can, however, provide it when you call type.
return type('OrderForm', (Form, StaticForm), form_fields)
If StaticForm subclasses Form this can be further simplified.
return type('OrderForm', (StaticForm,), form_fields)
In Django, how do I associate a Form with a Model so that data entered into the form are inserted into the database table associated with the Model? How do I save that user input to that database table?
For example:
class PhoneNumber(models.Model):
FirstName = models.CharField(max_length=30)
LastName = models.CharField(max_length=30)
PhoneNumber = models.CharField(max_length=20)
class PhoneNumber(forms.Form):
FirstName = forms.CharField(max_length=30)
LastName = forms.CharField(max_length=30)
PhoneNumber = forms.CharField(max_length=20)
I know there is a class for creating a form from the the model, but even there I'm unclear on how the data actually gets to the database. And I'd like to understand the inner workings before I move on to the time-savers. If there is a simple example of how this works in the docs, I've missed it.
Thanks.
UPDATED:
To be clear -- I do know about the ModelForm tool, I'm trying to figure out how to do this without that -- in part so I can better understand what it's doing in the first place.
ANSWERED:
With the help of the anwers, I arrived at this solution:
Form definition:
class ThisForm(forms.Form)
[various Field assignments]
model = ThisModel()
Code in views to save entered data to database:
if request_method == 'POST':
form = ThisForm(request.POST)
if form.is_valid():
for key, value in form.cleaned_data.items():
setattr(form.model, key, value)
form.model.save(form.model)
After this the data entered in the browser form was in the database table.
Note that the call of the model's save() method required passage of the model itself as an argument. I have no idea why.
CAVEAT: I'm a newbie. This succeeded in getting data from a browser to a database table, but God only knows what I've neglected or missed or outright broken along the way. ModelForm definitely seems like a much cleaner solution.
Back when I first used Forms and Models (without using ModelForm), what I remember doing was checking if the form was valid, which would set your cleaned data, manually moving the data from the form to the model (or whatever other processing you want to do), and then saving the model. As you can tell, this was extremely tedious when your form exactly (or even closely) matches your model. By using the ModelForm (since you said you weren't quite sure how it worked), when you save the ModelForm, it instantiates an object with the form data according to the model spec and then saves that model for you. So all-in-all, the flow of data goes from the HTML form, to the Django Form, to the Django Model, to the DB.
Some actual code for your questions:
To get the browser form data into the form object:
if request.method == 'POST':
form = SomeForm(request.POST)
if form.is_valid():
model.attr = form.cleaned_data['attr']
model.attr2 = form.cleaned_data['attr2']
model.save()
else:
form = SomeForm()
return render_to_response('page.html', {'form': form, })
In the template page you can do things like this with the form:
<form method="POST">
{{ form.as_p }}
<input type="submit"/>
</form>
That's just one example that I pulled from here.
I'm not sure which class do you mean. I know that there were a helper, something like form_for_model (don't really remember the exact name; that was way before 1.0 version was released). Right now I'd it that way:
import myproject.myapp.models as models
class PhoneNumberForm(forms.ModelForm):
class Meta:
model = models.PhoneNumber
To see the metaclass magic behind, you'd have to look into the code as there is a lot to explain :]. The constructor of the form can take instance argument. Passing it will make the form operate on an existing record rather than creating a new one. More info here.
I think ModelForm.save documentation should explain it. With its base class (Form) you would need to use the Form.cleaned_data() to get the field values and set them to appropriate Model fields "by hand". ModelForm does all that for you.
The Django documentation is pretty clear on this subject. However, here is a rough guide for you to get started: You can either override the form's save method or implement that functionality in the view.
if form.is_valid() # validation - first the fields, then the form itself is validated
form.save()
inside the form:
def save(self, *args, **kwargs):
foo = Foo()
foo.somefield = self.cleaned_data['somefield']
foo.otherfield = self.cleaned_data['otherfield']
...
return foo.save()