9

I'm trying to filter a model with get_queryset() and it seems to work in the view but not in the template.

My view :

class FolderCreate(CreateView):
    fields = ['name', 'parent']
    template_name = 'Form/folder_create.html'

    def get_queryset(self):
        folders = Folder.objects.filter(owner=self.request.user) 
        print folders # ==> return [<Folder: Folder>, <Folder: Another folder>]
        return folders

    def form_valid(self, form):
        self.object = form.save(commit=False)
        self.object.owner = self.request.user
        return super(FolderCreate, self).form_valid(form)

    def get_initial(self):
        if self.request.method == 'GET':
            foldersUrl = self.request.META['HTTP_REFERER'].split('/')
            foldersUrl.pop()
            folder = urllib2.unquote(foldersUrl[-1])

            try:
                return {'parent' : Folder.objects.get(name=folder, owner=self.request.user)}
            except Folder.DoesNotExist:
                pass

As you can see, folders return two objects related to the session user in get_queryset() : 'Folder' and 'Another folder

Infortunately, the combobox of my template get all the folders, without any filtering.

enter image description here

Any idea ?

Carl
  • 898
  • 9
  • 16
Burrich
  • 1,214
  • 1
  • 16
  • 15

1 Answers1

26

The issue here is that get_queryset is not used in a CreateView, as it's meant for filtering the models returned for display in a list or detail view. You want something completely different: you want to filter the choices available in a form field.

To do that you will need to create a custom ModelForm that accepts a user kwarg and filters the queryset accordingly:

class FolderForm(forms.ModelForm):
    class Meta:
       model = Folder
       fields = ['name', 'parent']

    def __init__(self, *args, **kwargs):
       user = kwargs.pop('user')
       super(FolderForm, self).__init__(*args, **kwargs)
       self.fields['parent'].queryset = Folder.objects.filter(user=user)

and then change your view to use that form and pass in the user parameter:

class FolderCreate(CreateView):
    template_name = 'Form/folder_create.html'
    form_class = FolderForm

    def get_form_kwargs(self):
        kwargs = super(FolderCreate, self).get_form_kwargs()
        kwargs['user'] = self.request.user
        return kwargs
Baptiste M.
  • 95
  • 1
  • 8
Daniel Roseman
  • 588,541
  • 66
  • 880
  • 895
  • 1
    Thank you, this is perfect. So get_queryset could not be used to populate my combobox filtering the model. – Burrich Jun 04 '14 at 18:04
  • 1
    Oddly enough the CreateView does call get_queryset() in some circumstances. Specifically in order to work out the model if it's not specified in self.model when it needs to know the model. While a queryset makes little sense in a CreateView, it falls back on this method get_form_class() of the ModelFormMixin. – Bernd Wechner Feb 26 '19 at 11:25