Wednesday, December 25, 2013

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

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

--
You received this message because you are subscribed to the Google Groups "Django users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to django-users+unsubscribe@googlegroups.com.
To post to this group, send email to django-users@googlegroups.com.
Visit this group at http://groups.google.com/group/django-users.
To view this discussion on the web visit https://groups.google.com/d/msgid/django-users/d744f153-f89a-47bd-b9f7-149e568af760%40googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.

No comments:

Post a Comment