如何获取Django/Python中倒数第二个最近的时间戳记录?
How to get the second to last most recent timestamped record in Django/Python?
我有一个来自模型的表格,可以跟踪 enter/leave 次。我正在尝试添加约束以使数据更准确。目前,当有人 "Enters" 时,它会创建一条记录,将时间保存在 "time_in" DateTimeField 中,然后重定向。如果此人随后尝试再次进入,它会创建一个带有新时间戳的新记录。
我现在要添加的是,如果此人之前的条目没有退出时间戳 (time_out),那么该记录(这将是倒数第二个最新条目),将通过将 time_exceptions 字段更新为 'N'.
来标记
目前,无论是否有出口,它都将所有字段更改为'N',如下所示。
注意 我减少了 form_valid 中的代码量,因此离开区域部分不存在。只是根据其他字段进行了很多过滤,看起来不太相关。
views.py
class EnterExitArea(CreateView):
model = EmployeeWorkAreaLog
template_name = "operations/enter_exit_area.html"
form_class = WarehouseForm
def form_valid(self, form):
emp_num = form.cleaned_data['employee_number']
area = form.cleaned_data['work_area']
station = form.cleaned_data['station_number']
if 'enter_area' in self.request.POST:
form.save()
EmployeeWorkAreaLog.objects.filter((Q(employee_number=emp_num) & Q(work_area=area) & Q(time_out__isnull=True) & Q(time_in__isnull=True)) & (Q(station_number=station) | Q(station_number__isnull=True))).update(time_in=datetime.now())
if EmployeeWorkAreaLog.objects.filter(Q(employee_number=emp_num)).count() > 1:
EmployeeWorkAreaLog.objects.filter((Q(employee_number=emp_num) & Q(work_area=area) & Q(time_out__isnull=True)) & (Q(station_number=station) | Q(station_number__isnull=True))).update(time_exceptions='N')
return HttpResponseRedirect(self.request.path_info)
我尝试了以下方法,但我得到了 expected string or bytes-like object
,虽然它在崩溃前仍然创建了一条新记录,但它不会将倒数第二个的 time_exceptions 更新为 N。
if 'enter_area' in self.request.POST:
form.save()
EmployeeWorkAreaLog.objects.filter((Q(employee_number=emp_num) & Q(work_area=area) & Q(time_out__isnull=True) & Q(time_in__isnull=True)) & (Q(station_number=station) | Q(station_number__isnull=True))).update(time_in=datetime.now())
if EmployeeWorkAreaLog.objects.filter(Q(employee_number=emp_num) & Q(time_out__isnull=True) & Q(time_exceptions="")).count() > 1:
recent = EmployeeWorkAreaLog.objects.filter(employee_number=emp_num, work_area=area, station_number=station, time_out__isnull=True).order_by('-time_in')[1]
EmployeeWorkAreaLog.objects.filter((Q(employee_number=emp_num) & Q(work_area=area) & Q(time_in=recent) & Q(time_out__isnull=True)) & (Q(station_number=station) | Q(station_number__isnull=True))).update(time_exceptions='N')
return HttpResponseRedirect(self.request.path_info)
models.py
class EmployeeWorkAreaLog(TimeStampedModel, SoftDeleteModel, models.Model):
employee_number = models.ForeignKey(Salesman, on_delete=models.SET_NULL, help_text="Employee #", null=True, blank=False)
work_area = models.ForeignKey(WorkArea, on_delete=models.SET_NULL, null=True, blank=False, help_text="Work Area", related_name="work_area")
station_number = models.ForeignKey(StationNumber, on_delete=models.SET_NULL,
time_exceptions = models.CharField(max_length=2, blank=True)
time_in = models.DateTimeField(help_text="Time in", null=True, blank=True)
time_out = models.DateTimeField(blank=True, help_text="Time out", null=True)
def __str__(self):
return self.employee_number
回溯:
Internal Server Error: /operations/enter-exit-area/
Traceback (most recent call last):
File "C:\Users\mkusneco\appsve\lib\site-packages\django\core\handlers\exception.py", line 34, in inner
response = get_response(request)
File "C:\Users\mkusneco\appsve\lib\site-packages\django\core\handlers\base.py", line 126, in _get_response
response = self.process_exception_by_middleware(e, request)
File "C:\Users\mkusneco\appsve\lib\site-packages\django\core\handlers\base.py", line 124, in _get_response
response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "C:\Users\mkusneco\appsve\lib\site-packages\django\views\generic\base.py", line 68, in view
return self.dispatch(request, *args, **kwargs)
File "C:\Users\mkusneco\appsve\lib\site-packages\django\views\generic\base.py", line 88, in dispatch
return handler(request, *args, **kwargs)
File "C:\Users\mkusneco\appsve\lib\site-packages\django\views\generic\edit.py", line 172, in post
return super().post(request, *args, **kwargs)
File "C:\Users\mkusneco\appsve\lib\site-packages\django\views\generic\edit.py", line 142, in post
return self.form_valid(form)
File "C:\Users\mkusneco\apps.rsrgroup.com\apps\operations\views.py", line 45, in form_valid
Q(station_number=station) | Q(station_number__isnull=True))).update(time_exceptions='N')
File "C:\Users\mkusneco\appsve\lib\site-packages\django\db\models\manager.py", line 82, in manager_method
return getattr(self.get_queryset(), name)(*args, **kwargs)
File "C:\Users\mkusneco\appsve\lib\site-packages\django\db\models\query.py", line 844, in filter
return self._filter_or_exclude(False, *args, **kwargs)
File "C:\Users\mkusneco\appsve\lib\site-packages\django\db\models\query.py", line 862, in _filter_or_exclude
clone.query.add_q(Q(*args, **kwargs))
File "C:\Users\mkusneco\appsve\lib\site-packages\django\db\models\sql\query.py", line 1263, in add_q
clause, _ = self._add_q(q_object, self.used_aliases)
File "C:\Users\mkusneco\appsve\lib\site-packages\django\db\models\sql\query.py", line 1281, in _add_q
current_negated, allow_joins, split_subq)
File "C:\Users\mkusneco\appsve\lib\site-packages\django\db\models\sql\query.py", line 1287, in _add_q
split_subq=split_subq,
File "C:\Users\mkusneco\appsve\lib\site-packages\django\db\models\sql\query.py", line 1225, in build_filter
condition = self.build_lookup(lookups, col, value)
File "C:\Users\mkusneco\appsve\lib\site-packages\django\db\models\sql\query.py", line 1096, in build_lookup
lookup = lookup_class(lhs, rhs)
File "C:\Users\mkusneco\appsve\lib\site-packages\django\db\models\lookups.py", line 20, in __init__
self.rhs = self.get_prep_lookup()
File "C:\Users\mkusneco\appsve\lib\site-packages\django\db\models\lookups.py", line 70, in get_prep_lookup
return self.lhs.output_field.get_prep_value(self.rhs)
File "C:\Users\mkusneco\appsve\lib\site-packages\django\db\models\fields\__init__.py", line 1408, in get_prep_value
value = super().get_prep_value(value)
File "C:\Users\mkusneco\appsve\lib\site-packages\django\db\models\fields\__init__.py", line 1268, in get_prep_value
return self.to_python(value)
File "C:\Users\mkusneco\appsve\lib\site-packages\django\db\models\fields\__init__.py", line 1369, in to_python
parsed = parse_datetime(value)
File "C:\Users\mkusneco\appsve\lib\site-packages\django\utils\dateparse.py", line 106, in parse_datetime
match = datetime_re.match(value)
TypeError: expected string or bytes-like object
您将 EmployeeWorkAreaLog
实例分配给 recent
,但是您在条件中使用它作为 Q(time_in=recent)
,这显然是错误的,因为条件需要包含一个简单的值/日期时间/ 字符串,不是对象。
所以您 可以 使用 Q(time_in=recent.time_in)
修复它,但如果用户有某种重复条目,那不是很可靠。使用实例的 pk
会 更好 ,因此您可以使用 Q(pk=recent.pk)
而不是 time_in
条件。但这仍然不是最好的解决方案——如果有多个这样的条目怎么办?为什么只更新第二个而不更新第三个等等?
所以我认为不要 select 第二个条目(使用 [1]
),你应该 select 第一个 ,并且从更新查询集中排除这个,例如:
first = EmployeeWorkAreaLog.objects.filter(employee_number=emp_num, work_area=area, station_number=station, time_out__isnull=True).order_by('-time_in').first()
EmployeeWorkAreaLog.objects.filter((Q(employee_number=emp_num) & Q(work_area=area) & Q(time_out__isnull=True)) & (Q(station_number=station) | Q(station_number__isnull=True))).exclude(pk=first.pk).update(time_exceptions='N')
我有一个来自模型的表格,可以跟踪 enter/leave 次。我正在尝试添加约束以使数据更准确。目前,当有人 "Enters" 时,它会创建一条记录,将时间保存在 "time_in" DateTimeField 中,然后重定向。如果此人随后尝试再次进入,它会创建一个带有新时间戳的新记录。
我现在要添加的是,如果此人之前的条目没有退出时间戳 (time_out),那么该记录(这将是倒数第二个最新条目),将通过将 time_exceptions 字段更新为 'N'.
来标记目前,无论是否有出口,它都将所有字段更改为'N',如下所示。
注意 我减少了 form_valid 中的代码量,因此离开区域部分不存在。只是根据其他字段进行了很多过滤,看起来不太相关。
views.py
class EnterExitArea(CreateView):
model = EmployeeWorkAreaLog
template_name = "operations/enter_exit_area.html"
form_class = WarehouseForm
def form_valid(self, form):
emp_num = form.cleaned_data['employee_number']
area = form.cleaned_data['work_area']
station = form.cleaned_data['station_number']
if 'enter_area' in self.request.POST:
form.save()
EmployeeWorkAreaLog.objects.filter((Q(employee_number=emp_num) & Q(work_area=area) & Q(time_out__isnull=True) & Q(time_in__isnull=True)) & (Q(station_number=station) | Q(station_number__isnull=True))).update(time_in=datetime.now())
if EmployeeWorkAreaLog.objects.filter(Q(employee_number=emp_num)).count() > 1:
EmployeeWorkAreaLog.objects.filter((Q(employee_number=emp_num) & Q(work_area=area) & Q(time_out__isnull=True)) & (Q(station_number=station) | Q(station_number__isnull=True))).update(time_exceptions='N')
return HttpResponseRedirect(self.request.path_info)
我尝试了以下方法,但我得到了 expected string or bytes-like object
,虽然它在崩溃前仍然创建了一条新记录,但它不会将倒数第二个的 time_exceptions 更新为 N。
if 'enter_area' in self.request.POST:
form.save()
EmployeeWorkAreaLog.objects.filter((Q(employee_number=emp_num) & Q(work_area=area) & Q(time_out__isnull=True) & Q(time_in__isnull=True)) & (Q(station_number=station) | Q(station_number__isnull=True))).update(time_in=datetime.now())
if EmployeeWorkAreaLog.objects.filter(Q(employee_number=emp_num) & Q(time_out__isnull=True) & Q(time_exceptions="")).count() > 1:
recent = EmployeeWorkAreaLog.objects.filter(employee_number=emp_num, work_area=area, station_number=station, time_out__isnull=True).order_by('-time_in')[1]
EmployeeWorkAreaLog.objects.filter((Q(employee_number=emp_num) & Q(work_area=area) & Q(time_in=recent) & Q(time_out__isnull=True)) & (Q(station_number=station) | Q(station_number__isnull=True))).update(time_exceptions='N')
return HttpResponseRedirect(self.request.path_info)
models.py
class EmployeeWorkAreaLog(TimeStampedModel, SoftDeleteModel, models.Model):
employee_number = models.ForeignKey(Salesman, on_delete=models.SET_NULL, help_text="Employee #", null=True, blank=False)
work_area = models.ForeignKey(WorkArea, on_delete=models.SET_NULL, null=True, blank=False, help_text="Work Area", related_name="work_area")
station_number = models.ForeignKey(StationNumber, on_delete=models.SET_NULL,
time_exceptions = models.CharField(max_length=2, blank=True)
time_in = models.DateTimeField(help_text="Time in", null=True, blank=True)
time_out = models.DateTimeField(blank=True, help_text="Time out", null=True)
def __str__(self):
return self.employee_number
回溯:
Internal Server Error: /operations/enter-exit-area/
Traceback (most recent call last):
File "C:\Users\mkusneco\appsve\lib\site-packages\django\core\handlers\exception.py", line 34, in inner
response = get_response(request)
File "C:\Users\mkusneco\appsve\lib\site-packages\django\core\handlers\base.py", line 126, in _get_response
response = self.process_exception_by_middleware(e, request)
File "C:\Users\mkusneco\appsve\lib\site-packages\django\core\handlers\base.py", line 124, in _get_response
response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "C:\Users\mkusneco\appsve\lib\site-packages\django\views\generic\base.py", line 68, in view
return self.dispatch(request, *args, **kwargs)
File "C:\Users\mkusneco\appsve\lib\site-packages\django\views\generic\base.py", line 88, in dispatch
return handler(request, *args, **kwargs)
File "C:\Users\mkusneco\appsve\lib\site-packages\django\views\generic\edit.py", line 172, in post
return super().post(request, *args, **kwargs)
File "C:\Users\mkusneco\appsve\lib\site-packages\django\views\generic\edit.py", line 142, in post
return self.form_valid(form)
File "C:\Users\mkusneco\apps.rsrgroup.com\apps\operations\views.py", line 45, in form_valid
Q(station_number=station) | Q(station_number__isnull=True))).update(time_exceptions='N')
File "C:\Users\mkusneco\appsve\lib\site-packages\django\db\models\manager.py", line 82, in manager_method
return getattr(self.get_queryset(), name)(*args, **kwargs)
File "C:\Users\mkusneco\appsve\lib\site-packages\django\db\models\query.py", line 844, in filter
return self._filter_or_exclude(False, *args, **kwargs)
File "C:\Users\mkusneco\appsve\lib\site-packages\django\db\models\query.py", line 862, in _filter_or_exclude
clone.query.add_q(Q(*args, **kwargs))
File "C:\Users\mkusneco\appsve\lib\site-packages\django\db\models\sql\query.py", line 1263, in add_q
clause, _ = self._add_q(q_object, self.used_aliases)
File "C:\Users\mkusneco\appsve\lib\site-packages\django\db\models\sql\query.py", line 1281, in _add_q
current_negated, allow_joins, split_subq)
File "C:\Users\mkusneco\appsve\lib\site-packages\django\db\models\sql\query.py", line 1287, in _add_q
split_subq=split_subq,
File "C:\Users\mkusneco\appsve\lib\site-packages\django\db\models\sql\query.py", line 1225, in build_filter
condition = self.build_lookup(lookups, col, value)
File "C:\Users\mkusneco\appsve\lib\site-packages\django\db\models\sql\query.py", line 1096, in build_lookup
lookup = lookup_class(lhs, rhs)
File "C:\Users\mkusneco\appsve\lib\site-packages\django\db\models\lookups.py", line 20, in __init__
self.rhs = self.get_prep_lookup()
File "C:\Users\mkusneco\appsve\lib\site-packages\django\db\models\lookups.py", line 70, in get_prep_lookup
return self.lhs.output_field.get_prep_value(self.rhs)
File "C:\Users\mkusneco\appsve\lib\site-packages\django\db\models\fields\__init__.py", line 1408, in get_prep_value
value = super().get_prep_value(value)
File "C:\Users\mkusneco\appsve\lib\site-packages\django\db\models\fields\__init__.py", line 1268, in get_prep_value
return self.to_python(value)
File "C:\Users\mkusneco\appsve\lib\site-packages\django\db\models\fields\__init__.py", line 1369, in to_python
parsed = parse_datetime(value)
File "C:\Users\mkusneco\appsve\lib\site-packages\django\utils\dateparse.py", line 106, in parse_datetime
match = datetime_re.match(value)
TypeError: expected string or bytes-like object
您将 EmployeeWorkAreaLog
实例分配给 recent
,但是您在条件中使用它作为 Q(time_in=recent)
,这显然是错误的,因为条件需要包含一个简单的值/日期时间/ 字符串,不是对象。
所以您 可以 使用 Q(time_in=recent.time_in)
修复它,但如果用户有某种重复条目,那不是很可靠。使用实例的 pk
会 更好 ,因此您可以使用 Q(pk=recent.pk)
而不是 time_in
条件。但这仍然不是最好的解决方案——如果有多个这样的条目怎么办?为什么只更新第二个而不更新第三个等等?
所以我认为不要 select 第二个条目(使用 [1]
),你应该 select 第一个 ,并且从更新查询集中排除这个,例如:
first = EmployeeWorkAreaLog.objects.filter(employee_number=emp_num, work_area=area, station_number=station, time_out__isnull=True).order_by('-time_in').first()
EmployeeWorkAreaLog.objects.filter((Q(employee_number=emp_num) & Q(work_area=area) & Q(time_out__isnull=True)) & (Q(station_number=station) | Q(station_number__isnull=True))).exclude(pk=first.pk).update(time_exceptions='N')