1

I have a generic class-based view derived from ListView. The view should interact with a form declared in forms.py to filter the objects_list via a GET query and, also, modify the context (if you're interested in why I'd like to do that, check my previous question).

This means I need an instance of the form (form = MyForm(request.GET)) both in the get_queryset and get_context_data methods.


This solution is not acceptable since it is a violation of this coding principle and assumes that get_queryset will always gets called first (which may not be the case in future versions of Django).

Example:

def get_queryset(self):
    self.form = MyForm(self.request.GET)

This solution is not acceptable since it uses the raw GET arguments while we'd like to harness the full potential of the form automatic parsing/validation.

Example:

def get_queryset(self):
    a_form_field = self.kwargs["a_form_field"]

Is this possible to do without violating any good design principle?

Community
  • 1
  • 1
Saturnix
  • 10,130
  • 17
  • 64
  • 120
  • What do you mean "assumes that get_queryset will always gets called first"? First before what? – Nick Nov 14 '15 at 12:17
  • Before get_context_data. – Saturnix Nov 14 '15 at 15:10
  • What make you think that they can do it? I mean that we definitely don't want to hard code some django stuff or rely on some undocumented features, but if won't rely on some common ideas we can't use any frameworks. Like we can't be sure that they won't rename get_context_data to get_context, but it doesn't mean that we shouldn't use it. – Nick Nov 14 '15 at 15:25
  • Where is it documented that they won't? If you document the existence of a class and its methods, that means you can safely assume they will tell you if they change names. Nowhere it is documented that get_context_data comes after and get_queryset comes first: it is only understood from the source code which, ideally, you wouldn't even need to read. – Saturnix Nov 14 '15 at 20:16

1 Answers1

1

I would override the get method:

class SearchList(ListView):
    def get(self, request, *args, **kwargs):
        self.form = MyForm(request.GET)
        if self.form.is_valid():
            self.queryset = self.form.process_search(self.queryset)

        return super(SearchList, self).get(request, *args, **kwargs)

Your form will need to have process_search to hold the queryset filtering flow (this way you keep the search login inside form class).

You can access self.form afterwards and you can access it inside template with {{ view.form }}.

mariodev
  • 13,928
  • 3
  • 49
  • 61
  • +1, thanks for your help... still a violation of this though: http://stackoverflow.com/questions/19284857/instance-attribute-attribute-name-defined-outside-init – Saturnix Nov 17 '15 at 18:08