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

How to dynamically filter ModelChoice's queryset in a Inlineformset?


I just want to filter select field in a inlineformset.

Scenario:

Every task has own report.Each task has a booking .Booking has several booked items.I want to display only related bookeditems based on booking in report form.Report form is generated using signals and while editing i'm using inlineformset to populate form with instances.

Here is my code :

Models.py

class Task(models.Model):

    booking = models.ForeignKey(
        Booking, blank=False, null=True, related_name='booking_id',)
    ......


class Report(models.Model):

    task = models.ForeignKey(
        Task, blank=True, null=True, related_name='task',)

    hoarding = models.OneToOneField(
        BookedItem, blank=True, null=True, related_name='+')

    status = models.CharField(
        max_length=32, choices=ReportStatus.CHOICES, blank=True, null=True, default=ReportStatus.INCOMPLETE)

views.py

def report(request, pk):
    task_instance = get_object_or_404(Task, pk=pk)
    booking = task_instance.booking_id
    #all bookeditems here
    bookeditems = BookedItem.objects.filter(Booking_id=bookeditem)

     # inline formsetfactory
    ReportFormset = inlineformset_factory(Task,Report,form=TaskReportForm,fields=('hoarding','status',), extra=0,can_delete=False,)
    data = request.POST or None
    formset = ReportFormset(instance=task_instance)
    for form in formset:
                form.fields['hoarding'].queryset = bookeditems.all()

    if request.method == 'POST':
        formset = ReportFormset(request.POST,instance=task_instance)
        if formset.is_valid():
            formset.save
            return redirect('taskreport')
        else:
             formset = ReportFormset(instance=task_instance)    
    else:
        formset = ReportFormset(instance=task_instance)
    return render(request, 'report.html', {'formset': formset,
                                                       'bookeditems': bookeditems,
                                                       'task_instance': task_instance})

forms.py

class TaskReportForm(forms.ModelForm):
    def __init__(self, *args, **kwargs):
        super(TaskReportForm, self).__init__(*args, **kwargs)
    class Meta:
        model = PrinterReport
        fields = ['hoarding','status',]
        exclude = ['printer_task',]

report.html:

<form action="." method="POST">{% csrf_token %}
      {{ formset.management_form }}

           <section id="account" class="nice-padding active">
                              <div class="link-formset">
                                <table class="listing listing-page">
                                          <thead>
                                            {% for form in formset %}
                                                {% if forloop.first %}
                                                    {% for field in form %}
                                                        <th>{{ field.label_tag }}</th>
                                                    {% endfor %}
                                                {% endif %}
                                          </thead>
                                          <tbody>
                                                <tr>
                                                    {% for field in form %}
                                                        <td>{{ field }}</td>
                                                    {% endfor %}
                                                </tr>
                                            {% endfor %}
                                          </tbody>
                                      </table>
                              </div>            

                  </section>

                   <li class="">
                        <input type="submit" value="Save" class="button">
                    </li>

                            </ul>
                        </fieldset>
</form>

I want to display only related bookeditems as choicefield in each report hoarding field .

I tried above code ,but no result.


Solution

  • You define your formset with the name formset and customize the querysets for your fields properly here:

    for form in formset:
        form.fields['hoarding'].queryset = bookeditems.all()
    

    But you then overwrite that formset variable later in your view, removing the effects of that initial logic:

    if request.method == 'POST':
            formset = ReportFormset(request.POST,instance=task_instance)
            if formset.is_valid():
                formset.save
                return redirect('taskreport')
            else:
                 #invaild form, re-render with errors - and no custom querysets
                 formset = ReportFormset(instance=task_instance)    
        else:
            #non-POST request, render form - again overwriting custom querysets
            formset = ReportFormset(instance=task_instance)