Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit dc774c6

Browse filesBrowse files
gh-96168: Add sqlite3 row factory how-to
1 parent ee821dc commit dc774c6
Copy full SHA for dc774c6

File tree

Expand file treeCollapse file tree

1 file changed

+82
-33
lines changed
Filter options
Expand file treeCollapse file tree

1 file changed

+82
-33
lines changed

‎Doc/library/sqlite3.rst

Copy file name to clipboardExpand all lines: Doc/library/sqlite3.rst
+82-33Lines changed: 82 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1320,27 +1320,11 @@ Connection objects
13201320
a :class:`Cursor` object and the raw row results as a :class:`tuple`,
13211321
and returns a custom object representing an SQLite row.
13221322

1323-
Example:
1324-
1325-
.. doctest::
1326-
1327-
>>> def dict_factory(cursor, row):
1328-
... col_names = [col[0] for col in cursor.description]
1329-
... return {key: value for key, value in zip(col_names, row)}
1330-
>>> con = sqlite3.connect(":memory:")
1331-
>>> con.row_factory = dict_factory
1332-
>>> for row in con.execute("SELECT 1 AS a, 2 AS b"):
1333-
... print(row)
1334-
{'a': 1, 'b': 2}
1335-
13361323
If returning a tuple doesn't suffice and you want name-based access to
13371324
columns, you should consider setting :attr:`row_factory` to the
1338-
highly optimized :class:`sqlite3.Row` type. :class:`Row` provides both
1339-
index-based and case-insensitive name-based access to columns with almost no
1340-
memory overhead. It will probably be better than your own custom
1341-
dictionary-based approach or even a db_row based solution.
1325+
highly optimized :class:`sqlite3.Row`
13421326

1343-
.. XXX what's a db_row-based solution?
1327+
See :ref:`sqlite3-row-factory-how-to` for more details.
13441328

13451329
.. attribute:: text_factory
13461330

@@ -1611,6 +1595,8 @@ Row objects
16111595

16121596
Two row objects compare equal if have equal columns and equal members.
16131597

1598+
See :ref:`sqlite3-row-factory-how-to` for more details.
1599+
16141600
.. method:: keys
16151601

16161602
Return a :class:`list` of column names as :class:`strings <str>`.
@@ -1620,21 +1606,6 @@ Row objects
16201606
.. versionchanged:: 3.5
16211607
Added support of slicing.
16221608

1623-
Example:
1624-
1625-
.. doctest::
1626-
1627-
>>> con = sqlite3.connect(":memory:")
1628-
>>> con.row_factory = sqlite3.Row
1629-
>>> res = con.execute("SELECT 'Earth' AS name, 6378 AS radius")
1630-
>>> row = res.fetchone()
1631-
>>> row.keys()
1632-
['name', 'radius']
1633-
>>> row[0], row["name"] # Access by index and name.
1634-
('Earth', 'Earth')
1635-
>>> row["RADIUS"] # Column names are case-insensitive.
1636-
6378
1637-
16381609

16391610
.. _sqlite3-blob-objects:
16401611

@@ -2358,6 +2329,84 @@ can be found in the `SQLite URI documentation`_.
23582329
.. _SQLite URI documentation: https://www.sqlite.org/uri.html
23592330

23602331

2332+
.. _sqlite3-row-factory-how-to:
2333+
2334+
How to work with row factories
2335+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
2336+
2337+
By default, :mod:`!sqlite3` represent fetched rows as :class:`tuples <tuple>`.
2338+
If a :class:`!tuple` does not suit your needs,
2339+
use the built-in :class:`Row` type or a custom :attr:`~Connection.row_factory`.
2340+
The former provides both indexed and case-insensitive named access to columns,
2341+
with low memory overhead and minimal performance impact.
2342+
Example use:
2343+
2344+
.. doctest::
2345+
2346+
>>> con = sqlite3.connect(":memory:")
2347+
>>> con.row_factory = sqlite3.Row
2348+
>>> res = con.execute("SELECT 'Earth' AS name, 6378 AS radius")
2349+
>>> row = res.fetchone()
2350+
>>> row.keys()
2351+
['name', 'radius']
2352+
>>> row[0], row["name"] # Access by index and name.
2353+
('Earth', 'Earth')
2354+
>>> row["RADIUS"] # Column names are case-insensitive.
2355+
6378
2356+
2357+
If you need more flexibility, you can design your own row factory.
2358+
Here's an example of a :class:`dict` row factory:
2359+
2360+
.. doctest::
2361+
2362+
>>> def dict_factory(cursor, row):
2363+
... col_names = [col[0] for col in cursor.description]
2364+
... return {key: value for key, value in zip(col_names, row)}
2365+
2366+
>>> con = sqlite3.connect(":memory:")
2367+
>>> con.row_factory = dict_factory
2368+
>>> for row in con.execute("SELECT 1 AS a, 2 AS b"):
2369+
... print(row)
2370+
{'a': 1, 'b': 2}
2371+
2372+
Here's an example of a optimised :class:`~collections.namedtuple` factory:
2373+
2374+
.. testcode::
2375+
2376+
from collections import namedtuple
2377+
from functools import lru_cache
2378+
2379+
def _fields(cursor):
2380+
return [col[0] for col in cursor.description]
2381+
2382+
@lru_cache
2383+
def _make_cls(fields):
2384+
return namedtuple("Row", fields)
2385+
2386+
def NamedTupleFactory(cursor, row):
2387+
cls = _make_cls(_fields(cursor))
2388+
return cls._make(row)
2389+
2390+
Example use:
2391+
2392+
.. doctest::
2393+
2394+
>>> con = sqlite3.connect(":memory:")
2395+
>>> con.row_factory = NamedTupleRow
2396+
>>> cur = con.execute("SELECT 1 AS a, 2 AS b")
2397+
>>> row = cur.fetchone()
2398+
>>> row
2399+
Row(a='1', b='2')
2400+
>>> row[0] # Indexed access.
2401+
1
2402+
>>> row.b # Attribute access.
2403+
2
2404+
2405+
With some adjustments, the above recipe can be adapted to use a
2406+
:class:`~dataclasses.dataclass`, or any other custom class,
2407+
instead of a :class:`~collection.namedtuple`.
2408+
2409+
23612410
.. _sqlite3-explanation:
23622411

23632412
Explanation

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.