1

I'm using django extra views:

# views.py
from django.forms.models import inlineformset_factory
from extra_views import (CreateWithInlinesView, UpdateWithInlinesView,
                        InlineFormSet, )

class LinkInline(InlineFormSet):
    model = Link
    form = LinkForm
    extra = 1

    def get_form(self):
        return LinkForm({})

    def get_formset(self):
        return inlineformset_factory(self.model, self.get_inline_model(), form=LinkForm, **self.get_factory_kwargs())

class TargetCreateView(BaseSingleClient, CreateWithInlinesView):
    model = Target
    form_class = TargetForm
    inlines = [LinkInline, ]
    template_name = 'clients/target_form.html'

I want this 'keywords' field to change based on the pk I pass to the view through the url.

# forms.py
class LinkForm(forms.ModelForm):
    keywords = forms.ModelMultipleChoiceField(queryset=ClientKeyword.objects.filter(client__pk=1))

    class Meta:
        model = Link

I could manage to overwrite the form's init, however:

  1. I don't have access to self.kwargs inside LinkInline

  2. Even if I did, I'm not sure I can pass an instantiated form to inlineformset_factory()

la_f0ka
  • 1,773
  • 3
  • 23
  • 44
  • Since you have the pk ahead of time, have you considered using curry to pass in the pk to the form? – Brandon Taylor Jan 24 '13 at 15:35
  • I added the code to how I managed to do this in the answers, but I'm interested... not even sure what's curry – la_f0ka Jan 24 '13 at 15:37
  • When I need to pass a value to a form I'm using in a formset, I use curry: `from django.utils.functional import curry` MyFormset.form = staticmethod(curry(MyForm, pk=pk)) The form would need to accept a kwarg of `pk` in this example. – Brandon Taylor Jan 24 '13 at 15:41
  • Oh,... something like this: http://stackoverflow.com/questions/622982/django-passing-custom-form-parameters-to-formset . the problem is that I can only get the pk from within the TargetCreateView. If I had it in LinkInline I might be able to return `inlineformset_factory(self.model, self.get_inline_model(), form=curry(LinkForm, pk=pk), **self.get_factory_kwargs())` from get_formset(), but since it's not there I don't know how it would work – la_f0ka Jan 24 '13 at 15:55
  • Yeah. I'd have to take a look at the view class to see where it might be able to be applied. – Brandon Taylor Jan 24 '13 at 16:16
  • 1
    FYI, Extra Views has the currying trick built-in (see these lines: https://github.com/AndrewIngram/django-extra-views/blob/master/extra_views/formsets.py#L56-L67), so the issue is simply that the views kwargs aren't being passed to the inline, which should be relatively simple to introduce. I just need to make sure there's no nasty backwards compatibility issues. I can also pass the view object through too, so you don't have to redo any work you've already handled in the view. – Andrew Ingram Jan 25 '13 at 00:21
  • I've created an issue for it here: https://github.com/AndrewIngram/django-extra-views/issues/35 – Andrew Ingram Jan 25 '13 at 00:25

1 Answers1

3

Ok, if any poor soul needs an answer to how to accomplish this... I managed to do it by overwriting construct_inlines() (which is part of extra_views.advanced.ModelFormWithInlinesMixin) and modifying the field's queryset there.

class TargetCreateView(BaseSingleClient, CreateWithInlinesView):
    model = Target
    form_class = TargetForm
    inlines = [LinkInline, ]
    template_name = 'clients/target_form.html'

    def construct_inlines(self):
        '''I need to overwrite this method in order to change
        the queryset for the "keywords" field'''
        inline_formsets = super(TargetCreateView, self).construct_inlines()
        inline_formsets[0].forms[0].fields[
                'keywords'].queryset = ClientKeyword.objects.filter(
                        client__pk=self.kwargs['pk'])
        return inline_formsets

    def forms_valid(self, form, inlines):
        context_data = self.get_context_data()
        # We need the client instance
        client = context_data['client_obj']
        # And the cleaned_data from the form
        data = form.cleaned_data
        self.object = self.model(
                client=client,
                budget=data['budget'],
                month=data['month']
        )
        self.object.save()
        for formset in inlines:
            f_cd = formset.cleaned_data[0]
            print self.object.pk
            link = Link(client=client,
                    target=self.object,
                    link_type=f_cd['link_type'],
                    month=self.object.month,
                    status='PEN',
            )
            # save the object so we can add the M2M fields
            link.save()
            for kw in f_cd['keywords'].all():
                link.keywords.add(kw)
        return HttpResponseRedirect(self.get_success_url())
la_f0ka
  • 1,773
  • 3
  • 23
  • 44