Django — form_valid() принимает 2 позиционных аргумента, но было задано 5 — несколько форм

#django #forms #django-models

#django #формы #django-модели

Вопрос:

Я новичок в использовании Django и хочу сохранить 4 разные формы с помощью CreateView. Я могу сохранить 3 из них:

  • Форма продукта
  • Форма себестоимости продукта
  • Форма цен на товары

Но с формой инвентаризации продукта я получаю эту ошибку: form_valid() принимает 2 позиционных аргумента, но было задано 5.

Форма инвентаризации продукта:

 class ProdInvForm2(ModelForm):


    def __init__(self, *args, **kwargs):

        super().__init__(*args, **kwargs)

        self.helper = FormHelper()
        self.helper.form_tag = False
        self.helper.layout = Layout(
            Row(
                Column('invmax', css_class='form-group col-md-6 mb-0'),
                Column('invmin', css_class='form-group col-md-6 mb-0'),
                css_class='form-row'
            ),
            
        )

    class Meta:
        model = ProdInv
        # fields = ('invmin', 'invmax')
        widgets = {
            
            'invmax': NumberInput(
                attrs={
                    'placeholder': 'Inventario Maximo',
                }
            ),
            'invmin': NumberInput(
                attrs={
                    'placeholder': 'Inventario Minimo',
                }
            ),

        }
        # esto es para excluir campos que no quieres que aparezcan
        #, 'invact', 'invord', 'invres'
        exclude = ['user_updated', 'user_creation', 'prod', 'invact', 'invord', 'invres']
 

Модели инвентаризации продуктов:

 class ProdInv(BaseModel):
    prod = models.ForeignKey(Product, on_delete=models.CASCADE, verbose_name='Producto')
    invact = models.IntegerField(default=0, null=True, blank=True, verbose_name='Inventario Actual')
    invres = models.IntegerField(default=0, null=True, blank=True, verbose_name='Inventario Reservado')
    invord = models.IntegerField(default=0, null=True, blank=True, verbose_name='Inventario Ordenado')
    invmax = models.IntegerField(default=0, blank=True, verbose_name='Inventario Maximo')
    invmin = models.IntegerField(default=0, blank=True, verbose_name='Inventario Minimo')


    def toJSON(self):
        item = model_to_dict(self, exclude=['user_creation', 'user_updated'])
        item['prod'] = self.prod.toJSON()
        return item

    def __str__(self):
        return self.prod.name
    

    class Meta:
        verbose_name = 'Inventario de Producto'
        verbose_name_plural = 'Inventario de Productos'
        ordering = ['id']
 

CreateView:

 class ProductCreateView(LoginRequiredMixin, ValidatePermissionRequiredMixin, CreateView):
    model = Product
    form_class = ProductForm
    template_name = 'product/create.html'
    success_url = reverse_lazy('erpInv:product_list')
    permission_required = 'erpAdm.add_product'
    url_redirect = success_url

    @method_decorator(csrf_exempt)
    def dispatch(self, request, *args, **kwargs):
        return super().dispatch(request, *args, **kwargs)

    

    def post(self, request, *args, **kwargs):
        data = {}

        try:
            action = request.POST['action']
            if action == 'add':

                AttrValueFormSet = formset_factory(AttrValueForm, can_delete=True, extra=1)
                formprod = ProductForm(request.POST)
                formcost = ProdCostForm(request.POST)
                formprice = ProdPriceForm(request.POST)
                formprodinv = ProdInvForm2(request.POST)
                AV_formset = AttrValueFormSet(request.POST)
               
                with transaction.atomic():
                    if formprod.is_valid() and formcost.is_valid() and formprice.is_valid() 
                            and formprodinv.is_valid():

                        return self.form_valid(formprod, formcost, formprice, formprodinv)
                    else:
                        return self.form_invalid(formprod, formcost, formprice, formprodinv)

            else:
                data['error'] = 'No ha ingresado a ninguna opción'
        except Exception as e:
            data['error'] = str(e)
            # acuerdate cuando es coleccion de elementos, hay que serializar con safe=flase
        return JsonResponse(data, safe=False)

    def form_valid(self, formprod, formcost, formprice, formprodinv):

        # hubo que cmentar e save del form, para que funcione el save()
        with transaction.atomic():
            prod = formprod.save(commit=True)
            print(prod.pk)
            price = formprice.save(commit=False)
            price.prod_id = prod.pk
            cost = formcost.save(commit=False)
            cost.prod_id = prod.pk
            print(cost)
            inv = formprodinv.save(commit=False)
            inv.prod_id = prod.pk
            print(inv)
            inv.save()
            cost.save()
            price.save()

        return super().form_valid(formprod, formcost, formprice, formprodinv)

    def form_invalid(self, formprod, formcost, formprice, formprodinv):

        return self.render_to_response(
            self.get_context_data(formprod=formprod.errors, formcost=formcost.errors, formprice=formprice.errors,
                                  formprodinv=formprodinv.errors))

        # Dont Know which one to use as return statement

        # return super().form_invalid(formprod=formprod.errors, formcost=formcost.errors, formprice=formprice.errors,
        #                       formprodinv=formprodinv.errors)

    def get_context_data(self, **kwargs):
        # AVForm = AttrValueForm(prefix='avprefix')
        AttrValueFormSet = formset_factory(AttrValueForm, can_delete=True, extra=1)
        context = super().get_context_data(**kwargs)
        context['title'] = 'Creación un Producto'
        context['entity'] = 'Productos'
        context['list_url'] = self.success_url
        context['action'] = 'add'
        context['formcost'] = ProdCostForm()
        context['formprice'] = ProdPriceForm(prefix='precio')
        context['formprodinv'] = ProdInvForm2(prefix='invent')

        # Next step try to use formset to save product attributes
        # context['AV_formset'] = AttrValueFormSet(prefix='avprefix')
        # context['avHelper'] = AVHelper()
        return context
 

Я выполнил тест и прокомментировал «transaction.atomic()». Я смог сохранить в другие формы, но не знаю, почему у меня возникла эта проблема с формой инвентаризации товара.

Надеюсь, кто-нибудь сможет указать, что я делаю неправильно.

Приветствия и счастливого Нового года

Комментарии:

1. return super().form_valid(formprod, formcost, formprice, formprodinv) не имеет особого смысла, поскольку база form_valid принимает один параметр: форму, но только одну форму.

2. @WillemVanOnsem Я взял это в качестве ссылки из другого сообщения в StackOverflow, о сохранении кратной формы с помощью createview. Но они использовали только 2 формы.

Ответ №1:

Чтобы решить мою проблему, я сохранил формы внутри de def POST. Вместо того, чтобы использовать form_valid().

def post(self, request, * args, **kwargs): data = {}

 try:
    action = request.POST['action']
    if action == 'add':

        AttrValueFormSet = formset_factory(AttrValueForm, can_delete=True, extra=1)
        formprod = ProductForm(request.POST)
        formcost = ProdCostForm(request.POST)
        formprice = ProdPriceForm(request.POST)
        formprodinv = ProdInvForm2(request.POST)
        AV_formset = AttrValueFormSet(request.POST)
        

        with transaction.atomic():
            if formprod.is_valid() and formcost.is_valid() and formprice.is_valid() and formprodinv.is_valid():
                print('los form son validos')

                
                prod = formprod.save(commit=True)
                print(prod.pk)
                
                price = formprice.save(commit=False)
                print('precio')
                print(formprice.cleaned_data)
                price.prod_id = prod.pk
                

                cost = formcost.save(commit=False)
                print('costo')
                cost.prod_id = prod.pk

                inv = formprodinv.save(commit=False)
                print('Inventario')
                print(formprodinv.cleaned_data)
                

                inv.prod_id = prod.pk
                
                inv.save()

                cost.save()
                price.save()

           
            else:
                print('los forms NO son validos')
                return formprod.errors, formprice.errors, formcost.errors, formprodinv.errors


    else:
        data['error'] = 'No ha ingresado a ninguna opción'
except Exception as e:
    data['error'] = str(e)
    # acuerdate cuandp es coleccion de elementos, hay que serializar con safe=flase
return JsonResponse(data, safe=False)