首页 > 解决方案 > Django postgres SplitArrayField 在提交表单时抛出错误

问题描述

我是 django 的新手,发现自己有点卡在一些东西上。

我正在尝试实现一个提供如下表格的页面:



     Days of the month
   ------------->
  |                 +--------+-+-+-+    +--+--+
  |                 |Employee|1|2|3|    |30|31|
  |names            +--------+-+-+-+    +--+--+----------+
  |                 |Name1   |0|0|8|....| 8| 8|SAVEBUTTON|
  \/                +--------+-+-+-+    +--+--+----------+

每个单元格作为输入字段。

也可以随意提出一个更好的实现,我是一个 django(一般来说)新手,并且在我使用它时正在学习。

这是我尝试从我的视图中保存数据时遇到的错误:

File "/usr/local/lib/python3.8/site-packages/django/forms/forms.py", line 443, in changed_data

initial_value = field.to_python(hidden_widget.value_from_datadict(

File "/usr/local/lib/python3.8/site-packages/django/contrib/postgres/forms/array.py", line 195, in to_python

return [self.base_field.to_python(item) for item in value]

File "/usr/local/lib/python3.8/site-packages/django/contrib/postgres/forms/array.py", line 195, in <listcomp>

return [self.base_field.to_python(item) for item in value]

TypeError: to_python() missing 1 required positional argument: 'value'

django 管理页面上的一个不同但类似的错误:

File "/usr/local/lib/python3.8/site-packages/django/forms/forms.py", line 177, in is_valid

return self.is_bound and not self.errors

File "/usr/local/lib/python3.8/site-packages/django/forms/forms.py", line 172, in errors

self.full_clean()

File "/usr/local/lib/python3.8/site-packages/django/forms/forms.py", line 374, in full_clean

self._clean_fields()

File "/usr/local/lib/python3.8/site-packages/django/forms/forms.py", line 392, in _clean_fields

value = field.clean(value)

File "/usr/local/lib/python3.8/site-packages/django/contrib/postgres/forms/array.py", line 206, in clean

cleaned_data.append(self.base_field.clean(item))

TypeError: clean() missing 1 required positional argument: 'value'

相关models.py部分:

class DayField(forms.IntegerField):
    widget=forms.NumberInput(attrs={'max': 24, 'min':0, 'size':2, 'maxlength':2,
        'style':'width: 40px; -webkit-appearance: none; -moz-appearance: textfield;',
        'oninput':"this.value=this.value.replace(/[^0-9]/g,''); if (this.value.length > this.maxLength) this.value = this.value.slice(0, this.maxLength);",
        'class':'mr-2 form-control'
        })

    def to_python(self, value):
        ### copied from django/forms/fields.py
        """
        Validate that int() can be called on the input. Return the result
        of int() or None for empty values.
        """
        value = super().to_python(value)
        if value in self.empty_values:
            return None
        if self.localize:
            value = formats.sanitize_separators(value)
        # Strip trailing decimal and zeros.
        try:
            value = int(self.re_decimal.sub('', str(value)))
        except (ValueError, TypeError):
            raise ValidationError(self.error_messages['invalid'], code='invalid')
        return value

    def clean(self, value):
        value = self.to_python(value)
        self.validate(value)
        self.run_validators(value)
        return value

class MyArrayField(ArrayField):
    # https://gist.github.com/danni/f55c4ce19598b2b345ef

    def formfield(self, **kwargs):
        defaults = {
            'form_class': pforms.SplitArrayField,
            'base_field': DayField,
            'size': 31,
            'remove_trailing_nulls': True,
        }
        defaults.update(kwargs)

        return super(ArrayField, self).formfield(**defaults)
    
    def to_python(self, value):
        res = super().to_python(value)
        if isinstance(res, list):
            value = [self.base_field.to_python(val) for val in res]
        return value

class Attendance(models.Model):
    employee = models.ForeignKey(Employee, on_delete=models.CASCADE,verbose_name=_("employee"))
    ref_date = models.DateField(verbose_name=_("date"))
    attendance = MyArrayField(models.SmallIntegerField(), default=zeroes, size=31, verbose_name=_('attendance'))

    def __str__(self):
        return '%s' %(date_filter(self.ref_date, 'F Y'))

    class Meta:
        verbose_name = "Presenze"
        verbose_name_plural = "Presenze"

视图.py

from django.shortcuts import render, get_object_or_404
from .models import *
from datetime import date
from django.forms import modelformset_factory
from .forms import *

def month_attendees(request, company_id, year, month):
    message = ''
    company = get_object_or_404(Company, pk=company_id)
    months = Attendance.objects.filter(ref_date__gte=date(year, month, 1), 
                                    ref_date__lt=date(year, month+1, 1),
                                    employee__company=company,
                                    )
    AttendanceFormSet = modelformset_factory(Attendance, fields=('attendance',), max_num=len(months))

    if request.method == 'POST':
        formset = AttendanceFormSet(data=request.POST)
        if formset.is_valid():
            print(formset.changed_objects)
            formset.save()
            message = "Saved"
    else:
        formset= AttendanceFormSet(queryset=months)

    context = {'months':months, 'message':message, 'formset':formset}
    return render(request, 'formazione/month_attendees.html', context)

month_attendees.html

<form method="post" class="form-inline">
  {% csrf_token %}
  {{ formset }}
  <input type="submit" value="Save" class="btn btn-primary">
</form>

标签: pythondjangopostgresqlforms

解决方案


推荐阅读