Lord Elrond
Lord Elrond

Reputation: 16002

Django how to add an initial value with modelformset_factory?

How can I pass an initial value to Product_Form when using it with modelformset_factory?

This is my attempt:

models.py:

from django.db import models

class Product(models.Model):
    name = models.CharField(max_length=45)
    qty = models.IntegerField()
    price = models.IntegerField()

forms.py:

from django import forms
from .models import Product

class ProductForm(forms.BaseModelFormSet):
    def __init__(self, *args, **kwargs):
    super(Product_Form, self).__init__(*args, **kwargs)

    qty = kwargs.get('qty','')
    print(qty) #prints blank string
    self.queryset = Product.objects.filter(qty=qty)
    class Meta:
        model = Product
        fields = ['name', 'qty', 'price']

views.py:

from django.shortcuts import render
from django.views import View
from django.forms import modelformset_factory
from .forms import Product_Form
from .models import Product

class Inventory(View):
    def __init__(self):
        pass

    def get(self, req):

        product_form = modelformset_factory(Product, fields=('qty','price','name'), 
                       formset=Product_Form) 

        form = product_form(initial=[
             {'qty':0},
        ])
        context = {
            'form':form,
        }
        return render(req, 'base.html', context)

the data I need to pass to it is the result of a Search_Form, (IE user input) which is used to filter the Products query.

When I try to render base.py, I get the following error:

invalid literal for int() with base 10: ''

Which appears to be due to the fact that an empty string is being inserted into Product.objects.filter(qty='')

I am taking most of this code directly from the docs, so I'm really not sure why it isn't working.

What am I missing here?

update

Changing this:

form = product_form(initial=[
     {'qty':0},
])

To this:

form = product_form(qty=0)

yields an error:

init() got an unexpected keyword argument 'qty'

update 2

I modified my code based on bdoubleu's answer, and I get the following error:

Template error:
In template /Users/jane/Code/mu_env/mu/inventory/templates/partials/product_form.html, error at line 2
   __init__() got an unexpected keyword argument 'use_required_attribute'
   1 : <form action="/inventory/update" method="POST" id="search_form"> {% csrf_token %}
   2 :  {{ product_form }} 
   3 : <button>save</button>
   4 : </form>
   5 : 

Traceback:

File "/Users/jane/Code/mu_env/env/lib/python3.7/site-packages/django/core/handlers/exception.py" in inner
  34.             response = get_response(request)

File "/Users/jane/Code/mu_env/env/lib/python3.7/site-packages/django/core/handlers/base.py" in _get_response
  115.                 response = self.process_exception_by_middleware(e, request)

File "/Users/jane/Code/mu_env/env/lib/python3.7/site-packages/django/core/handlers/base.py" in _get_response
  113.                 response = wrapped_callback(request, *callback_args, **callback_kwargs)

File "/Users/jane/Code/mu_env/env/lib/python3.7/site-packages/django/views/generic/base.py" in view
  71.             return self.dispatch(request, *args, **kwargs)

File "/Users/jane/Code/mu_env/env/lib/python3.7/site-packages/django/views/generic/base.py" in dispatch
  97.         return handler(request, *args, **kwargs)

File "/Users/jane/Code/mu_env/mu/inventory/views.py" in get
  31.         return render(req, 'inventory/base.html', context)

File "/Users/jane/Code/mu_env/env/lib/python3.7/site-packages/django/shortcuts.py" in render
  36.     content = loader.render_to_string(template_name, context, request, using=using)

File "/Users/jane/Code/mu_env/env/lib/python3.7/site-packages/django/template/loader.py" in render_to_string
  62.     return template.render(context, request)

File "/Users/jane/Code/mu_env/env/lib/python3.7/site-packages/django/template/backends/django.py" in render
  61.             return self.template.render(context)

File "/Users/jane/Code/mu_env/env/lib/python3.7/site-packages/django/template/base.py" in render
  171.                     return self._render(context)

File "/Users/jane/Code/mu_env/env/lib/python3.7/site-packages/django/template/base.py" in _render
  163.         return self.nodelist.render(context)

File "/Users/jane/Code/mu_env/env/lib/python3.7/site-packages/django/template/base.py" in render
  937.                 bit = node.render_annotated(context)

File "/Users/jane/Code/mu_env/env/lib/python3.7/site-packages/django/template/base.py" in render_annotated
  904.             return self.render(context)

File "/Users/jane/Code/mu_env/env/lib/python3.7/site-packages/django/template/defaulttags.py" in render
  309.                 return nodelist.render(context)

File "/Users/jane/Code/mu_env/env/lib/python3.7/site-packages/django/template/base.py" in render
  937.                 bit = node.render_annotated(context)

File "/Users/jane/Code/mu_env/env/lib/python3.7/site-packages/django/template/base.py" in render_annotated
  904.             return self.render(context)

File "/Users/jane/Code/mu_env/env/lib/python3.7/site-packages/django/template/loader_tags.py" in render
  188.             return template.render(context)

File "/Users/jane/Code/mu_env/env/lib/python3.7/site-packages/django/template/base.py" in render
  173.                 return self._render(context)

File "/Users/jane/Code/mu_env/env/lib/python3.7/site-packages/django/template/base.py" in _render
  163.         return self.nodelist.render(context)

File "/Users/jane/Code/mu_env/env/lib/python3.7/site-packages/django/template/base.py" in render
  937.                 bit = node.render_annotated(context)

File "/Users/jane/Code/mu_env/env/lib/python3.7/site-packages/django/template/base.py" in render_annotated
  904.             return self.render(context)

File "/Users/jane/Code/mu_env/env/lib/python3.7/site-packages/django/template/base.py" in render
  993.         return render_value_in_context(output, context)

File "/Users/jane/Code/mu_env/env/lib/python3.7/site-packages/django/template/base.py" in render_value_in_context
  972.             value = str(value)

File "/Users/jane/Code/mu_env/env/lib/python3.7/site-packages/django/utils/html.py" in <lambda>
  388.     klass.__str__ = lambda self: mark_safe(klass_str(self))

File "/Users/jane/Code/mu_env/env/lib/python3.7/site-packages/django/forms/formsets.py" in __str__
  64.         return self.as_table()

File "/Users/jane/Code/mu_env/env/lib/python3.7/site-packages/django/forms/formsets.py" in as_table
  404.         forms = ' '.join(form.as_table() for form in self)

File "/Users/jane/Code/mu_env/env/lib/python3.7/site-packages/django/forms/formsets.py" in __iter__
  68.         return iter(self.forms)

File "/Users/jane/Code/mu_env/env/lib/python3.7/site-packages/django/utils/functional.py" in __get__
  80.         res = instance.__dict__[self.name] = self.func(instance)

File "/Users/jane/Code/mu_env/env/lib/python3.7/site-packages/django/forms/formsets.py" in forms
  136.                  for i in range(self.total_form_count())]

File "/Users/jane/Code/mu_env/env/lib/python3.7/site-packages/django/forms/formsets.py" in <listcomp>
  136.                  for i in range(self.total_form_count())]

File "/Users/jane/Code/mu_env/env/lib/python3.7/site-packages/django/forms/models.py" in _construct_form
  620.         form = super()._construct_form(i, **kwargs)

File "/Users/jane/Code/mu_env/env/lib/python3.7/site-packages/django/forms/formsets.py" in _construct_form
  172.         form = self.form(**defaults)

File "/Users/jane/Code/mu_env/mu/inventory/forms.py" in __init__
  31.         super(Product_Form, self).__init__(*args, **kwargs)

File "/Users/jane/Code/mu_env/env/lib/python3.7/site-packages/django/forms/models.py" in __init__
  569.         super().__init__(**{'data': data, 'files': files, 'auto_id': auto_id, 'prefix': prefix, **kwargs})

Exception Type: TypeError at /inventory/search
Exception Value: __init__() got an unexpected keyword argument 'use_required_attribute'

Upvotes: 0

Views: 925

Answers (1)

bromosapien
bromosapien

Reputation: 234

The initial keyword argument is for passing initial data to a form, to pass form kwargs to a formset you'll need to use form_kwargs.

form = product_form(form_kwargs={'qty': 0})

It's worth noting for what you're trying to accomplish it's not necessary to pass any extra kwargs to the formset because you can modify the queryset directly.

To do this the ProductForm should be a django Form, not a BaseModelFormset.

forms.py

from django import forms
from .models import Product

class ProductForm(forms.Form):

    class Meta:
        model = Product
        fields = ['name', 'qty', 'price']

ProductFormSet = forms.modelformset_factory(Product, form=ProductForm)

So putting it together in your current view:

from .forms import ProductFormSet

class Inventory(View):
    def get(self, request, *args, **kwargs):
        qty = self.request.GET.get('qty', None)
        qs = Product.objects.all()
        if qty:
            qs = qs.filter(qty=qty)

        form = ProductFormSet(queryset=qs)

        context = {
            'form':form,
        }
        return render(req, 'base.html', context)

Here's an alternate version using FormView:

from django.views.generic import FormView

from .forms import ProductFormSet

class Inventory(FormView):
    form_class = ProductFormSet

    def get_form_kwargs(self)
        kwargs = super().get_form_kwargs()
        qty = self.request.GET.get('qty', None)
        qs = Product.objects.all()
        if qty:
            qs = qs.filter(qty=qty)
        kwargs['queryset'] = qs
        return kwargs

Upvotes: 1

Related Questions