Skip to content

Commit ed5be28

Browse files
authored
Merge pull request #504 from MongoEngine/datetime_fields
New model form generator: Support of ComplexDateTimeField, DateField, DateTimeField
2 parents 1c9258c + e5101e1 commit ed5be28

File tree

11 files changed

+271
-99
lines changed

11 files changed

+271
-99
lines changed

docs/forms.md

Lines changed: 158 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -87,13 +87,169 @@ Not yet documented. Please help us with new pull request.
8787

8888
Not yet documented. Please help us with new pull request.
8989

90+
### ComplexDateTimeField
91+
92+
- API: {class}`.db_fields.ComplexDateTimeField`
93+
- Default form field class: {class}`wtforms.fields.DateTimeLocalField`
94+
95+
#### Form generation behaviour
96+
97+
ComplexDateTimeField stores date and time information in database `string` format. This
98+
format allow precision up to microseconds dimension.
99+
100+
Unfortunately, there is no HTML5 field, that allow so high precision. That's why, by
101+
default the generated field will use HTML5 `<input type="datetime-local">` with
102+
precision set to milliseconds.
103+
104+
If you require concrete microseconds for edit purposes, please use
105+
{class}`wtforms.fields.DateTimeField` with correct format (see examples below).
106+
107+
Field is easy adjustable, to use any other precision. Check examples and example app
108+
for more details.
109+
110+
#### Examples
111+
112+
dates_demo.py in example app contain basic non-requirement example. You can adjust
113+
it to any provided example for test purposes.
114+
115+
##### ComplexDateTimeField with milliseconds precision
116+
117+
```python
118+
"""dates_demo.py"""
119+
from example_app.models import db
120+
121+
122+
class DateTimeModel(db.Document):
123+
"""Documentation example model."""
124+
125+
complex_datetime = db.ComplexDateTimeField()
126+
```
127+
128+
##### ComplexDateTimeField with seconds precision
129+
130+
```python
131+
"""dates_demo.py"""
132+
from example_app.models import db
133+
134+
135+
class DateTimeModel(db.Document):
136+
"""Documentation example model."""
137+
138+
complex_datetime_sec = db.ComplexDateTimeField(
139+
wtf_options={"render_kw": {"step": "1"}}
140+
)
141+
```
142+
143+
##### ComplexDateTimeField with microseconds precision (text)
144+
145+
```python
146+
"""dates_demo.py"""
147+
from wtforms.fields import DateTimeField
148+
149+
from example_app.models import db
150+
151+
152+
class DateTimeModel(db.Document):
153+
"""Documentation example model."""
154+
155+
complex_datetime_microseconds = db.ComplexDateTimeField(
156+
wtf_field_class=DateTimeField, wtf_options={"format": "%Y-%m-%d %H:%M:%S.%f"}
157+
)
158+
```
159+
90160
### DateField
91161

92-
Not yet documented. Please help us with new pull request.
162+
- API: {class}`.db_fields.DateField`
163+
- Default form field class: {class}`wtforms.fields.DateField`
164+
165+
#### Form generation behaviour
166+
167+
DateField is one of the simplest fields in the forms generation process. By default,
168+
the field use {class}`wtforms.fields.DateField` WTForms class, representing a form
169+
input with standard HTML5 `<input type="date">`. No custom additional transformation
170+
done, during field generation. Field is fully controllable by [global transforms].
171+
172+
#### Examples
173+
174+
dates_demo.py in example app contain basic non-requirement example. You can adjust
175+
it to any provided example for test purposes.
176+
177+
```python
178+
"""dates_demo.py"""
179+
from example_app.models import db
180+
181+
182+
class DateTimeModel(db.Document):
183+
"""Documentation example model."""
184+
185+
date = db.DateField()
186+
```
187+
188+
##### Not limited DateField
189+
190+
```python
191+
pass
192+
```
93193

94194
### DateTimeField
95195

96-
Not yet documented. Please help us with new pull request.
196+
- API: {class}`.db_fields.DateTimeField`
197+
- Default form field class: {class}`wtforms.fields.DateTimeLocalField`
198+
199+
#### Form generation behaviour
200+
201+
DateTimeField stores date and time information in database `date` format. This
202+
format allow precision up to milliseconds dimension. By default, generated form will
203+
use HTML5 `<input type="datetime-local">` with precision set to seconds.
204+
205+
Field is easy adjustable, to use any other precision. Check examples and example app
206+
for more details.
207+
208+
It is possible to use {class}`wtforms.fields.DateTimeField` for text input behaviour.
209+
210+
#### Examples
211+
212+
dates_demo.py in example app contain basic non-requirement example. You can adjust
213+
it to any provided example for test purposes.
214+
215+
##### DateTimeField with seconds precision
216+
217+
```python
218+
"""dates_demo.py"""
219+
from example_app.models import db
220+
221+
222+
class DateTimeModel(db.Document):
223+
"""Documentation example model."""
224+
225+
datetime = db.DateTimeField()
226+
```
227+
228+
##### DateTimeField without seconds
229+
230+
```python
231+
"""dates_demo.py"""
232+
from example_app.models import db
233+
234+
235+
class DateTimeModel(db.Document):
236+
"""Documentation example model."""
237+
238+
datetime_no_sec = db.DateTimeField(wtf_options={"render_kw": {"step": "60"}})
239+
```
240+
241+
##### DateTimeField with milliseconds precision
242+
243+
```python
244+
"""dates_demo.py"""
245+
from example_app.models import db
246+
247+
248+
class DateTimeModel(db.Document):
249+
"""Documentation example model."""
250+
251+
datetime_ms = db.DateTimeField(wtf_options={"render_kw": {"step": "0.001"}})
252+
```
97253

98254
### DecimalField
99255

@@ -533,10 +689,6 @@ class StringsDemoModel(db.Document):
533689

534690
Not yet documented. Please help us with new pull request.
535691

536-
### ComplexDateTimeField
537-
538-
Not yet documented. Please help us with new pull request.
539-
540692
### DynamicField
541693

542694
Not yet documented. Please help us with new pull request.

example_app/app.py

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
from pymongo import monitoring
44

55
from example_app import views
6+
from example_app.dates_demo import dates_demo_view
67
from example_app.models import db
78
from example_app.numbers_demo import numbers_demo_view
89
from example_app.strings_demo import strings_demo_view
@@ -42,14 +43,12 @@
4243

4344
app.add_url_rule("/", view_func=views.index, methods=["GET", "POST"])
4445
app.add_url_rule("/pagination", view_func=views.pagination, methods=["GET", "POST"])
45-
app.add_url_rule("/strings_demo", view_func=strings_demo_view, methods=["GET", "POST"])
46-
app.add_url_rule(
47-
"/strings_demo/<pk>/", view_func=strings_demo_view, methods=["GET", "POST"]
48-
)
49-
app.add_url_rule("/numbers_demo", view_func=numbers_demo_view, methods=["GET", "POST"])
50-
app.add_url_rule(
51-
"/numbers_demo/<pk>/", view_func=numbers_demo_view, methods=["GET", "POST"]
52-
)
46+
app.add_url_rule("/strings", view_func=strings_demo_view, methods=["GET", "POST"])
47+
app.add_url_rule("/strings/<pk>/", view_func=strings_demo_view, methods=["GET", "POST"])
48+
app.add_url_rule("/numbers", view_func=numbers_demo_view, methods=["GET", "POST"])
49+
app.add_url_rule("/numbers/<pk>/", view_func=numbers_demo_view, methods=["GET", "POST"])
50+
app.add_url_rule("/dates", view_func=dates_demo_view, methods=["GET", "POST"])
51+
app.add_url_rule("/dates/<pk>/", view_func=dates_demo_view, methods=["GET", "POST"])
5352

5453
if __name__ == "__main__":
5554
app.run(host="0.0.0.0", port=8000)

example_app/dates_demo.py

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
"""Date and DateTime fields demo model."""
2+
3+
from flask import render_template, request
4+
from wtforms.fields import DateTimeField
5+
6+
from example_app.models import db
7+
8+
9+
class DateTimeModel(db.Document):
10+
"""Documentation example model."""
11+
12+
any_string = db.StringField()
13+
date = db.DateField()
14+
datetime = db.DateTimeField()
15+
datetime_no_sec = db.DateTimeField(wtf_options={"render_kw": {"step": "60"}})
16+
datetime_ms = db.DateTimeField(wtf_options={"render_kw": {"step": "0.001"}})
17+
complex_datetime = db.ComplexDateTimeField()
18+
complex_datetime_sec = db.ComplexDateTimeField(
19+
wtf_options={"render_kw": {"step": "1"}}
20+
)
21+
complex_datetime_microseconds = db.ComplexDateTimeField(
22+
wtf_field_class=DateTimeField, wtf_options={"format": "%Y-%m-%d %H:%M:%S.%f"}
23+
)
24+
25+
26+
DateTimeDemoForm = DateTimeModel.to_wtf_form()
27+
28+
29+
def dates_demo_view(pk=None):
30+
"""Return all fields demonstration."""
31+
form = DateTimeDemoForm()
32+
obj = None
33+
if pk:
34+
obj = DateTimeModel.objects.get(pk=pk)
35+
form = DateTimeDemoForm(obj=obj)
36+
37+
if request.method == "POST" and form.validate_on_submit():
38+
if pk:
39+
form.populate_obj(obj)
40+
obj.save()
41+
else:
42+
form.save()
43+
page_num = int(request.args.get("page") or 1)
44+
page = DateTimeModel.objects.paginate(page=page_num, per_page=100)
45+
46+
return render_template(
47+
"form_demo.html",
48+
view=dates_demo_view.__name__,
49+
page=page,
50+
form=form,
51+
model=DateTimeModel,
52+
)

example_app/numbers_demo.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,5 +42,9 @@ def numbers_demo_view(pk=None):
4242
page = NumbersDemoModel.objects.paginate(page=page_num, per_page=100)
4343

4444
return render_template(
45-
"numbers_demo.html", page=page, form=form, model=NumbersDemoModel
45+
"form_demo.html",
46+
view=numbers_demo_view.__name__,
47+
page=page,
48+
form=form,
49+
model=NumbersDemoModel,
4650
)

example_app/strings_demo.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,5 +48,9 @@ def strings_demo_view(pk=None):
4848
page = StringsDemoModel.objects.paginate(page=page_num, per_page=100)
4949

5050
return render_template(
51-
"strings_demo.html", page=page, form=form, model=StringsDemoModel
51+
"form_demo.html",
52+
view=strings_demo_view.__name__,
53+
page=page,
54+
form=form,
55+
model=StringsDemoModel,
5256
)

example_app/templates/numbers_demo.html renamed to example_app/templates/form_demo.html

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
<thead>
1010
<tr>
1111
{% for field in model._fields_ordered %}
12-
<th>{{ model[field].name }}</th>
12+
<th>{{ model[field].verbose_name or model[field].name}}</th>
1313
{% endfor %}
1414
<th>Edit</th>
1515
</tr>
@@ -20,14 +20,14 @@
2020
{% for field in page_object._fields_ordered %}
2121
<td>{{ page_object[field] }}</td>
2222
{% endfor %}
23-
<td><a href="{{ url_for('numbers_demo_view', pk=page_object.pk) }}">edit</a></td>
23+
<td><a href="{{ url_for(view, pk=page_object.pk) }}">edit</a></td>
2424
</tr>
2525
{% endfor %}
2626
</tbody>
2727
</table>
2828
</div>
2929
<div>
30-
{{ render_navigation(page, "numbers_demo_view") }}
30+
{{ render_navigation(page, view) }}
3131
</div>
3232
<div>
3333
<form method="POST">

example_app/templates/layout.html

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
<li><a href="{{ url_for("pagination") }}">Pagination</a></li>
2121
<li><a href="{{ url_for("strings_demo_view") }}">Strings demo</a></li>
2222
<li><a href="{{ url_for("numbers_demo_view") }}">Numbers demo</a></li>
23+
<li><a href="{{ url_for("dates_demo_view") }}">DateTime demo</a></li>
2324
</ul>
2425
</nav>
2526
<div>

example_app/templates/strings_demo.html

Lines changed: 0 additions & 41 deletions
This file was deleted.

example_app/views.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
from mongoengine.context_managers import switch_db
55

66
from example_app import models
7+
from example_app.dates_demo import DateTimeModel
78
from example_app.numbers_demo import NumbersDemoModel
89
from example_app.strings_demo import StringsDemoModel
910

@@ -49,6 +50,7 @@ def delete_data():
4950
"""Clear database."""
5051
with switch_db(models.Todo, "default"):
5152
models.Todo.objects().delete()
53+
DateTimeModel.objects().delete()
5254
StringsDemoModel.objects().delete()
5355
NumbersDemoModel.objects().delete()
5456
with switch_db(models.Todo, "secondary"):

0 commit comments

Comments
 (0)