Django Time字段相互交织的问题迫使黑客修改/显示时间

时间:2019-01-22 21:58:31

标签: django

Django 2

这里有很多信息。我将尝试总结问题的实质。

背景事实:为“时间”字段设置默认值需要在模型参考:https://code.djangoproject.com/ticket/6754

中设置datetime.time

这里有两个相关的问题。

问题1:时间字段的数据类型更改

第一个问题是,下面的Django页面的初始GET返回数据类型为<class 'datetime.time'>的时间字段。很好,这是预期的。

但是,如果您通过POST提交表单,并且存在字段验证错误,则 “时间”字段的数据类型会更改为字符串 < / strong>。查看此问题底部的服务器日志以查看。结果,数据的格式也会改变-请注意,秒数会丢失。这也可以在下面的服务器日志中看到。

这会导致问题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表单加载后将时间字段的类型从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 个答案:

答案 0 :(得分:1)

  

问题1:如何在不借助强制手段的情况下解决此问题   时间字段通过一个附加字段转换为字符串。   这行得通,但这只是解决上述问题的一种手段。

您应该使用模板中的表单字段来解决此问题。而不是

<input
        type="time"
        name="time"
        required
        step="60"
        id="id_time"
        value="{{ form.time.value|time:'H:i' }}"
>

使用:

 {{ form.time }}

如果需要修改属性,可以通过表单类定义来完成。

  

问题2:为什么时间字段的类型从   将datetime.time转换为字符串后,将其发布到服务器时   初始GET表单加载?

在GET流中,值设置为默认值,即python时间对象。对于POST流,将value设置为来自request.POST的字符串形式的值。如果您要运行.is_valid(),然后选中form.cleaned_data['time'],则它将是datetime.time的实例。

  

问题3:为什么Django模板的时间标签转换   当其输入不包含秒数时返回None?

(我认为)这不是因为它没有任何秒数,而是因为它要应用的值是一个字符串。如果使用cleaned_data,它将正确呈现。但是,这意味着当它是GET / POST时或在表单上检查是否已设置cleaned_data时,将需要if / else处理。