Testing formsets in Django - django

How do I pass the values of a formset in a unit test using client self.client.post('/url/', {})? I am getting a validation error saying management_form tampered.
Thanks in advance!

This is an example formset getting user's skills
class SkillForm(forms.Form):
level_id = forms.ChoiceField(choices=LEVEL_CHOICES, required = True)
txt_skills = forms.CharField(max_length=250, required = True)
SkillFormset = formset_factory(SkillForm,extra=1, max_num=10)
and this the sample POST data for test cases.
self.post_data.update({
'skillform-0-level_id': '2',
'skillform-0-txt_skills': 'Python',
'skillform-1-level_id': '3',
'skillform-1-txt_skills': 'Java',
'skillform-TOTAL_FORMS': '2',
'skillform-INITIAL_FORMS': '1',
'skillform-MAX_NUM_FORMS': '10'
})

Related

Deal with multiple forms from the same Model in Django

I have a template page where I can create multiple jobs at the same time.
They all use the same Form, and when I submit the form, I receive POST data on the view like this:
<QueryDict: {'csrfmiddlewaretoken': ['(token)'], 'name': ['name1', 'name2', 'name3'], 'min': ['1', '2', '3'], 'max': ['10', '20', '30'], 'color': ['green', 'blue', 'red']}>
In the view, when I do
form = JobForm(request.POST), I get the following clean data {'name': 'name3', 'min': 3, 'max': 30, 'color': 'red'}. I have seen this solution, but I don't know how many Jobs will be created at the same time so I can't create different prefixes on the view, so I only send the form to the template like this form = JobForm().
How can I check if all the submitted data is valid and create all the objects in a single page submission?

How to POST data to a Django Form that contains checkboxes

I have a problem when I am testing my registration form in Django. I am trying to make a POST request but I cannot select a checkbox field.
self.response = self.client.post(url, {
'username': 'testuser',
'password': 'testuserpassword',
'first_name': 'testtt',
'last_name': 'userrr',
'image': '',
'email': 'testuser#gmail.com',
'gender': 'M',
'dob': '10/10/1996',
'hobby': 'Fishing'
})
This is my line of code. The problem is at Hobby. The registration page is made of two forms. A profile form and a hobby form. There is a many-to-many relationship between Profile and Hobby models.
When I make the above POST request, I get this (Select a valid choice):
Thank you in advance!
According to the screenshot you've posted, the value for each hobby checkbox corresponds to an integer - 1, 2, 3, 4, etc. That would imply that the backend is expecting the hobby ID to be transmitted in the form. However, the test is not sending the hobby ID, it's sending the name.
Change the name to the corresponding ID - e.g.
self.response = self.client.post(url, {
...
'hobby': 1 # Fishing
})

FlaskTest FieldList form

I have forms:
class EntryForm(CsrfDissableForm):
id = HiddenField()
name = StringField(...)
...
class FooForm(FlaskForm):
entries = FieldList(FormField(EntryForm))
new_name = StringField(...)
...
In route:
...
while len(form.entries) > 0:
form_entry = form.entries.pop_entry()
save_changes(form_entry)
new_inst = form.new_name.data
save_new(new_inst)
...
I was write some test (Flask-Test used). I save 'new_name' from post data to database and then edit this as 'name' (entry form):
def test_change_name(self):
with self.client:
self.client.post(url, data={'new_name': 'Foo'})
foo = db.get_last_foo()
self.assertEqual(foo.name, 'Foo')
self.client.post(url, data={'entries': [{'id': foo.id, name: 'foo1'}]})
foo = db.get_by_id(foo.id)
self.assertEqual(foo.name, 'Foo')
I get error on this test:
TypeError: add_file() got an unexpected keyword argument 'id'.
How to correctly test a request from a form fieldlist?
Can I to wrong in route?
You need to post the form values as they would be posted by your application. So, it would look something like data={"entries-0-id": foo.id, "entries-0-name": "foo1"}
You may also need to include a csrf or disable csrf in your testing.

Django: How To use SplitArrayField?

I am trying to test out SplitArrayField,
class MYForm(forms.Form):
places = SplitArrayField(forms.IntegerField(), size=4)
Now, When I do:
form = MYForm({'places': [1,2,14,3]})
form.is_valid() returns False
and form.cleaned_data is {}
I checked the official docs, cant find a example. please fix me.
https://docs.djangoproject.com/es/1.9/ref/contrib/postgres/forms/#django.contrib.postgres.forms.SplitArrayField
The way to pass data for a SplitArrayField is like this:
form = MYForm({
'places_0': '1',
'places_1': '2',
'places_2': '14',
'places_3': '3',
})
form.is_valid() # True
form.cleaned_data # {'places': [1, 2, 14, 3]}
The field names need to be "split", and an index needs to be appended. The general format of a field name is '{field_name}_{index}'.
If you were to use a SimpleArrayField, the input data would look like this instead:
class MYForm(forms.Form):
places = SimpleArrayField(forms.IntegerField())
form = MYForm({
'places': '1,2,14,3'
})
form.is_valid() # True
form.cleaned_data # {'places': [1, 2, 14, 3]}

Django unit testing; POST checkboxes with multiple values

I am trying to run a unit test on a form with multiple checkboxes, but cannot figure out how to send the POST data. The most similar question I can find is here. But how do I embed that url-encoded piece into the POST with the other form data?
If I do something like this, my test errors out and says classes = request.POST.getlist('class_choices')
AttributeError: 'dict' object has no attribute 'getlist':
request = HttpRequest()
request.method = 'POST'
request.POST['fname'] = 'A'
request.POST['lname'] = 'Student'
request.POST['email'] = 'me#name.com'
request.POST['class_choices'] = urllib.urlencode({
'class_choices': ['1', '2'],
}, True)
request.POST['passwd'] = 'password'
request.POST['conpasswd'] = 'password'
response = success(request)
self.assertIn('My Browser', response.content.decode())
But if I do this, I get an error on fname = request.POST['fname']
TypeError: string indices must be integers, not str
request.POST = urllib.urlencode({
'class_choices': ['1', '2'],
'fname': 'A',
'lname': 'Student',
'email': 'me#name.com',
'passwd': 'password',
'conpasswd': 'password'
}, True)
response = success(request)
So after trying out a couple other things, I'm basically going to say there is "technically" no answer to my question...I could not find any way to create a checkbox-type POST argument using HttpRequest. However, doing it the 'right' way with the Django test client as Hieu Nguyen suggested does allow for that capability. You just have to encapsulate the multiple options in parantheses, as:
response = c.post('/success/',{
'fname': 'A',
'lname': 'Student',
'email': 'me#name.com',
'passwd': 'password',
'conpasswd': 'password',
'class_choices': ('1','2'),
})