假设我有一个"查找发票"页面;用户可以输入(或不输入)不同的字段,以便搜索发票并将其显示在列表中。假设这个字段列表随着时间的推移可能会增加额外的db字段。我目前的(工作)解决方案如下,但我想知道是否有更好的方法来允许可能的额外字段并相应地调整查询。
query.py[自定义查询编写器]
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)
views.py (Django Rest Framework)
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
这里用ORM方法解决。又短又快!还解决了附加/可选搜索字段的问题。
class InvoiceViewSet(viewsets.ModelViewSet):
serializer_class = InvoiceSerializer
def get_queryset(self):
# input value from search page
user = self.request.user.id
year = self.request.GET.get('selected_year')
client = self.request.GET.get('selected_client')
filters = {
# model name: input value
}
if user:
filters['iv_created_by'] = user
if year:
filters['iv_year'] = year
if client:
filters['iv_client'] = client
result = Invoice.objects.filter(**filters)
return result