Skip to content

Commit 1c9258c

Browse files
authored
Merge pull request #502 from MongoEngine/number_fields
New model form generator: Support of DecimalField, FloatField, IntField
2 parents 0cbca28 + a27e008 commit 1c9258c

File tree

10 files changed

+336
-37
lines changed

10 files changed

+336
-37
lines changed

docs/forms.md

Lines changed: 137 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,51 @@ Not yet documented. Please help us with new pull request.
9797

9898
### DecimalField
9999

100-
Not yet documented. Please help us with new pull request.
100+
- API: {class}`.db_fields.DecimalField`
101+
- Default form field class: {class}`wtforms.fields.DecimalField`
102+
103+
#### Form generation behaviour
104+
105+
From form generation side this field is pretty standard and do not use any form
106+
generation adjustments.
107+
108+
If database field definition has any of {attr}`min_value` or {attr}`max_value`, then
109+
{class}`~wtforms.validators.NumberRange` validator will be added to form field.
110+
111+
#### Examples
112+
113+
numbers_demo.py in example app contain basic non-requirement example. You can adjust
114+
it to any provided example for test purposes.
115+
116+
##### Not limited DecimalField
117+
118+
```python
119+
"""numbers_demo.py"""
120+
from example_app.models import db
121+
122+
123+
class NumbersDemoModel(db.Document):
124+
"""Documentation example model."""
125+
126+
decimal_field_unlimited = db.DecimalField()
127+
```
128+
129+
##### Limited DecimalField
130+
131+
```python
132+
"""numbers_demo.py"""
133+
from decimal import Decimal
134+
135+
from example_app.models import db
136+
137+
138+
class NumbersDemoModel(db.Document):
139+
"""Documentation example model."""
140+
141+
decimal_field_limited = db.DecimalField(
142+
min_value=Decimal("1"), max_value=Decimal("200.455")
143+
)
144+
```
101145

102146
### DictField
103147

@@ -163,11 +207,101 @@ Not yet documented. Please help us with new pull request.
163207

164208
### FloatField
165209

166-
Not yet documented. Please help us with new pull request.
210+
```{versionchanged} 2.0.0
211+
Default form field class changed from: {class}`wtforms.fields.FloatField` to
212+
{class}`~.fields.MongoFloatField`.
213+
```
214+
215+
- API: {class}`.db_fields.FloatField`
216+
- Default form field class: {class}`~.fields.MongoFloatField`
217+
218+
#### Form generation behaviour
219+
220+
For Mongo database {class}`~.db_fields.FloatField` special WTForm field was created.
221+
This field's behaviour is the same, as for {class}`wtforms.fields.FloatField`,
222+
but the widget is replaced to {class}`~wtforms.widgets.NumberInput`, this should make a
223+
look of generated form better. It is possible, that in some cases usage of base,
224+
{class}`wtforms.fields.FloatField` can be required by form design. Both fields are
225+
completely compatible, and replace can be done with {attr}`wtf_field_class` db form
226+
parameter.
227+
228+
If database field definition has any of {attr}`min_value` or {attr}`max_value`, then
229+
{class}`~wtforms.validators.NumberRange` validator will be added to form field.
230+
231+
#### Examples
232+
233+
numbers_demo.py in example app contain basic non-requirement example. You can adjust
234+
it to any provided example for test purposes.
235+
236+
##### Not limited FloatField
237+
238+
```python
239+
"""numbers_demo.py"""
240+
from example_app.models import db
241+
242+
243+
class NumbersDemoModel(db.Document):
244+
"""Documentation example model."""
245+
246+
float_field_unlimited = db.FloatField()
247+
```
248+
249+
##### Limited FloatField
250+
251+
```python
252+
"""numbers_demo.py"""
253+
from example_app.models import db
254+
255+
256+
class NumbersDemoModel(db.Document):
257+
"""Documentation example model."""
258+
259+
float_field_limited = db.FloatField(min_value=float(1), max_value=200.455)
260+
```
167261

168262
### IntField
169263

170-
Not yet documented. Please help us with new pull request.
264+
- API: {class}`.db_fields.IntField`
265+
- Default form field class: {class}`wtforms.fields.IntegerField`
266+
267+
#### Form generation behaviour
268+
269+
From form generation side this field is pretty standard and do not use any form
270+
generation adjustments.
271+
272+
If database field definition has any of {attr}`min_value` or {attr}`max_value`, then
273+
{class}`~wtforms.validators.NumberRange` validator will be added to form field.
274+
275+
#### Examples
276+
277+
numbers_demo.py in example app contain basic non-requirement example. You can adjust
278+
it to any provided example for test purposes.
279+
280+
##### Not limited IntField
281+
282+
```python
283+
"""numbers_demo.py"""
284+
from example_app.models import db
285+
286+
287+
class NumbersDemoModel(db.Document):
288+
"""Documentation example model."""
289+
290+
integer_field_unlimited = db.IntField()
291+
```
292+
293+
##### Limited IntField
294+
295+
```python
296+
"""numbers_demo.py"""
297+
from example_app.models import db
298+
299+
300+
class NumbersDemoModel(db.Document):
301+
"""Documentation example model."""
302+
303+
integer_field_limited = db.IntField(min_value=1, max_value=200)
304+
```
171305

172306
### ListField
173307

example_app/app.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
from example_app import views
66
from example_app.models import db
7+
from example_app.numbers_demo import numbers_demo_view
78
from example_app.strings_demo import strings_demo_view
89
from flask_mongoengine.panels import mongo_command_logger
910

@@ -45,6 +46,10 @@
4546
app.add_url_rule(
4647
"/strings_demo/<pk>/", view_func=strings_demo_view, methods=["GET", "POST"]
4748
)
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+
)
4853

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

example_app/numbers_demo.py

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
"""Numbers and related fields demo model."""
2+
3+
from decimal import Decimal
4+
5+
from flask import render_template, request
6+
7+
from example_app.models import db
8+
9+
10+
class NumbersDemoModel(db.Document):
11+
"""Documentation example model."""
12+
13+
simple_sting_name = db.StringField()
14+
float_field_unlimited = db.FloatField()
15+
decimal_field_unlimited = db.DecimalField()
16+
integer_field_unlimited = db.IntField()
17+
float_field_limited = db.FloatField(min_value=float(1), max_value=200.455)
18+
decimal_field_limited = db.DecimalField(
19+
min_value=Decimal("1"), max_value=Decimal("200.455")
20+
)
21+
integer_field_limited = db.IntField(min_value=1, max_value=200)
22+
23+
24+
NumbersDemoForm = NumbersDemoModel.to_wtf_form()
25+
26+
27+
def numbers_demo_view(pk=None):
28+
"""Return all fields demonstration."""
29+
form = NumbersDemoForm()
30+
obj = None
31+
if pk:
32+
obj = NumbersDemoModel.objects.get(pk=pk)
33+
form = NumbersDemoForm(obj=obj)
34+
35+
if request.method == "POST" and form.validate_on_submit():
36+
if pk:
37+
form.populate_obj(obj)
38+
obj.save()
39+
else:
40+
form.save()
41+
page_num = int(request.args.get("page") or 1)
42+
page = NumbersDemoModel.objects.paginate(page=page_num, per_page=100)
43+
44+
return render_template(
45+
"numbers_demo.html", page=page, form=form, model=NumbersDemoModel
46+
)

example_app/templates/layout.html

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
<li><a href="{{ url_for("index") }}">Home</a></li>
2020
<li><a href="{{ url_for("pagination") }}">Pagination</a></li>
2121
<li><a href="{{ url_for("strings_demo_view") }}">Strings demo</a></li>
22+
<li><a href="{{ url_for("numbers_demo_view") }}">Numbers demo</a></li>
2223
</ul>
2324
</nav>
2425
<div>
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
{% extends "layout.html" %}
2+
{% from "_formhelpers.html" import render_field %}
3+
{% from "_formhelpers.html" import render_navigation %}
4+
5+
{% block body %}
6+
7+
<div>
8+
<table>
9+
<thead>
10+
<tr>
11+
{% for field in model._fields_ordered %}
12+
<th>{{ model[field].name }}</th>
13+
{% endfor %}
14+
<th>Edit</th>
15+
</tr>
16+
</thead>
17+
<tbody>
18+
{% for page_object in page.items %}
19+
<tr>
20+
{% for field in page_object._fields_ordered %}
21+
<td>{{ page_object[field] }}</td>
22+
{% endfor %}
23+
<td><a href="{{ url_for('numbers_demo_view', pk=page_object.pk) }}">edit</a></td>
24+
</tr>
25+
{% endfor %}
26+
</tbody>
27+
</table>
28+
</div>
29+
<div>
30+
{{ render_navigation(page, "numbers_demo_view") }}
31+
</div>
32+
<div>
33+
<form method="POST">
34+
{% for field in form %}
35+
{{ render_field(field, style='font-weight: bold') }}
36+
{% endfor %}
37+
<input type="submit" value="{% if form.instance %}Edit{% else %}Create{% endif %}">
38+
</form>
39+
</div>
40+
41+
{% endblock %}

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.numbers_demo import NumbersDemoModel
78
from example_app.strings_demo import StringsDemoModel
89

910

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

0 commit comments

Comments
 (0)