Django ModelForms - 使用中间模型测试具有M2M内联实例的模型

时间:2013-12-25 18:11:54

标签: python django django-forms django-admin django-testing

我有发票/估计django app,我需要为它编写测试。由于我是初学者,测试表格对我来说很难。 这是代码 - 适用于模型,表单和管理员:

# 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):
        ...

我正在尝试测试InvoiceAdminForm。这是测试代码:

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)

由于缺少必填字段“任务”,测试失败。我无法解释这一点。我试图使用管理界面保存表单,它没有错误地工作。使用ipdb调试器,我保存了数据querydict,并在表单中使用了它。因此填充表单的数据相同,但结果不同。

这是追溯:

# ./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'...

对此有何帮助?

感谢

1 个答案:

答案 0 :(得分:0)

您正在使用内联来编辑相关任务,因此管理员会从您的表单中删除tasks字段。如果您使用管理员之外的表单,tasks字段仍然存在,因此您需要提供值。或者,您可以在表单的fields选项中明确指定Meta,但不包括tasks字段。

管理员为其使用生成了不同的表单,看看这个,请尝试:

from django.test import RequestFactory
from django.contrib.auth.models import User
from django.contrib import admin

# import InvoiceAdmin and Invoice here...

rf = RequestFactory()
user = User.objects.get(username="a_user_with_sufficient_permissions")
request = rf.get("/admin/foo/")
request.user = user
a = InvoiceAdmin(Invoice, admin.site)
print a.get_form(request).Meta.fields  # the form as modified by the admin
print a.form.Meta.fields  # the form as specified by you