Django ModelForms - testing forms with model that have M2M inline instance using an intermediate model

113 views
Skip to first unread message

luke lukes

unread,
Dec 25, 2013, 3:24:47 PM12/25/13
to django...@googlegroups.com
I have invoice/estimates django app, I need to write tests for it. Since I'm a beginner with this, testing forms results hard for me.
This is the code - for models, form  and admin:

    # MODELS 
    class Invoice(models.Model):
        subject = models.ForeignKey(
   Subject,
   verbose_name= _("Subject")
        )
        date = models.DateField(default=date.today())
        tasks = models.ManyToManyField(
   Task,
   through='TaskCount',
        )
        discount = models.DecimalField(
   max_digits=10, 
   decimal_places=2, 
   default=0
        )
        tip1 = models.BooleanField();
        tip2 = models.BooleanField();
        tax_a = models.BooleanField();
        notes = models.CharField(max_length=500, blank=True)
        expire = models.DateField(null=True, blank=True)
        invoicenumber = models.IntegerField("Invoice number")
        subtotal = models.DecimalField(max_digits=10, decimal_places=2,)
        amount = models.DecimalField(max_digits=10, decimal_places=2, default=0)
        adi_start_date = models.DateField(null=True, blank=True)
        adi_end_date = models.DateField(null=True, blank=True)


    class People(models.Model):
        first_name = models.CharField(
            "First name",max_length=50, blank=True
        )
        last_name = models.CharField(
            "Last name",max_length=50, blank=True
        )
        ....
        .... # other fields
        def __unicode__(self):
   return u"%s %s" % (self.first_name, self.last_name)

    # model for inlines
    class TaskCount(models.Model):
        count_items = models.PositiveIntegerField("Qty", default=1)
        task = models.ForeignKey(
   'Task',
   null=False)
        estimate = models.ForeignKey(
            'Estimate', 
            null=True, 
            blank=True
        )
        invoice = models.ForeignKey(
            'Invoice',
            related_name='task_count',
            null=True,
            blank=True
        )

        def __unicode__(self):
            return u"%s" % (str(self.task.price))

    class Task(models.Model):
        label = models.CharField(
            "Task name",
            max_length=150
        )
        price = models.DecimalField(
            "Price per session", 
            max_digits=10, 
            decimal_places=2,
            default=0
        )
        is_adi = models.BooleanField(
            default=False,
            help_text=_("")
        )



    # FORMS

    class InvoiceAdminForm(forms.ModelForm):
        class Meta:
            model = Invoice

        def __init__(self, *args, **kwargs):
            super(InvoiceAdminForm, self).__init__(*args, **kwargs)
   ....

    # ADMIN

    # inline
    class TaskCountInline(admin.TabularInline):
        model = TaskCount
        extra = 0
        fields = ('num_items', 'task')

        def __init__(self, *args, **kwargs):
            super(TaskCountInline, self).__init__(*args, **kwargs)

        ...

    class InvoiceAdmin(admin.ModelAdmin):
        list_display = ('subject', 'date', 'amount',
'discount', 'invoicenumber','get_pdf',
'edit_item', 'delete_item')
        list_display_links = ('edit_item',)
        filter_horizontal = ('tasks',)
        search_fields = ['subject__first_name','subject__last_name']
        actions = ['create_pdf']
        inlines = (TaskCountInline,)
        form = InvoiceAdminForm

        fieldsets = (
   .... # fieldsets ovverride
        )

        formfield_overrides = {
   models.CharField: {'widget': forms.Textarea},
        }

        def get_pdf(self, obj):
            opts = self.model._meta
            return '<a href=%(reverse_url)s>' \
                   '<img src="/static/admin/img/blue-document-pdf.png"/>' \
                   '</a>' % {
      'reverse_url':reverse(
                           'admin:%s_%s_pdf' % (
                                opts.app_label, 
                                opts.object_name.lower()),
args=(obj.id,)
       ),
           }
        get_pdf.short_description = _("PDF")
        get_pdf.allow_tags = True

        def change_view(self, request, object_id, form_url='', extra_context=None):
   ...


        def get_urls(self):
            urls = super(InvoiceAdmin, self).get_urls()
            info = self.model._meta.app_label, self.model._meta.module_name
            extra_urls = patterns('',
                url(r'^(?P<object_id>\d+)/pdf/$',
                    self.admin_site.admin_view(self.pdf_view),
                    name='%s_%s_pdf' % info),
            )
            return extra_urls+urls

        def pdf_view(self, request, object_id, extra_context=None):
            """
            view for generating PDF objects
            """
            ....


        def get_form(self, request, obj=None, **kwargs):
            form = super(InvoiceAdmin, self).get_form(request, obj, **kwargs)
            form.base_fields['invoicenumber'].initial =self.__get_last_invoice_nr_plus_one()
            ....
            return form

        def __get_last_invoice_nr_plus_one(self):
            ...


I'm trying to test the InvoiceAdminForm. this is the test code:


    # FORM TESTS

    class InvoiceAdminFormTestCase(TestCase):
def setUp(self):
   self.subject = Preople.objects.create(
...
   )
   self.task1 = Task.objects.create(
...
   )
   self.task2 = Task.objects.create(
...
   )
   
   self.data = {
'subject':self.subject.id,
'csrfmiddlewaretoken':csrf._get_new_csrf_key(),
'tip1': 1,
'task_count-0-task': self.task1.id,
'subtotal': 67.00,
'amount': 69.68,
'_continue': 'Save and continue edit',
'task_count-0-id': '',
'task_count-__prefix__-task': '',
'notes': 'example  notes',
'task_count-0-invoice':'',
'task_count-1-num_items': '1',
'invoicenumber': '4',
'task_count-__prefix__-invoice': '',
'adi_end_date': '',
'task_count-MAX_NUM_FORMS': '1000',
'discount': '0',
'dataìe': '25/11/2013',
'task_count-1-id': '',
'adi_start_date': '',
'task_count-1-invoice': '',
'task_count-0-num_items': '1',
'task_count-TOTAL_FORMS': '2',
'task_count-__prefix__-num_items': '1',
'task_count-__prefix__-id': '',
'task_count-INITIAL_FORMS': '0',
'task_count-1-task': self.task2.id,
'expire': ''
   }
   self.form = InvoiceAdminForm(data=self.data)

def test_valid_form(self):
    self.assertTrue(self.form.is_valid(), msg=self.form.errors)
         

the test fails due to the lack of mandatory field 'tasks'. I can't explain this. I've tried to save the form using admin interface, and it worked without errors. Using ipdb debugger, I  saved the data querydict and I used it in the form case. So same data for populating the form, but different results. 

this is the traceback:

    # ./manage.py test gpf2
    Creating test database for alias 'default'...
    ======================================================================
    FAIL: test_valid_form (gpf2.tests.test_forms.InvoiceAdminFormTestCase)
    ----------------------------------------------------------------------
    Traceback (most recent call last):
      File "/data_ext4/src/proj7/gpf2/tests/test_forms.py", line 113, in test_valid_form
self.assertTrue(self.form.is_valid(), msg=self.form.errors)
    AssertionError: <ul class="errorlist"><li>tasks<ul class="errorlist"><li>This field is required..</li></ul></li></ul>

    ----------------------------------------------------------------------
    Ran 13 tests in 0.205s

    FAILED (failures=1)
    Destroying test database for alias 'default'...



Any help on that?

thanks
LuKe
Reply all
Reply to author
Forward
0 new messages