title: Is there a best practice to create a Django query with extensible filters?
body: <p>Suppose I have a &quot;find invoice page&quot; where users can input (or not) different fields in order to search for invoices to display them in a list.
  Suppose this list of fields might grow over time with additional db fields.
  My current (working) solution is the following but I'm wondering if there is a better way to allow possible additional fields and adapt the query accordingly.</p>
  <p>query.py [custom query composer]</p>
  <pre><code>from .models import Invoice
  
  class FindQuery:
  
      def __init__(self):
          self.filters = {}
          self.fq_sql = ''
          self.fq_select = 'SELECT * '
          self.fq_from = 'FROM invoice_invoice '
          self.fq_where = 'WHERE 1=1 '
          self.fq_order = ' ORDER BY iv_created_at DESC'
  
      def set_filters(self, user, year, client):
          if user:
              self.filters['request_user'] = user
  
          if year:
              self.filters['selected_year'] = year
  
          if client:
              self.filters['selected_client'] = client
  
          # adding here new fields
      
      def apply_filter(self):
  
          if 'request_user' in self.filters:
              self.fq_where += ' AND iv_created_by = ' + str(self.filters.get('request_user'))
  
          if 'selected_year' in self.filters:
              self.fq_where += ' AND iv_year = ' + str(self.filters.get('selected_year'))
              
          if 'selected_client' in self.filters:
              self.fq_where += ' AND iv_client = ' + str(self.filters.get('selected_client'))
  
          # adding here new fields
  
          self.fq_sql = self.fq_select + self.fq_from + self.fq_where + self.fq_order
          return Invoice.objects.raw(self.fq_sql)
  </code></pre>
  <p>views.py (Django Rest Framework)</p>
  <pre><code>from .query import FindQuery
  
  class InvoiceViewSet(viewsets.ModelViewSet):
      serializer_class = InvoiceSerializer
  
  
      def get_queryset(self):
          q = FindQuery()
  
          user = self.request.user.id
          year = self.request.GET.get('selected_year')
          client = self.request.GET.get('selected_client')
          # adding here new fields
  
          q.set_filters(user, year, client)
          qs = q.apply_filter()
          result = Invoice.objects.filter(iv_id__in=[q.iv_id for q in qs])
          return result
  </code></pre>