Alex
Alex

Reputation: 6037

CreateView use parameters

In my Form I have a dropdown-list projects, which should show some elements based on a certain type, using ModelChoiceField. This query needs some parameter, but how do how can I pass this parameter to the form?

class TaskCreate(CreateView):
    model = Task
    fields = ['name', 'description', 'project']

    def form_valid(self, form):
        return super(TaskCreate, self).form_valid(form)

\

class TaskcreateForm(forms.ModelForm):
    projects = forms.ModelChoiceField(queryset=Project.objects.filter(type=someParameter))
    class Meta:
        model = Task

Upvotes: 1

Views: 2822

Answers (3)

hellsgate
hellsgate

Reputation: 6005

You should use the get_form_kwargs method of the view:

class TaskCreate(CreateView):
    model = Task
    fields = ['name', 'description', 'project']

    def form_valid(self, form):
        return super(TaskCreate, self).form_valid(form)

    def get_form_kwargs(self):
        """
        Returns the keyword arguments for instantiating the form.
        """
        kwargs = super(TaskCreate, self).get_form_kwargs()
        kwargs.update({'my_var': 'my value'})
        return kwargs

And then capture that parameter in the form __init__ method. You also need to set the queryset for the field in the __init__ method:

class TaskcreateForm(forms.ModelForm):
    projects = forms.ModelChoiceField(queryset=Project.objects.none())

    def __init__(self, *args, **kwargs):
        self.my_var = kwargs.pop('my_var')
        super(TaskcreateForm, self).__init__(*args, **kwargs)
        self.fields['projects'].queryset = Project.objects.filter(type=self.my_var))

    class Meta:
        model = Task

You must use kwargs.pop() otherwise the call to super() will raise an error due to the unexpected keyword argument.

CCBV is a great resource for detailing the methods available on all of the generic class-based views.

Upvotes: 2

catavaran
catavaran

Reputation: 45555

You can override the get_form() method of the view. For example if you provide this parameter via the request.GET then the view will be like this:

class TaskCreate(CreateView):
    ...
    def get_form(self, form_class):
        form = super(TaskCreate, self).get_form(form_class)
        form.fields['project'].queryset = Project.objects.filter(
                                               type=self.request.GET['type'])
        return form

And in the form you can set the queryset to none():

class TaskcreateForm(forms.ModelForm):
    projects = forms.ModelChoiceField(queryset=Project.objects.none())
    class Meta:
        model = Task

Upvotes: 1

Hedde van der Heide
Hedde van der Heide

Reputation: 22449

Catavaran's answer is straight forward. Another option could be to add the type to the url pattern (untested syntax)

url(r'^create/(?P<type>[-\w]+)/$', TaskCreate.as_view(), name='create_task')

This way you'll receive the type via kwargs, and you'd still be able to create custom links to certain types using a reverse pattern

{% url 'create_task' type='foo' %}

Don't forget there's a chance you'll get bogus input from the GET param.

Upvotes: 0

Related Questions