PageRenderTime 70ms CodeModel.GetById 29ms app.highlight 36ms RepoModel.GetById 1ms app.codeStats 0ms

/tests/regressiontests/model_formsets_regress/tests.py

https://code.google.com/p/mango-py/
Python | 411 lines | 356 code | 24 blank | 31 comment | 13 complexity | 478913623170c6c0fc49ce629db88b38 MD5 | raw file
  1from django import forms
  2from django.forms.formsets import BaseFormSet, DELETION_FIELD_NAME
  3from django.forms.util import ErrorDict, ErrorList
  4from django.forms.models import modelform_factory, inlineformset_factory, modelformset_factory, BaseModelFormSet
  5from django.test import TestCase
  6
  7from models import User, UserSite, Restaurant, Manager, Network, Host
  8
  9
 10class InlineFormsetTests(TestCase):
 11    def test_formset_over_to_field(self):
 12        "A formset over a ForeignKey with a to_field can be saved. Regression for #10243"
 13        Form = modelform_factory(User)
 14        FormSet = inlineformset_factory(User, UserSite)
 15
 16        # Instantiate the Form and FormSet to prove
 17        # you can create a form with no data
 18        form = Form()
 19        form_set = FormSet(instance=User())
 20
 21        # Now create a new User and UserSite instance
 22        data = {
 23            'serial': u'1',
 24            'username': u'apollo13',
 25            'usersite_set-TOTAL_FORMS': u'1',
 26            'usersite_set-INITIAL_FORMS': u'0',
 27            'usersite_set-MAX_NUM_FORMS': u'0',
 28            'usersite_set-0-data': u'10',
 29            'usersite_set-0-user': u'apollo13'
 30        }
 31        user = User()
 32        form = Form(data)
 33        if form.is_valid():
 34            user = form.save()
 35        else:
 36            self.fail('Errors found on form:%s' % form_set)
 37
 38        form_set = FormSet(data, instance=user)
 39        if form_set.is_valid():
 40            form_set.save()
 41            usersite = UserSite.objects.all().values()
 42            self.assertEqual(usersite[0]['data'], 10)
 43            self.assertEqual(usersite[0]['user_id'], u'apollo13')
 44        else:
 45            self.fail('Errors found on formset:%s' % form_set.errors)
 46
 47        # Now update the UserSite instance
 48        data = {
 49            'usersite_set-TOTAL_FORMS': u'1',
 50            'usersite_set-INITIAL_FORMS': u'1',
 51            'usersite_set-MAX_NUM_FORMS': u'0',
 52            'usersite_set-0-id': unicode(usersite[0]['id']),
 53            'usersite_set-0-data': u'11',
 54            'usersite_set-0-user': u'apollo13'
 55        }
 56        form_set = FormSet(data, instance=user)
 57        if form_set.is_valid():
 58            form_set.save()
 59            usersite = UserSite.objects.all().values()
 60            self.assertEqual(usersite[0]['data'], 11)
 61            self.assertEqual(usersite[0]['user_id'], u'apollo13')
 62        else:
 63            self.fail('Errors found on formset:%s' % form_set.errors)
 64
 65        # Now add a new UserSite instance
 66        data = {
 67            'usersite_set-TOTAL_FORMS': u'2',
 68            'usersite_set-INITIAL_FORMS': u'1',
 69            'usersite_set-MAX_NUM_FORMS': u'0',
 70            'usersite_set-0-id': unicode(usersite[0]['id']),
 71            'usersite_set-0-data': u'11',
 72            'usersite_set-0-user': u'apollo13',
 73            'usersite_set-1-data': u'42',
 74            'usersite_set-1-user': u'apollo13'
 75        }
 76        form_set = FormSet(data, instance=user)
 77        if form_set.is_valid():
 78            form_set.save()
 79            usersite = UserSite.objects.all().values().order_by('data')
 80            self.assertEqual(usersite[0]['data'], 11)
 81            self.assertEqual(usersite[0]['user_id'], u'apollo13')
 82            self.assertEqual(usersite[1]['data'], 42)
 83            self.assertEqual(usersite[1]['user_id'], u'apollo13')
 84        else:
 85            self.fail('Errors found on formset:%s' % form_set.errors)
 86
 87    def test_formset_over_inherited_model(self):
 88        "A formset over a ForeignKey with a to_field can be saved. Regression for #11120"
 89        Form = modelform_factory(Restaurant)
 90        FormSet = inlineformset_factory(Restaurant, Manager)
 91
 92        # Instantiate the Form and FormSet to prove
 93        # you can create a form with no data
 94        form = Form()
 95        form_set = FormSet(instance=Restaurant())
 96
 97        # Now create a new Restaurant and Manager instance
 98        data = {
 99            'name': u"Guido's House of Pasta",
100            'manager_set-TOTAL_FORMS': u'1',
101            'manager_set-INITIAL_FORMS': u'0',
102            'manager_set-MAX_NUM_FORMS': u'0',
103            'manager_set-0-name': u'Guido Van Rossum'
104        }
105        restaurant = User()
106        form = Form(data)
107        if form.is_valid():
108            restaurant = form.save()
109        else:
110            self.fail('Errors found on form:%s' % form_set)
111
112        form_set = FormSet(data, instance=restaurant)
113        if form_set.is_valid():
114            form_set.save()
115            manager = Manager.objects.all().values()
116            self.assertEqual(manager[0]['name'], 'Guido Van Rossum')
117        else:
118            self.fail('Errors found on formset:%s' % form_set.errors)
119
120        # Now update the Manager instance
121        data = {
122            'manager_set-TOTAL_FORMS': u'1',
123            'manager_set-INITIAL_FORMS': u'1',
124            'manager_set-MAX_NUM_FORMS': u'0',
125            'manager_set-0-id': unicode(manager[0]['id']),
126            'manager_set-0-name': u'Terry Gilliam'
127        }
128        form_set = FormSet(data, instance=restaurant)
129        if form_set.is_valid():
130            form_set.save()
131            manager = Manager.objects.all().values()
132            self.assertEqual(manager[0]['name'], 'Terry Gilliam')
133        else:
134            self.fail('Errors found on formset:%s' % form_set.errors)
135
136        # Now add a new Manager instance
137        data = {
138            'manager_set-TOTAL_FORMS': u'2',
139            'manager_set-INITIAL_FORMS': u'1',
140            'manager_set-MAX_NUM_FORMS': u'0',
141            'manager_set-0-id': unicode(manager[0]['id']),
142            'manager_set-0-name': u'Terry Gilliam',
143            'manager_set-1-name': u'John Cleese'
144        }
145        form_set = FormSet(data, instance=restaurant)
146        if form_set.is_valid():
147            form_set.save()
148            manager = Manager.objects.all().values().order_by('name')
149            self.assertEqual(manager[0]['name'], 'John Cleese')
150            self.assertEqual(manager[1]['name'], 'Terry Gilliam')
151        else:
152            self.fail('Errors found on formset:%s' % form_set.errors)
153
154    def test_formset_with_none_instance(self):
155        "A formset with instance=None can be created. Regression for #11872"
156        Form = modelform_factory(User)
157        FormSet = inlineformset_factory(User, UserSite)
158
159        # Instantiate the Form and FormSet to prove
160        # you can create a formset with an instance of None
161        form = Form(instance=None)
162        formset = FormSet(instance=None)
163
164    def test_empty_fields_on_modelformset(self):
165        "No fields passed to modelformset_factory should result in no fields on returned forms except for the id. See #14119."
166        UserFormSet = modelformset_factory(User, fields=())
167        formset = UserFormSet()
168        for form in formset.forms:
169            self.assertTrue('id' in form.fields)
170            self.assertEqual(len(form.fields), 1)
171
172    def test_save_as_new_with_new_inlines(self):
173        """
174        Existing and new inlines are saved with save_as_new.
175
176        Regression for #14938.
177
178        """
179        efnet = Network.objects.create(name="EFNet")
180        host1 = Host.objects.create(hostname="irc.he.net", network=efnet)
181
182        HostFormSet = inlineformset_factory(Network, Host)
183
184        # Add a new host, modify previous host, and save-as-new
185        data = {
186            'host_set-TOTAL_FORMS': u'2',
187            'host_set-INITIAL_FORMS': u'1',
188            'host_set-MAX_NUM_FORMS': u'0',
189            'host_set-0-id': unicode(host1.id),
190            'host_set-0-hostname': u'tranquility.hub.dal.net',
191            'host_set-1-hostname': u'matrix.de.eu.dal.net'
192        }
193
194        # To save a formset as new, it needs a new hub instance
195        dalnet = Network.objects.create(name="DALnet")
196        formset = HostFormSet(data, instance=dalnet, save_as_new=True)
197
198        self.assertTrue(formset.is_valid())
199        formset.save()
200        self.assertQuerysetEqual(
201            dalnet.host_set.order_by("hostname"),
202            ["<Host: matrix.de.eu.dal.net>", "<Host: tranquility.hub.dal.net>"]
203            )
204
205class FormsetTests(TestCase):
206    def test_error_class(self):
207        '''
208        Test the type of Formset and Form error attributes
209        '''
210        Formset = modelformset_factory(User)
211        data = {
212            'form-TOTAL_FORMS': u'2',
213            'form-INITIAL_FORMS': u'0',
214            'form-MAX_NUM_FORMS': u'0',
215            'form-0-id': '',
216            'form-0-username': u'apollo13',
217            'form-0-serial': u'1',
218            'form-1-id': '',
219            'form-1-username': u'apollo13',
220            'form-1-serial': u'2',
221        }
222        formset = Formset(data)
223        # check if the returned error classes are correct
224        # note: formset.errors returns a list as documented
225        self.assertTrue(isinstance(formset.errors, list))
226        self.assertTrue(isinstance(formset.non_form_errors(), ErrorList))
227        for form in formset.forms:
228            self.assertTrue(isinstance(form.errors, ErrorDict))
229            self.assertTrue(isinstance(form.non_field_errors(), ErrorList))
230
231class CustomWidget(forms.CharField):
232    pass
233
234
235class UserSiteForm(forms.ModelForm):
236    class Meta:
237        model = UserSite
238        widgets = {'data': CustomWidget}
239
240
241class Callback(object):
242
243    def __init__(self):
244        self.log = []
245
246    def __call__(self, db_field, **kwargs):
247        self.log.append((db_field, kwargs))
248        return db_field.formfield(**kwargs)
249
250
251class FormfieldCallbackTests(TestCase):
252    """
253    Regression for #13095: Using base forms with widgets
254    defined in Meta should not raise errors.
255    """
256
257    def test_inlineformset_factory_default(self):
258        Formset = inlineformset_factory(User, UserSite, form=UserSiteForm)
259        form = Formset().forms[0]
260        self.assertTrue(isinstance(form['data'].field.widget, CustomWidget))
261
262    def test_modelformset_factory_default(self):
263        Formset = modelformset_factory(UserSite, form=UserSiteForm)
264        form = Formset().forms[0]
265        self.assertTrue(isinstance(form['data'].field.widget, CustomWidget))
266
267    def assertCallbackCalled(self, callback):
268        id_field, user_field, data_field = UserSite._meta.fields
269        expected_log = [
270            (id_field, {}),
271            (user_field, {}),
272            (data_field, {'widget': CustomWidget}),
273        ]
274        self.assertEqual(callback.log, expected_log)
275
276    def test_inlineformset_custom_callback(self):
277        callback = Callback()
278        inlineformset_factory(User, UserSite, form=UserSiteForm,
279                              formfield_callback=callback)
280        self.assertCallbackCalled(callback)
281
282    def test_modelformset_custom_callback(self):
283        callback = Callback()
284        modelformset_factory(UserSite, form=UserSiteForm,
285                             formfield_callback=callback)
286        self.assertCallbackCalled(callback)
287
288
289class BaseCustomDeleteFormSet(BaseFormSet):
290    """
291    A formset mix-in that lets a form decide if it's to be deleted.
292    Works for BaseFormSets. Also works for ModelFormSets with #14099 fixed.
293
294    form.should_delete() is called. The formset delete field is also suppressed.
295    """
296    def add_fields(self, form, index):
297        super(BaseCustomDeleteFormSet, self).add_fields(form, index)
298        self.can_delete = True
299        if DELETION_FIELD_NAME in form.fields:
300            del form.fields[DELETION_FIELD_NAME]
301
302    def _should_delete_form(self, form):
303        return hasattr(form, 'should_delete') and form.should_delete()
304
305
306class FormfieldShouldDeleteFormTests(TestCase):
307    """
308    Regression for #14099: BaseModelFormSet should use ModelFormSet method _should_delete_form
309    """
310
311    class BaseCustomDeleteModelFormSet(BaseModelFormSet, BaseCustomDeleteFormSet):
312        """ Model FormSet with CustomDelete MixIn """
313
314    class CustomDeleteUserForm(forms.ModelForm):
315        """ A model form with a 'should_delete' method """
316        class Meta:
317            model = User
318
319        def should_delete(self):
320            """ delete form if odd PK """
321            return self.instance.id % 2 != 0
322
323    NormalFormset = modelformset_factory(User, form=CustomDeleteUserForm, can_delete=True)
324    DeleteFormset = modelformset_factory(User, form=CustomDeleteUserForm, formset=BaseCustomDeleteModelFormSet)
325
326    data = {
327            'form-TOTAL_FORMS': '4',
328            'form-INITIAL_FORMS': '0',
329            'form-MAX_NUM_FORMS': '4',
330            'form-0-username': 'John',
331            'form-0-serial': '1',
332            'form-1-username': 'Paul',
333            'form-1-serial': '2',
334            'form-2-username': 'George',
335            'form-2-serial': '3',
336            'form-3-username': 'Ringo',
337            'form-3-serial': '5',
338            }
339
340    delete_all_ids = {
341            'form-0-DELETE': '1',
342            'form-1-DELETE': '1',
343            'form-2-DELETE': '1',
344            'form-3-DELETE': '1',
345            }
346
347    def test_init_database(self):
348        """ Add test data to database via formset """
349        formset = self.NormalFormset(self.data)
350        self.assertTrue(formset.is_valid())
351        self.assertEqual(len(formset.save()), 4)
352
353    def test_no_delete(self):
354        """ Verify base formset doesn't modify database """
355        # reload database
356        self.test_init_database()
357
358        # pass standard data dict & see none updated
359        data = dict(self.data)
360        data['form-INITIAL_FORMS'] = 4
361        data.update(dict(
362            ('form-%d-id' % i, user.id)
363            for i,user in enumerate(User.objects.all())
364        ))
365        formset = self.NormalFormset(data, queryset=User.objects.all())
366        self.assertTrue(formset.is_valid())
367        self.assertEqual(len(formset.save()), 0)
368        self.assertEqual(len(User.objects.all()), 4)
369
370    def test_all_delete(self):
371        """ Verify base formset honors DELETE field """
372        # reload database
373        self.test_init_database()
374
375        # create data dict with all fields marked for deletion
376        data = dict(self.data)
377        data['form-INITIAL_FORMS'] = 4
378        data.update(dict(
379            ('form-%d-id' % i, user.id)
380            for i,user in enumerate(User.objects.all())
381        ))
382        data.update(self.delete_all_ids)
383        formset = self.NormalFormset(data, queryset=User.objects.all())
384        self.assertTrue(formset.is_valid())
385        self.assertEqual(len(formset.save()), 0)
386        self.assertEqual(len(User.objects.all()), 0)
387
388    def test_custom_delete(self):
389        """ Verify DeleteFormset ignores DELETE field and uses form method """
390        # reload database
391        self.test_init_database()
392
393        # Create formset with custom Delete function
394        # create data dict with all fields marked for deletion
395        data = dict(self.data)
396        data['form-INITIAL_FORMS'] = 4
397        data.update(dict(
398            ('form-%d-id' % i, user.id)
399            for i,user in enumerate(User.objects.all())
400        ))
401        data.update(self.delete_all_ids)
402        formset = self.DeleteFormset(data, queryset=User.objects.all())
403
404        # verify two were deleted
405        self.assertTrue(formset.is_valid())
406        self.assertEqual(len(formset.save()), 0)
407        self.assertEqual(len(User.objects.all()), 2)
408
409        # verify no "odd" PKs left
410        odd_ids = [user.id for user in User.objects.all() if user.id % 2]
411        self.assertEqual(len(odd_ids), 0)