django - 与 Django 时间字段交织在一起的问题迫使黑客编辑/显示时间
问题描述
姜戈 2
这里有很多信息。我将尝试总结问题的本质。
背景事实:为时间字段设置默认值需要在模型参考中设置 datetime.time:https ://code.djangoproject.com/ticket/6754
这里有两个相关的问题。
问题一:时间字段的数据类型发生变化
第一个问题是下面 Django 页面的初始 GET 返回一个数据类型为<class 'datetime.time'>
. 这是好的和预期的。
但是,如果您通过 POST 提交该表单,并且存在字段验证错误,则时间字段的数据类型会更改为字符串。查看此问题底部的服务器日志以查看。结果,数据的格式也发生了变化——注意秒数被丢弃了。这也可以在下面的服务器日志中看到。
这导致问题2:
问题 2:当传入的数据没有秒数时,Django 的时间格式化标签返回 None。
在下面的 HTML 模板中,您可以看到包含以下内容的行:
time:'H:i'
这是一个格式化标签,它接受一个时间,它应该以 hh:mm 格式输出时间。如果输入的格式为 18:00:00,则它可以工作。如果输入的格式为 18:00,则返回 None
这个的用户体验:
所以发生的情况是用户最初通过 GET 加载表单,默认时间以 HH:MM 格式显示 OK。用户填写一些字段并提交,如果出现验证错误,则再次显示页面,并显示验证错误消息,但现在时间已经消失,因为它将数据类型更改为字符串,从而减少了秒数,现在没有时间显示,因为如果 Django 模板时间过滤器标签的输入没有秒,则返回 None。
问题 1: 如何解决这个问题,而无需通过我转换为字符串的附加字段来强制时间字段。这行得通,但这只是解决上述问题的一种技巧。
问题 2: 为什么在初始 GET 表单加载后 POST 到服务器时,时间字段的类型从 datetime.time 变为 string?
问题3: 为什么Django模板时间标签转换在其输入不包含秒的情况下返回None?
Django HTML 模板:
<form action="{% url 'main:testtime' %}" method="post">
<br/><br/>
Event title<br/>
{% if form.title.errors %}
{% for error in form.title.errors %}
<div class="form-error">{{ error|escape }}</div>
{% endfor %}
{% endif %}
<input type="text"
name="title"
id="id_title"
>
<br/><br/>
Event time<br/>
{{ form.time.value|time:'H:i' }}<br/>
{{ form.time.value }}<br/>
<input
type="time"
name="time"
required
step="60"
id="id_time"
value="{{ form.time.value|time:'H:i' }}"
>
<br/><br/>
{% csrf_token %}
<input type="submit" value="submit">
</form>
Django形式:
class TestForm(forms.ModelForm):
class Meta:
model = Event
fields = [
'date',
'time',
'title',
]
def clean_title(self):
raise forms.ValidationError('This forces a valdation error')
Django 模型(删除了一堆不相关的字段)
class Event(models.Model):
@staticmethod
def default_datetime():
return datetime.time(18, 00, 00)
date = models.DateField(blank=False, null=False)
time = models.TimeField(default=default_datetime.__func__, blank=False, null=False)
title = models.TextField()
来自 urls.py 的相关行
path('testtime/', views.testtime, name='testtime'),
来自views.py的相关函数
@require_http_methods(['GET', 'POST'])
@login_required
def testtime(request):
if request.method == 'POST':
form = TestForm(request.POST)
print("POST HANDLE NEW EVENT")
elif request.method == 'GET':
form = TestForm()
print("GET NEW EVENT")
print("type of form['time'].value() is:")
print(type(form['time'].value()))
print("value of form['time'].value() is:")
print(form['time'].value())
return render(request, 'main/testtime.html', {
'form': form,
})
服务器日志:
Jan 22 21:39:22 ip-10-0-1-251 uwsgi[14637]: GET NEW EVENT
Jan 22 21:39:22 ip-10-0-1-251 uwsgi[14637]: type of form['time'].value() is:
Jan 22 21:39:22 ip-10-0-1-251 uwsgi[14637]: <class 'datetime.time'>
Jan 22 21:39:22 ip-10-0-1-251 uwsgi[14637]: value of form['time'].value() is:
Jan 22 21:39:22 ip-10-0-1-251 uwsgi[14637]: 18:00:00
Jan 22 21:39:22 ip-10-0-1-251 uwsgi[14637]: [pid: 14647|app: 0|req: 1/5] xx.xx.102.186 () {44 vars in 1026 bytes} [Tue Jan 22 21:39:22 2019] GET /testtime/ => generated 580 bytes in 108 msecs (HTTP/1.1 200) 5 headers in 293 bytes (2 switches on core 0)
Jan 22 21:39:37 ip-10-0-1-251 uwsgi[14637]: POST HANDLE NEW EVENT
Jan 22 21:39:37 ip-10-0-1-251 uwsgi[14637]: type of form['time'].value() is:
Jan 22 21:39:37 ip-10-0-1-251 uwsgi[14637]: <class 'str'>
Jan 22 21:39:37 ip-10-0-1-251 uwsgi[14637]: value of form['time'].value() is:
Jan 22 21:39:37 ip-10-0-1-251 uwsgi[14637]: 20:03
Jan 22 21:39:37 ip-10-0-1-251 uwsgi[14637]: [pid: 14645|app: 0|req: 3/6] xx.xx.102.186 () {54 vars in 1263 bytes} [Tue Jan 22 21:39:37 2019] POST /testtime/ => generated 658 bytes in 8 msecs (HTTP/1.1 200) 5 headers in 293 bytes (2 switches on core 0)
解决方案
问题 1:如何解决这个问题,而无需通过我转换为字符串的附加字段来强制时间字段。这行得通,但这只是解决上述问题的一种技巧。
您应该使用模板中的表单字段来解决这个问题。而不是
<input
type="time"
name="time"
required
step="60"
id="id_time"
value="{{ form.time.value|time:'H:i' }}"
>
利用:
{{ form.time }}
如果需要修改属性,可以通过表单类定义进行。
问题 2:为什么在初始 GET 表单加载后 POST 到服务器时,时间字段的类型从 datetime.time 变为 string?
在 GET 流中,值设置为默认值,即 python 时间对象。对于 POST 流,值设置为request.POST
作为字符串传入的值。如果你要运行,.is_valid()
那么检查form.cleaned_data['time']
它是否是datetime.time
.
问题3:为什么Django模板时间标签转换在其输入不包含秒的情况下返回None?
(我认为)这不是因为它没有任何秒数,而是因为它所应用的值是一个字符串。如果你使用cleaned_data
它会正确渲染。cleaned_data
但是,这意味着当它是 GET/POST 或检查表单以查看是否已设置时,您将需要 if/else 来处理。
推荐阅读
- paypal - paypal资金如何拆分到不同的vandor账户?
- ios - 如何禁用添加到项目的特定 SDK 的位码
- python-2.7 - 将 TensorFlow Object Detection Api 模型转换为 TFLite 时出错
- flutter - 如何通过顶部文本字段对齐底部文本字段?
- angular - 如何从指令更改编辑器 [禁用] 属性?
- android - 如何使用离子在画廊中显示下载的图像
- angular - App Engine 上的 Angular 6 - 页面刷新时出现错误 500
- ubuntu-14.04 - Ubuntu上的Instana代理一班轮安装错误
- android - android Fragment中的导航流程
- windows - HTTP 代理后面的 Windows 上的 Minikube