首页 > 解决方案 > 在我将 formset 属性添加到 modelformset_factory() 之前,我的模型表单集工作正常

问题描述

我终于让我的模型表单集工作了。作为最后的调整,我添加了 formset 属性和 BaseFormSet 类来验证用户是否至少完成了 formset 中的表单。我在其他表单集(但不是模型表单集)上做了同样的事情,所以我认为代码可以正常工作。但是它会引发我无法解决的异常。

视图.py:

def reconciliation_action(request,pk):

    ledger = get_object_or_404(Ledger,pk=pk)
    line_items = LineItem.objects.filter(ledger=ledger, reconciliation_date=None).order_by('-journal_entry__date')
    LineItemReconciliationFormSet = modelformset_factory(LineItem, extra=0, fields=('reconciliation_action',), widgets={'reconciliation_action':forms.CheckboxInput()})
    #Following line doesn't work. The formset attribute breaks things.
    #LineItemReconciliationFormSet = modelformset_factory(LineItem, formset=BaseReconciliationFormSet, extra=0, fields=('reconciliation_action',), widgets={'reconciliation_action':forms.CheckboxInput()})
    if request.method == 'POST':
        formset = LineItemReconciliationFormSet(request.POST)
        form = ReconciliationForm(request.POST)
        if formset.is_valid() and form.is_valid():
            formset.save()
            # Count checked boxes for later confirmation message.
            no_of_checkboxes = 0
            for form1 in formset:
                if form1.cleaned_data['reconciliation_action'] == True:
                    no_of_checkboxes += 1
            # If date was set then save it to lineitems
            if form.cleaned_data['date']:
                for line_item in line_items:
                    if line_item.reconciliation_action == True:
                        line_item.reconciliation_date=form.cleaned_data['date']
                        line_item.save()

            if form.cleaned_data['date']:
                messages.success(request, str(no_of_checkboxes)+" items successfully reconciled in "+ledger.name)
                return HttpResponseRedirect(reverse('journal:reconciliation_show_all'))
            else:
                messages.success(request, str(no_of_checkboxes)+" items successfully saved for later reconciliation in "+ledger.name)
                return HttpResponseRedirect(reverse('journal:reconciliation_action', kwargs={'pk': pk}) )
    else:
        formset = LineItemReconciliationFormSet(queryset=line_items) #<-- LINE 55 WHERE THERE ERROR OCCURS!!!!
        form = ReconciliationForm()
    return render(request, 'journal/reconciliation_action.html',{'ledger': ledger, 'line_items': line_items, 'formset': formset, 'form': form,})

表格.py:

# It is used here in order to validate *across* formsets.
class BaseReconciliationFormSet(BaseFormSet):
    def clean(self):
        if any(self.errors):
            # If any forms have errors then don't continue.
            return
        count_checked_boxes = 0
        for form in self.forms:
            if self.can_delete and self._should_delete_form(form):
                #Skips any records that are scheduled for deletion
                continue
            if form.cleaned_data.get('reconciliation_action')== True:
                logger.warning(form.cleaned_data.get('reconciliation_action'))
                count_checked_boxes += 1
        if count_checked_boxes == 0:
            forms.ValidationError('Please select at least one checkbox to reconcile.')

例外:

TypeError at /journal/reconciliation/action/13/
__init__() got an unexpected keyword argument 'queryset'
Request Method: GET
Request URL:    http://localhost/journal/reconciliation/action/13/
Django Version: 3.0
Exception Type: TypeError
Exception Value:    
__init__() got an unexpected keyword argument 'queryset'
Exception Location: C:\Users\Philip\CodeRepos\Acacia2\journal\views.py in reconciliation_action, line 55
Python Executable:  C:\Users\Philip\CodeRepos\Acacia2\venv\Scripts\python.exe
Python Version: 3.8.0
Python Path:    
['C:\\Users\\Philip\\CodeRepos\\Acacia2',
 'C:\\Users\\Philip\\AppData\\Local\\Programs\\Python\\Python38-32\\python38.zip',
 'C:\\Users\\Philip\\AppData\\Local\\Programs\\Python\\Python38-32\\DLLs',
 'C:\\Users\\Philip\\AppData\\Local\\Programs\\Python\\Python38-32\\lib',
 'C:\\Users\\Philip\\AppData\\Local\\Programs\\Python\\Python38-32',
 'C:\\Users\\Philip\\CodeRepos\\Acacia2\\venv',
 'C:\\Users\\Philip\\CodeRepos\\Acacia2\\venv\\lib\\site-packages']
Server time:    Sun, 5 Jan 2020 08:38:35 +0000
Traceback Switch to copy-and-paste view
C:\Users\Philip\CodeRepos\Acacia2\venv\lib\site-packages\django\core\handlers\exception.py in inner
            response = get_response(request) …
▶ Local vars
C:\Users\Philip\CodeRepos\Acacia2\venv\lib\site-packages\django\core\handlers\base.py in _get_response
                response = self.process_exception_by_middleware(e, request) …
▶ Local vars
C:\Users\Philip\CodeRepos\Acacia2\venv\lib\site-packages\django\core\handlers\base.py in _get_response
                response = wrapped_callback(request, *callback_args, **callback_kwargs) …
▶ Local vars
C:\Users\Philip\AppData\Local\Programs\Python\Python38-32\lib\contextlib.py in inner
                return func(*args, **kwds) …
▶ Local vars
C:\Users\Philip\CodeRepos\Acacia2\journal\views.py in reconciliation_action
        formset = LineItemReconciliationFormSet(queryset=line_items) …
▼ Local vars
Variable    Value
LineItemReconciliationFormSet   
<class 'django.forms.formsets.LineItemFormFormSet'>
ledger  
<Ledger: Philip's Credit Card>
line_items  
<QuerySet [<LineItem: LineItem object (335)>, <LineItem: LineItem object (337)>, <LineItem: LineItem object (339)>, <LineItem: LineItem object (341)>, <LineItem: LineItem object (347)>, <LineItem: LineItem object (344)>, <LineItem: LineItem object (345)>, <LineItem: LineItem object (351)>, <LineItem: LineItem object (355)>, <LineItem: LineItem object (365)>, <LineItem: LineItem object (375)>, <LineItem: LineItem object (385)>, <LineItem: LineItem object (383)>, <LineItem: LineItem object (359)>]>
pk  
13
request 
<WSGIRequest: GET '/journal/reconciliation/action/13/'>

标签: djangodjango-forms

解决方案


要使用您的表单集类BaseReconciliationFormSet作为formset参数,modelformset_factory它应该是BaseModelFormSet

class BaseReconciliationFormSet(BaseModelFormSet):
    ...

推荐阅读