下面的调试会话说明了我想说的话。 我已经在Django开发服务器,Cherrypy服务器和Werkzeug调试器下执行了此操作。 在Windows 10 MySQL 5.5后端上使用Django 1.11.10。
该函数(在本文结尾)对QuerySet进行连续过滤。 我停止执行程序以执行一些健全性检查。 我发现,第一个过滤器操作的工作是event_values.count()== 14,但是任何进一步的过滤尝试将始终产生相同的结果。 例如,我在pk = 72上进行过滤,但仍然返回了所有14个模型实例。 我尝试使用get(pk = 72)并得到了MultipleObjectsReturned异常。
有趣的是,当我在Django shell中执行连续过滤时,我得到了应该得到的结果,但是当我从shell中运行实际代码时,它也有同样的问题。
有人可以让我知道我在做什么错吗?
谢谢。
(Pdb) l
160 event_values = event_values.filter(
161 tsn__gte=tsn_start, tsn__lte=tsn_end)
162
163 import pdb; pdb.set_trace()
164
165 -> if tso_start or tso_end:
166 tso_start, tso_end = resolve_ranges(tso_start, tso_end)
167
168 event_values = event_values.filter(
169 tso__gte=tso_start, tso__lte=tso_end)
170
(Pdb) tsn_start
5800
(Pdb) tsn_end
6000
(Pdb) event_values.count()
14
(Pdb) event_values
<QuerySet [<ComplianceEvent: pk: 72 -- 383201 -- 2017-12-11 -- SB>, <ComplianceEvent: pk: 73 -- 383202 -- 2017-04-11 -- SB>, <ComplianceEvent: pk: 74 -- 383203 -- 2018-01-15 -- SB>, <ComplianceEvent: pk: 75 -- 383210 -- 2017-10-06 -- SB>, <ComplianceEvent: pk: 76 -- 383217 -- 2018-05-18 -- SB>, <ComplianceEvent: pk: 77 -- 383219 -- 2017-09-21 -- SB>, <ComplianceEvent: pk: 78 -- 383303 -- 2017-07-19 -- SB>, <ComplianceEvent: pk: 79 -- 383303 -- 2017-07-07 -- SB>, <ComplianceEvent: pk: 80 -- 383309 -- 2018-02-23 -- SB>, <ComplianceEvent: pk: 81 -- 383313 -- 2018-03-07 -- SB>, <ComplianceEvent: pk: 82 -- 383315 -- 2016-04-18 -- SB>, <ComplianceEvent: pk: 83 -- 383317 -- 2017-04-21 -- SB>, <ComplianceEvent: pk: 84 -- 383319 -- 2018-02-22 -- SB>, <ComplianceEvent: pk: 85 -- 383324 -- 2018-08-15 -- SB>]>
(Pdb) event_values.filter(pk=72)
<QuerySet [<ComplianceEvent: pk: 72 -- 383201 -- 2017-12-11 -- SB>, <ComplianceEvent: pk: 73 -- 383202 -- 2017-04-11 -- SB>, <ComplianceEvent: pk: 74 -- 383203 -- 2018-01-15 -- SB>, <ComplianceEvent: pk: 75 -- 383210 -- 2017-10-06 -- SB>, <ComplianceEvent: pk: 76 -- 383217 -- 2018-05-18 -- SB>, <ComplianceEvent: pk: 77 -- 383219 -- 2017-09-21 -- SB>, <ComplianceEvent: pk: 78 -- 383303 -- 2017-07-19 -- SB>, <ComplianceEvent: pk: 79 -- 383303 -- 2017-07-07 -- SB>, <ComplianceEvent: pk: 80 -- 383309 -- 2018-02-23 -- SB>, <ComplianceEvent: pk: 81 -- 383313 -- 2018-03-07 -- SB>, <ComplianceEvent: pk: 82 -- 383315 -- 2016-04-18 -- SB>, <ComplianceEvent: pk: 83 -- 383317 -- 2017-04-21 -- SB>, <ComplianceEvent: pk: 84 -- 383319 -- 2018-02-22 -- SB>, <ComplianceEvent: pk: 85 -- 383324 -- 2018-08-15 -- SB>]>
(Pdb) event_values.get(pk=72)
*** esipeht.models.MultipleObjectsReturned: get() returned more than one ComplianceEvent -- it returned 14!
(Pdb) ComplianceEvent.objects.get(pk=72)
<ComplianceEvent: pk: 72 -- 383201 -- 2017-12-11 -- SB>
完整代码:
def evaluate_search(criteria):
"""Execute the query and return associated engine events.
The submitted dict:
{
'ac_rh_end': None,
'ac_rh_start': None,
'affected_parts': ['31'],
'aircraft': [],
'end_date': None,
'engines': [],
'event_source': '',
'event_subtype': ['Compliance-SB'],
'positions': [],
'ref_docs': [],
'ress': [],
'start_date': None,
'status': '',
'tsn_end': 6000,
'tsn_start': 5800,
'tso_end': None,
'tso_start': None
}
Args:
criteria (dict): The criteria posted by the user.
Returns:
The associated engine events.
"""
ac_rh_end = criteria['ac_rh_end']
ac_rh_start = criteria['ac_rh_start']
end_date = criteria['end_date']
start_date = criteria['start_date']
event_source = criteria['event_source']
tsn_end = criteria['tsn_end']
tsn_start = criteria['tsn_start']
tso_end = criteria['tso_end']
tso_start = criteria['tso_start']
review_status = criteria['status']
# get ids of the form multiselects
# note: if the criteria was not selected, the result will be an empty list
affpart_ids = criteria['affected_parts']
aircraft = criteria['aircraft']
engines = criteria['engines']
ref_doc_ids = criteria['ref_docs']
res_ids = criteria['ress']
positions = criteria['positions']
event_subtype = criteria['event_subtype']
# create a dictionary with all subtypes initialized to empty querysets
events = {
'Fitment' : FitmentEvent.objects.none(),
'Compliance' : ComplianceEvent.objects.none(),
'Incident' : IncidentEvent.objects.none(),
'RepairOverhaul' : RepairOverhaulEvent.objects.none()
}
# if one or more event subtypes were selected by user
if event_subtype:
# determine event and event subtype
for type_subtype in event_subtype:
event_type, subtype = type_subtype.split('-')
model_class = getattr(esipeht.models, event_type + 'Event')
events[event_type] |= model_class.objects.filter(
event_subtype=subtype
)
# if no subtypes selected then we want everything
else:
if affpart_ids:
# Fitment events do not reference affected parts
events['Fitment'] = FitmentEvent.objects.none()
else:
events['Fitment'] = FitmentEvent.objects.all()
events['Compliance'] = ComplianceEvent.objects.all()
events['Incident'] = IncidentEvent.objects.all()
events['RepairOverhaul'] = RepairOverhaulEvent.objects.all()
results = []
# keep track of the number of each type of event
all_counts = {
'Fitment' : 0,
'Compliance' : 0,
'Incident' : 0,
'RepairOverhaul' : 0
}
# loop through the query sets (event_values) for each event type (key)
for event_type, event_values in events.items():
if event_values.count() == 0:
continue
if engines:
event_values = event_values.filter(
engine__serial_number__in=engines)
if aircraft:
event_values = event_values.filter(
aircraft__tail_number__in=aircraft)
if positions:
event_values = event_values.filter(engine_position__in=positions)
# a fitment event does not reference affected parts
if affpart_ids and event_type != 'Fitment':
event_values1 = event_values.filter(
affected_parts__id__in=affpart_ids)
event_values2 = event_values.filter(
ress__affected_parts__id__in=affpart_ids)
event_values = event_values1.union(event_values2)
if ref_doc_ids:
event_values = event_values.filter(
reference_documents__id__in=ref_doc_ids)
if res_ids:
event_values = event_values.filter(ress__id__in=res_ids)
if tsn_start or tsn_end:
tsn_start, tsn_end = resolve_ranges(tsn_start, tsn_end)
event_values = event_values.filter(
tsn__gte=tsn_start, tsn__lte=tsn_end)
import pdb; pdb.set_trace()
if tso_start or tso_end:
tso_start, tso_end = resolve_ranges(tso_start, tso_end)
event_values = event_values.filter(
tso__gte=tso_start, tso__lte=tso_end)
if ac_rh_start or ac_rh_end:
ac_rh_start, ac_rh_end = resolve_ranges(ac_rh_start, ac_rh_end)
event_values = event_values.filter(
aircraft_hours__gte=ac_rh_start, aircraft_hours__lte=ac_rh_end)
if start_date or end_date:
start_date, end_date = resolve_ranges(start_date, end_date)
event_values = event_values.filter(
event_date__gte=start_date, event_date__lte=end_date)
if event_source:
event_values = event_values.filter(source=event_source)
if review_status:
event_values = event_values.filter(review_status=review_status)
results.extend(list(event_values.distinct()))
all_counts[event_type] += event_values.count()
sorted_results = sorted(results, key=attrgetter('engine', 'event_date'))
grouped_events = {}
for event in sorted_results:
engine = event.engine.serial_number
if engine in grouped_events:
grouped_events[engine].append(event)
else:
grouped_events[engine] = [event]
return grouped_events, all_counts
def resolve_ranges(start, end):
"""This will determine how numeric and date ranges are filtered.
"""
if start and end:
# if start and end are reversed, swap them
if end < start:
start, end = end, start
return start, end
elif start:
end = (
datetime.date.today() if type(start) == datetime.date else 999999
)
return start, end
elif end:
start = (
datetime.date(2009, 1, 1) if type(end) == datetime.date else 0
)
return start, end
return None, None
答案 0 :(得分:0)
找到答案:
替换
event_values = event_values1.union(event_values2)
使用
event_values = (event_values1 | event_values2).distinct()
union()方法的评估正确,但是结果查询集无法进一步过滤。
我在以下位置检查了文档
发现这是设计使然:
此外,仅允许LIMIT,OFFSET,COUNT(*),ORDER BY和指定列(即切片,count(),order_by()和values()/ values_list())。结果QuerySet。