Question

I have a weird error, when submitting a form. When calling the method form.is_valid() the stack runs down until some of the built-in code tries to access an attribute, that isn't precent... I do not understand where the problem comes from. I simply run

mform = InvAddMainForm(request.POST)
    if mform.is_valid():
        ...

as I've done several times on other forms without trouble. Any idea what could cause this?

EDIT: The form in question looks like this:

class InvAddMainForm(ModelForm):
    class Meta:
        model = Maintenance
        fields = ('serial','end','discount','vat')
    def __init__(self, *args, **kwargs):
        super(InvAddMainForm, self).__init__(*args, **kwargs)
        # The queryset of the field 'serial' is set to None here, as it is
        # Derived from the context
        self.fields['serial'] = SelectMaintenanceSerialField(required=True, queryset=None)
        self.fields['serial'].empty_label = None
        self.fields['end'].initial = Option.objects.get(pk='enddate').value
        self.fields['vat'].empty_label = None
        self.fields['vat'].queryset = Vat.objects.filter(disabled=False).order_by('name')

the relevant parts of the view look like this:

if 'addmain' in request.POST:
        mform = InvAddMainForm(request.POST)
        print str(mform)
        if mform.is_valid():
            mf = mform.save(commit=False)
            it = mf.serial

            if it.disabled:
                raise Exception('Cannot buy maintenance to disabled license')

            # check if maintenance for given item already is on invoice
            if Maintenance.objects.filter(invoice=inv, serial=it):
                raise Exception('Item already has maintenance on draft')

            startdate = None

            # continue maintenance
            latest = it.latest_main()
            if latest:
                startdate = latest.end

            # if maintenance date used, add one day
            if startdate:
                startdate += timedelta(days=1)

            if not startdate:
                startdate = it.pdate

            if not startdate:
                itinv = it.invoice()
                if itinv:
                    startdate = itinv.idate

            # otherwise use quote date
            if not startdate:
                ii = ItemInv.objects.filter(invoice=inv, item=it)
                if ii:
                    startdate = inv.qdate

            if not startdate:
                raise Exception('Could not determine start date')

            if startdate > mf.end:
                raise Exception("Start date after end date")

            # add back maintenance
            if startdate < inv.qdate:
                back = Maintenance(serial = mf.serial,
                                   invoice = inv,
                                   back = True,
                                   start = startdate,
                                   end = inv.qdate,
                                   price = it.prod.prodprice_set.get(cur=inv.cur).bmprice,
                                   discount = mf.discount,
                                   vat = mf.vat,
                                   parent = latest)
                latest = back.save()
                startdate = inv.qdate

            nm = Maintenance(serial = it,
                             invoice = inv,
                             start = startdate,
                             end = mf.end,
                             price = it.prod.prodprice_set.get(cur=inv.cur).mprice,
                             discount = mf.discount,
                             vat = mf.vat,
                             parent = latest)
            nm.save()
            updateinvoice(inv.iid)
            return redirect('invoice.invoice.invoice', inv.iid)
else:
        mform = InvAddMainForm()
    # vat = null AND pdate = null, license imported and removed
    mform.fields['serial'].queryset = Item.objects.filter(
                                                          account__in=cust_acc
                                                          ).exclude(
                                                                    prod__in=Product.objects.filter(prodprice__mprice__exact=0, prodprice__cur=inv.cur)
                                                                    ).exclude(
                                                                              disabled=True
                                                                              ).exclude(
                                                                                        vat__isnull=True,
                                                                                        pdate__isnull=True
                                                                                        )
    mform.fields['discount'].initial = def_discount
    mform.fields['vat'].initial = Vat.objects.get(name=calcVAT(inv.customer.main_address.country.cc, inv.customer.vatnr, 'PTS'), disabled=False)
...

The Template simply calls form.as_table()... No magics there...

the traceback looks as follows:

AttributeError at /invoice/10013/
'NoneType' object has no attribute 'model'
Request Method: POST
Request URL:    http://127.0.0.1:8000/invoice/10013/
Django Version: 1.3.1
Exception Type: AttributeError
Exception Value:    
'NoneType' object has no attribute 'model'
Exception Location: /usr/lib/python2.7/dist-packages/django/forms/models.py in to_python, line 973
Python Executable:  /usr/bin/python
Python Version: 2.7.3
Python Path:    
['/home/ruben/mnt/derby/v2',
 '/usr/lib/python2.7',
 '/usr/lib/python2.7/plat-linux2',
 '/usr/lib/python2.7/lib-tk',
 '/usr/lib/python2.7/lib-old',
 '/usr/lib/python2.7/lib-dynload',
 '/usr/local/lib/python2.7/dist-packages',
 '/usr/lib/python2.7/dist-packages',
 '/usr/lib/python2.7/dist-packages/PIL',
 '/usr/lib/python2.7/dist-packages/gst-0.10',
 '/usr/lib/python2.7/dist-packages/gtk-2.0',
 '/usr/lib/python2.7/dist-packages/ubuntu-sso-client',
 '/usr/lib/python2.7/dist-packages/ubuntuone-client',
 '/usr/lib/python2.7/dist-packages/ubuntuone-control-panel',
 '/usr/lib/python2.7/dist-packages/ubuntuone-couch',
 '/usr/lib/python2.7/dist-packages/ubuntuone-installer',
 '/usr/lib/python2.7/dist-packages/ubuntuone-storage-protocol']
Server time:    Wed, 22 Aug 2012 14:13:06 +0200
Traceback Switch to copy-and-paste view

/usr/lib/python2.7/dist-packages/django/core/handlers/base.py in get_response
                        response = callback(request, *callback_args, **callback_kwargs) ...
▶ Local vars
/usr/lib/python2.7/dist-packages/django/db/transaction.py in inner
                res = func(*args, **kwargs) ...
▶ Local vars
/home/ruben/mnt/derby/v2/invoice/invoice.py in invoice
        print str(mform) ...
▶ Local vars
/usr/lib/python2.7/dist-packages/django/utils/encoding.py in __str__
        return self.__unicode__().encode('utf-8') ...
▶ Local vars
/usr/lib/python2.7/dist-packages/django/forms/forms.py in __unicode__
        return self.as_table() ...
▶ Local vars
/usr/lib/python2.7/dist-packages/django/forms/forms.py in as_table
            errors_on_separate_row = False) ...
▶ Local vars
/usr/lib/python2.7/dist-packages/django/forms/forms.py in _html_output
        top_errors = self.non_field_errors() # Errors that should be displayed above all fields. ...
▶ Local vars
/usr/lib/python2.7/dist-packages/django/forms/forms.py in non_field_errors
        return self.errors.get(NON_FIELD_ERRORS, self.error_class()) ...
▶ Local vars
/usr/lib/python2.7/dist-packages/django/forms/forms.py in _get_errors
            self.full_clean() ...
▶ Local vars
/usr/lib/python2.7/dist-packages/django/forms/forms.py in full_clean
        self._clean_fields() ...
▶ Local vars
/usr/lib/python2.7/dist-packages/django/forms/forms.py in _clean_fields
                    value = field.clean(value) ...
▶ Local vars
/usr/lib/python2.7/dist-packages/django/forms/fields.py in clean
    def clean(self, value):
        """
        Validates the given value and returns its "cleaned" value as an
        appropriate Python object.
        Raises ValidationError for any errors.
        """
        value = self.to_python(value) ...
        self.validate(value)
        self.run_validators(value)
        return value
    def bound_data(self, data, initial):
        """
▶ Local vars
/usr/lib/python2.7/dist-packages/django/forms/models.py in to_python
    def to_python(self, value):
        if value in EMPTY_VALUES:
            return None
        try:
            key = self.to_field_name or 'pk'
            value = self.queryset.get(**{key: value})
        except (ValueError, self.queryset.model.DoesNotExist): ...
            raise ValidationError(self.error_messages['invalid_choice'])
        return value
    def validate(self, value):
        return Field.validate(self, value)
▼ Local vars
Variable    Value
self    
<invoice.forms.SelectMaintenanceSerialField object at 0x7f14c83dc250>
value   
u'100035'
key 
'pk'

I'm getting confused in the last bit, where the built-in code doesn't work

EDIT: Now, I've found the problem, but not the cause... I use a custom made form field for the form. The field is called SelectMaintenanceSerialField. When i use the default field, everythin works fine. The code for the custom field looks like this:

class SelectMaintenanceSerialField(ModelChoiceField):
    '''
    When adding maintenance to a product on a draft; formerly,
    only the serial of the product was shown. This field allows
    for a custom label for that form
    '''
    def label_from_instance(self, obj):
        '''
        This method sets the label for each of the objects of the queryset
        '''
        item = Item.objects.get(pk=str(obj.serial))
        name = item.prod.name
        return "%s, %s"%(str(obj.serial), str(name))

Either something is wrong with this form, or something needs to be added. The form is displayed as intended, when rendering the template, but apparantly wont work when submitting data

Was it helpful?

Solution

I'm sorry to have bothered you... I just found the problem... The custom field is made with an empty queryset, since the queryset can only be determined when the view is evaluated. I had forgotten to edit the queryset, when an instance of the form is created from the FORM data. Now it works as intended

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top