Skip to content

Commit 0c0b3b8

Browse files
authored
added to_dict (piccolo-orm#201)
* added `to_dict` * add test for `to_dict` * support aliases in `to_dict` * add docs for `to_dict` * fix typo in docstring * allow a subset of columns to be specified * update docs
1 parent fe6767a commit 0c0b3b8

File tree

3 files changed

+94
-0
lines changed

3 files changed

+94
-0
lines changed

docs/src/piccolo/query_types/objects.rst

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,29 @@ Complex where clauses are supported, but only within reason. For example:
138138
defaults={'popularity': 100}
139139
).run_sync()
140140
141+
to_dict
142+
-------
143+
144+
If you need to convert an object into a dictionary, you can do so using the
145+
``to_dict`` method.
146+
147+
.. code-block:: python
148+
149+
band = Band.objects().first().run_sync()
150+
151+
>>> band.to_dict()
152+
{'id': 1, 'name': 'Pythonistas', 'manager': 1, 'popularity': 1000}
153+
154+
If you only want a subset of the columns, or want to use aliases for some of
155+
the columns:
156+
157+
.. code-block:: python
158+
159+
band = Band.objects().first().run_sync()
160+
161+
>>> band.to_dict(Band.id, Band.name.as_alias('title'))
162+
{'id': 1, 'title': 'Pythonistas'}
163+
141164
142165
Query clauses
143166
-------------

piccolo/table.py

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -407,6 +407,41 @@ def get_related(self, foreign_key: t.Union[ForeignKey, str]) -> Objects:
407407
.first()
408408
)
409409

410+
def to_dict(self, *columns: Column) -> t.Dict[str, t.Any]:
411+
"""
412+
A convenience method which returns a dictionary, mapping column names
413+
to values for this table instance.
414+
415+
.. code-block::
416+
417+
instance = await Manager.objects().get(
418+
Manager.name == 'Guido'
419+
).run()
420+
421+
>>> instance.to_dict()
422+
{'id': 1, 'name': 'Guido'}
423+
424+
If the columns argument is provided, only those columns are included in
425+
the output. It also works with column aliases.
426+
427+
.. code-block::
428+
429+
>>> instance.to_dict(Manager.id, Manager.name.as_alias('title'))
430+
{'id': 1, 'title': 'Guido'}
431+
432+
"""
433+
alias_names = {
434+
column._meta.name: getattr(column, "alias", None)
435+
for column in columns
436+
}
437+
438+
output = {}
439+
for column in columns or self._meta.columns:
440+
output[
441+
alias_names.get(column._meta.name) or column._meta.name
442+
] = getattr(self, column._meta.name)
443+
return output
444+
410445
def __setitem__(self, key: str, value: t.Any):
411446
setattr(self, key, value)
412447

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
from tests.base import DBTestCase
2+
from tests.example_app.tables import Manager
3+
4+
5+
class TestToDict(DBTestCase):
6+
def test_to_dict(self):
7+
"""
8+
Make sure that `to_dict` works correctly.
9+
"""
10+
self.insert_row()
11+
12+
instance = Manager.objects().first().run_sync()
13+
dictionary = instance.to_dict()
14+
self.assertEqual(dictionary, {"id": 1, "name": "Guido"})
15+
16+
def test_filter_rows(self):
17+
"""
18+
Make sure that `to_dict` works correctly with a subset of columns.
19+
"""
20+
self.insert_row()
21+
22+
instance = Manager.objects().first().run_sync()
23+
dictionary = instance.to_dict(Manager.name)
24+
self.assertEqual(dictionary, {"name": "Guido"})
25+
26+
def test_to_dict_aliases(self):
27+
"""
28+
Make sure that `to_dict` works correctly with aliases.
29+
"""
30+
self.insert_row()
31+
32+
instance = Manager.objects().first().run_sync()
33+
dictionary = instance.to_dict(
34+
Manager.id, Manager.name.as_alias("title")
35+
)
36+
self.assertEqual(dictionary, {"id": 1, "title": "Guido"})

0 commit comments

Comments
 (0)