Search code examples
djangodjango-modelsdjango-formsdjango-viewsinline-formset

Django inlineformset_factory with queryset


I need to filter foreignkey select options on a form based on an object id passed by a view. I have the following view:

@login_required()
def QAView(request, equipamento_id):
    form = ActividadeForm()
    equipamento = Equipamento.objects.get(id=equipamento_id)
    testes_list = Teste.objects.filter(equipamento=equipamento_id)  
    form1 = inlineformset_factory(
              Actividade, Resultado, form=ResultadoForm, 
              exclude=('actividade',), extra=len(testes_list))

    context = {'equipamento_id': equipamento_id, 
               'data':datetime.now(), 'equipamento': equipamento, 
               'form': form, 'testes_list': testes_list, 
               'form1': form1}
    template = 'SFM/Equipamento/QA.html'
    return render(request, template, context)

Here are my forms:

class ActividadeForm(forms.ModelForm):      
    class Meta:
        model = Actividade
        fields = ['tipo']
        exclude = ['conclusoes']


class ResultadoForm(forms.ModelForm):
    frequencia = forms.CharField(max_length=50)
    tolerancia = forms.CharField(max_length=255)
    #def __init__(self, equipamento_id, *args, **kwargs):
        #super (ResultadoForm,self ).__init__(*args,**kwargs)
        #self.fields['teste'].queryset = Teste.objects.filter(equipamento=equipamento_id)
    class Meta:
        model = Resultado
        exclude = ['actividade']

This passes all the testes (which is a foreignkey to Teste Model) to the form. What I need is to query this foreignkey to get only the testes related to equipamento_id given by the view. Teste has a manytomany relation to Equipamento. If I do:

form1 = inlineformset_factory(Actividade, Resultado, form=ResultadoForm(equipamento_id), exclude=('actividade',), extra=len(testes_list))

and define init method commented in ResultadoForm, I get the following error:

Traceback:

File "C:\Users\i11931\Programas\Python3.5.1\lib\site-packages\django-1.9-py3.5.egg\django\core\handlers\base.py" in get_response
  149.                     response = self.process_exception_by_middleware(e, request)

File "C:\Users\i11931\Programas\Python3.5.1\lib\site-packages\django-1.9-py3.5.egg\django\core\handlers\base.py" in get_response
  147.                     response = wrapped_callback(request, *callback_args, **callback_kwargs)

File "C:\Users\i11931\Programas\Python3.5.1\lib\site-packages\django-1.9-py3.5.egg\django\contrib\auth\decorators.py" in _wrapped_view
  23.                 return view_func(request, *args, **kwargs)

File "C:\Users\i11931\Documents\DjangoProjects\IPO\SFM\views.py" in QAView
  37.       exclude=('actividade',), extra=len(testes_list))

File "C:\Users\i11931\Programas\Python3.5.1\lib\site-packages\django-1.9-py3.5.egg\django\forms\models.py" in inlineformset_factory
  1049.     FormSet = modelformset_factory(model, **kwargs)

File "C:\Users\i11931\Programas\Python3.5.1\lib\site-packages\django-1.9-py3.5.egg\django\forms\models.py" in modelformset_factory
  847.                              error_messages=error_messages, field_classes=field_classes)

File "C:\Users\i11931\Programas\Python3.5.1\lib\site-packages\django-1.9-py3.5.egg\django\forms\models.py" in modelform_factory
  545.     return type(form)(class_name, (form,), form_class_attrs)

File "C:\Users\i11931\Documents\DjangoProjects\IPO\SFM\forms.py" in __init__
  23.       self.fields['teste'].queryset = Teste.objects.filter(equipamento=equipamento_id)

File "C:\Users\i11931\Programas\Python3.5.1\lib\site-packages\django-1.9-py3.5.egg\django\db\models\manager.py" in manager_method
  122.                 return getattr(self.get_queryset(), name)(*args, **kwargs)

File "C:\Users\i11931\Programas\Python3.5.1\lib\site-packages\django-1.9-py3.5.egg\django\db\models\query.py" in filter
  790.         return self._filter_or_exclude(False, *args, **kwargs)

File "C:\Users\i11931\Programas\Python3.5.1\lib\site-packages\django-1.9-py3.5.egg\django\db\models\query.py" in _filter_or_exclude
  808.             clone.query.add_q(Q(*args, **kwargs))

File "C:\Users\i11931\Programas\Python3.5.1\lib\site-packages\django-1.9-py3.5.egg\django\db\models\sql\query.py" in add_q
  1243.         clause, _ = self._add_q(q_object, self.used_aliases)

File "C:\Users\i11931\Programas\Python3.5.1\lib\site-packages\django-1.9-py3.5.egg\django\db\models\sql\query.py" in _add_q
  1269.                     allow_joins=allow_joins, split_subq=split_subq,

File "C:\Users\i11931\Programas\Python3.5.1\lib\site-packages\django-1.9-py3.5.egg\django\db\models\sql\query.py" in build_filter
  1199.             condition = lookup_class(lhs, value)

File "C:\Users\i11931\Programas\Python3.5.1\lib\site-packages\django-1.9-py3.5.egg\django\db\models\lookups.py" in __init__
  19.         self.rhs = self.get_prep_lookup()

File "C:\Users\i11931\Programas\Python3.5.1\lib\site-packages\django-1.9-py3.5.egg\django\db\models\fields\related_lookups.py" in get_prep_lookup
  98.                     self.lookup_name, self.rhs)

File "C:\Users\i11931\Programas\Python3.5.1\lib\site-packages\django-1.9-py3.5.egg\django\db\models\fields\__init__.py" in get_prep_lookup
  744.             return self.get_prep_value(value)

File "C:\Users\i11931\Programas\Python3.5.1\lib\site-packages\django-1.9-py3.5.egg\django\db\models\fields\__init__.py" in get_prep_value
  976.         return int(value)

Exception Type: ValueError at /SFM/Equipamento/6/QA/
Exception Value: invalid literal for int() with base 10: 'ResultadoForm'

But if I replace form1 by:

form1 = ResultadoForm(equipamento_id)

I am able to filter the testes related to that equipamento_id but I cannot create the inline relations. Why is this? How can I pass that equipamento_id to the inlineformset in order to make a queryset?? Please Help...


Solution

  • Here's the problem

     return type(form)(class_name, (form,), form_class_attrs)
    

    This is where your form is initialized. The first parameter that is passed to the __init__ method of your form is the class name of the form a String. However your __init__ looks like this

    def __init__(self, equipamento_id, *args, **kwargs):
        super (ResultadoForm,self ).__init__(*args,**kwargs)
        self.fields['teste'].queryset = Teste.objects.filter(equipamento=equipamento_id)
    

    The first parameter here is equipamento_id and that's assigned 'ResultadoForm' but you are using it as an integer in the next line in the query filter. Hence the error. Looking at the source code for modelform_factory it isn't clear how you an actually pass equipamento_id as a parameter via inlineformset_factory.

    you will have to try something like

     equipamento_id = kwargs.pop('equipamento_id')
    

    But I am unsure how this can be sent through inlineform_set.