summaryrefslogtreecommitdiff
path: root/doc/build/orm/tutorial.rst
diff options
context:
space:
mode:
authorMike Bayer <mike_mp@zzzcomputing.com>2020-06-06 20:40:43 -0400
committerMike Bayer <mike_mp@zzzcomputing.com>2020-06-10 15:29:01 -0400
commitb0cfa7379cf8513a821a3dbe3028c4965d9f85bd (patch)
tree19a79632b4f159092d955765ff9f7e842808bce7 /doc/build/orm/tutorial.rst
parent3ab2364e78641c4f0e4b6456afc2cbed39b0d0e6 (diff)
downloadsqlalchemy-b0cfa7379cf8513a821a3dbe3028c4965d9f85bd.tar.gz
Turn on caching everywhere, add logging
A variety of caching issues found by running all tests with statement caching turned on. The cache system now has a more conservative approach where any subclass of a SQL element will by default invalidate the cache key unless it adds the flag inherit_cache=True at the class level, or if it implements its own caching. Add working caching to a few elements that were omitted previously; fix some caching implementations to suit lesser used edge cases such as json casts and array slices. Refine the way BaseCursorResult and CursorMetaData interact with caching; to suit cases like Alembic modifying table structures, don't cache the cursor metadata if it were created against a cursor.description using non-positional matching, e.g. "select *". if a table re-ordered its columns or added/removed, now that data is obsolete. Additionally we have to adapt the cursor metadata _keymap regardless of if we just processed cursor.description, because if we ran against a cached SQLCompiler we won't have the right columns in _keymap. Other refinements to how and when we do this adaption as some weird cases were exposed in the Postgresql dialect, a text() construct that names just one column that is not actually in the statement. Fixed that also as it looks like a cut-and-paste artifact that doesn't actually affect anything. Various issues with re-use of compiled result maps and cursor metadata in conjunction with tables being changed, such as change in order of columns. mappers can be cleared but the class remains, meaning a mapper has to use itself as the cache key not the class. lots of bound parameter / literal issues, due to Alembic creating a straight subclass of bindparam that renders inline directly. While we can update Alembic to not do this, we have to assume other people might be doing this, so bindparam() implements the inherit_cache=True logic as well that was a bit involved. turn on cache stats in logging. Includes a fix to subqueryloader which moves all setup to the create_row_processor() phase and elminates any storage within the compiled context. This includes some changes to create_row_processor() signature and a revising of the technique used to determine if the loader can participate in polymorphic queries, which is also applied to selectinloading. DML update.values() and ordered_values() now coerces the keys as we have tests that pass an arbitrary class here which only includes __clause_element__(), so the key can't be cached unless it is coerced. this in turn changed how composite attributes support bulk update to use the standard approach of ClauseElement with annotations that are parsed in the ORM context. memory profiling successfully caught that the Session from Query was getting passed into _statement_20() so that was a big win for that test suite. Apparently Compiler had .execute() and .scalar() methods stuck on it, these date back to version 0.4 and there was a single test in the PostgreSQL dialect tests that exercised it for no apparent reason. Removed these methods as well as the concept of a Compiler holding onto a "bind". Fixes: #5386 Change-Id: I990b43aab96b42665af1b2187ad6020bee778784
Diffstat (limited to 'doc/build/orm/tutorial.rst')
-rw-r--r--doc/build/orm/tutorial.rst156
1 files changed, 78 insertions, 78 deletions
diff --git a/doc/build/orm/tutorial.rst b/doc/build/orm/tutorial.rst
index c08daa7fd..8ea8af4a2 100644
--- a/doc/build/orm/tutorial.rst
+++ b/doc/build/orm/tutorial.rst
@@ -210,16 +210,16 @@ the actual ``CREATE TABLE`` statement:
>>> Base.metadata.create_all(engine)
PRAGMA main.table_info("users")
- ()
+ [...] ()
PRAGMA temp.table_info("users")
- ()
+ [...] ()
CREATE TABLE users (
id INTEGER NOT NULL, name VARCHAR,
fullname VARCHAR,
nickname VARCHAR,
PRIMARY KEY (id)
)
- ()
+ [...] ()
COMMIT
.. topic:: Minimal Table Descriptions vs. Full Descriptions
@@ -373,7 +373,7 @@ added:
{sql}>>> our_user = session.query(User).filter_by(name='ed').first() # doctest:+NORMALIZE_WHITESPACE
BEGIN (implicit)
INSERT INTO users (name, fullname, nickname) VALUES (?, ?, ?)
- ('ed', 'Ed Jones', 'edsnickname')
+ [...] ('ed', 'Ed Jones', 'edsnickname')
SELECT users.id AS users_id,
users.name AS users_name,
users.fullname AS users_fullname,
@@ -381,7 +381,7 @@ added:
FROM users
WHERE users.name = ?
LIMIT ? OFFSET ?
- ('ed', 1, 0)
+ [...] ('ed', 1, 0)
{stop}>>> our_user
<User(name='ed', fullname='Ed Jones', nickname='edsnickname')>
@@ -448,13 +448,13 @@ three new ``User`` objects we've added:
{sql}>>> session.commit()
UPDATE users SET nickname=? WHERE users.id = ?
- ('eddie', 1)
+ [...] ('eddie', 1)
INSERT INTO users (name, fullname, nickname) VALUES (?, ?, ?)
- ('wendy', 'Wendy Williams', 'windy')
+ [...] ('wendy', 'Wendy Williams', 'windy')
INSERT INTO users (name, fullname, nickname) VALUES (?, ?, ?)
- ('mary', 'Mary Contrary', 'mary')
+ [...] ('mary', 'Mary Contrary', 'mary')
INSERT INTO users (name, fullname, nickname) VALUES (?, ?, ?)
- ('fred', 'Fred Flintstone', 'freddy')
+ [...] ('fred', 'Fred Flintstone', 'freddy')
COMMIT
:meth:`~.Session.commit` flushes the remaining changes to the
@@ -475,7 +475,7 @@ If we look at Ed's ``id`` attribute, which earlier was ``None``, it now has a va
users.nickname AS users_nickname
FROM users
WHERE users.id = ?
- (1,)
+ [...] (1,)
{stop}1
After the :class:`~sqlalchemy.orm.session.Session` inserts new rows in the
@@ -519,16 +519,16 @@ Querying the session, we can see that they're flushed into the current transacti
{sql}>>> session.query(User).filter(User.name.in_(['Edwardo', 'fakeuser'])).all()
UPDATE users SET name=? WHERE users.id = ?
- ('Edwardo', 1)
+ [...] ('Edwardo', 1)
INSERT INTO users (name, fullname, nickname) VALUES (?, ?, ?)
- ('fakeuser', 'Invalid', '12345')
+ [...] ('fakeuser', 'Invalid', '12345')
SELECT users.id AS users_id,
users.name AS users_name,
users.fullname AS users_fullname,
users.nickname AS users_nickname
FROM users
WHERE users.name IN (?, ?)
- ('Edwardo', 'fakeuser')
+ [...] ('Edwardo', 'fakeuser')
{stop}[<User(name='Edwardo', fullname='Ed Jones', nickname='eddie')>, <User(name='fakeuser', fullname='Invalid', nickname='12345')>]
Rolling back, we can see that ``ed_user``'s name is back to ``ed``, and
@@ -548,7 +548,7 @@ Rolling back, we can see that ``ed_user``'s name is back to ``ed``, and
users.nickname AS users_nickname
FROM users
WHERE users.id = ?
- (1,)
+ [...] (1,)
{stop}u'ed'
>>> fake_user in session
False
@@ -564,7 +564,7 @@ issuing a SELECT illustrates the changes made to the database:
users.nickname AS users_nickname
FROM users
WHERE users.name IN (?, ?)
- ('ed', 'fakeuser')
+ [...] ('ed', 'fakeuser')
{stop}[<User(name='ed', fullname='Ed Jones', nickname='eddie')>]
.. _ormtutorial_querying:
@@ -590,7 +590,7 @@ returned:
users.fullname AS users_fullname,
users.nickname AS users_nickname
FROM users ORDER BY users.id
- ()
+ [...] ()
{stop}ed Ed Jones
wendy Wendy Williams
mary Mary Contrary
@@ -609,7 +609,7 @@ is expressed as tuples:
SELECT users.name AS users_name,
users.fullname AS users_fullname
FROM users
- ()
+ [...] ()
{stop}ed Ed Jones
wendy Wendy Williams
mary Mary Contrary
@@ -630,7 +630,7 @@ class:
users.fullname AS users_fullname,
users.nickname AS users_nickname
FROM users
- ()
+ [...] ()
{stop}<User(name='ed', fullname='Ed Jones', nickname='eddie')> ed
<User(name='wendy', fullname='Wendy Williams', nickname='windy')> wendy
<User(name='mary', fullname='Mary Contrary', nickname='mary')> mary
@@ -647,7 +647,7 @@ is mapped to one (such as ``User.name``):
... print(row.name_label)
SELECT users.name AS name_label
FROM users
- (){stop}
+ [...] (){stop}
ed
wendy
mary
@@ -669,7 +669,7 @@ entities are present in the call to :meth:`~.Session.query`, can be controlled u
user_alias.fullname AS user_alias_fullname,
user_alias.nickname AS user_alias_nickname
FROM users AS user_alias
- (){stop}
+ [...] (){stop}
<User(name='ed', fullname='Ed Jones', nickname='eddie')>
<User(name='wendy', fullname='Wendy Williams', nickname='windy')>
<User(name='mary', fullname='Mary Contrary', nickname='mary')>
@@ -689,7 +689,7 @@ conjunction with ORDER BY:
users.nickname AS users_nickname
FROM users ORDER BY users.id
LIMIT ? OFFSET ?
- (2, 1){stop}
+ [...] (2, 1){stop}
<User(name='wendy', fullname='Wendy Williams', nickname='windy')>
<User(name='mary', fullname='Mary Contrary', nickname='mary')>
@@ -703,7 +703,7 @@ and filtering results, which is accomplished either with
... print(name)
SELECT users.name AS users_name FROM users
WHERE users.fullname = ?
- ('Ed Jones',)
+ [...] ('Ed Jones',)
{stop}ed
...or :func:`~sqlalchemy.orm.query.Query.filter`, which uses more flexible SQL
@@ -717,7 +717,7 @@ operators with the class-level attributes on your mapped class:
... print(name)
SELECT users.name AS users_name FROM users
WHERE users.fullname = ?
- ('Ed Jones',)
+ [...] ('Ed Jones',)
{stop}ed
The :class:`~sqlalchemy.orm.query.Query` object is fully **generative**, meaning
@@ -739,7 +739,7 @@ users named "ed" with a full name of "Ed Jones", you can call
users.nickname AS users_nickname
FROM users
WHERE users.name = ? AND users.fullname = ?
- ('ed', 'Ed Jones')
+ [...] ('ed', 'Ed Jones')
{stop}<User(name='ed', fullname='Ed Jones', nickname='eddie')>
Common Filter Operators
@@ -861,7 +861,7 @@ database results. Here's a brief tour:
users.nickname AS users_nickname
FROM users
WHERE users.name LIKE ? ORDER BY users.id
- ('%ed',)
+ [...] ('%ed',)
{stop}[<User(name='ed', fullname='Ed Jones', nickname='eddie')>,
<User(name='fred', fullname='Fred Flintstone', nickname='freddy')>]
@@ -893,7 +893,7 @@ database results. Here's a brief tour:
FROM users
WHERE users.name LIKE ? ORDER BY users.id
LIMIT ? OFFSET ?
- ('%ed', 1, 0)
+ [...] ('%ed', 1, 0)
{stop}<User(name='ed', fullname='Ed Jones', nickname='eddie')>
* :meth:`_query.Query.one()` fully fetches all rows, and if not
@@ -937,7 +937,7 @@ database results. Here's a brief tour:
SELECT users.id AS users_id
FROM users
WHERE users.name = ? ORDER BY users.id
- ('ed',)
+ [...] ('ed',)
{stop}1
.. _orm_tutorial_literal_sql:
@@ -965,7 +965,7 @@ by most applicable methods. For example,
users.nickname AS users_nickname
FROM users
WHERE id<224 ORDER BY id
- ()
+ [...] ()
{stop}ed
wendy
mary
@@ -985,7 +985,7 @@ method:
users.nickname AS users_nickname
FROM users
WHERE id<? and name=? ORDER BY users.id
- (224, 'fred')
+ [...] (224, 'fred')
{stop}<User(name='fred', fullname='Fred Flintstone', nickname='freddy')>
To use an entirely string-based statement, a :func:`_expression.text` construct
@@ -999,7 +999,7 @@ returned by the SQL statement based on column name::
{sql}>>> session.query(User).from_statement(
... text("SELECT * FROM users where name=:name")).params(name='ed').all()
SELECT * FROM users where name=?
- ('ed',)
+ [...] ('ed',)
{stop}[<User(name='ed', fullname='Ed Jones', nickname='eddie')>]
For better targeting of mapped columns to a textual SELECT, as well as to
@@ -1013,7 +1013,7 @@ columns are passed in the desired order to :meth:`_expression.TextClause.columns
>>> stmt = stmt.columns(User.name, User.id, User.fullname, User.nickname)
{sql}>>> session.query(User).from_statement(stmt).params(name='ed').all()
SELECT name, id, fullname, nickname FROM users where name=?
- ('ed',)
+ [...] ('ed',)
{stop}[<User(name='ed', fullname='Ed Jones', nickname='eddie')>]
When selecting from a :func:`_expression.text` construct, the :class:`_query.Query`
@@ -1028,7 +1028,7 @@ any other case:
{sql}>>> session.query(User.id, User.name).\
... from_statement(stmt).params(name='ed').all()
SELECT name, id FROM users where name=?
- ('ed',)
+ [...] ('ed',)
{stop}[(1, u'ed')]
.. seealso::
@@ -1052,7 +1052,7 @@ counting called :meth:`~sqlalchemy.orm.query.Query.count()`:
users.nickname AS users_nickname
FROM users
WHERE users.name LIKE ?) AS anon_1
- ('%ed',)
+ [...] ('%ed',)
{stop}2
.. sidebar:: Counting on ``count()``
@@ -1085,7 +1085,7 @@ use it to return the count of each distinct user name:
{sql}>>> session.query(func.count(User.name), User.name).group_by(User.name).all()
SELECT count(users.name) AS count_1, users.name AS users_name
FROM users GROUP BY users.name
- ()
+ [...] ()
{stop}[(1, u'ed'), (1, u'fred'), (1, u'mary'), (1, u'wendy')]
To achieve our simple ``SELECT count(*) FROM table``, we can apply it as:
@@ -1095,7 +1095,7 @@ To achieve our simple ``SELECT count(*) FROM table``, we can apply it as:
{sql}>>> session.query(func.count('*')).select_from(User).scalar()
SELECT count(?) AS count_1
FROM users
- ('*',)
+ [...] ('*',)
{stop}4
The usage of :meth:`_query.Query.select_from` can be removed if we express the count in terms
@@ -1106,7 +1106,7 @@ of the ``User`` primary key directly:
{sql}>>> session.query(func.count(User.id)).scalar()
SELECT count(users.id) AS count_1
FROM users
- ()
+ [...] ()
{stop}4
.. _orm_tutorial_relationship:
@@ -1223,7 +1223,7 @@ already been created:
PRIMARY KEY (id),
FOREIGN KEY(user_id) REFERENCES users (id)
)
- ()
+ [...] ()
COMMIT
Working with Related Objects
@@ -1272,11 +1272,11 @@ known as **cascading**:
>>> session.add(jack)
{sql}>>> session.commit()
INSERT INTO users (name, fullname, nickname) VALUES (?, ?, ?)
- ('jack', 'Jack Bean', 'gjffdd')
+ [...] ('jack', 'Jack Bean', 'gjffdd')
INSERT INTO addresses (email_address, user_id) VALUES (?, ?)
- ('jack@google.com', 5)
+ [...] ('jack@google.com', 5)
INSERT INTO addresses (email_address, user_id) VALUES (?, ?)
- ('j25@yahoo.com', 5)
+ [...] ('j25@yahoo.com', 5)
COMMIT
Querying for Jack, we get just Jack back. No SQL is yet issued for Jack's addresses:
@@ -1292,7 +1292,7 @@ Querying for Jack, we get just Jack back. No SQL is yet issued for Jack's addre
users.nickname AS users_nickname
FROM users
WHERE users.name = ?
- ('jack',)
+ [...] ('jack',)
{stop}>>> jack
<User(name='jack', fullname='Jack Bean', nickname='gjffdd')>
@@ -1308,7 +1308,7 @@ Let's look at the ``addresses`` collection. Watch the SQL:
addresses.user_id AS addresses_user_id
FROM addresses
WHERE ? = addresses.user_id ORDER BY addresses.id
- (5,)
+ [...] (5,)
{stop}[<Address(email_address='jack@google.com')>, <Address(email_address='j25@yahoo.com')>]
When we accessed the ``addresses`` collection, SQL was suddenly issued. This
@@ -1349,7 +1349,7 @@ Below we load the ``User`` and ``Address`` entities at once using this method:
FROM users, addresses
WHERE users.id = addresses.user_id
AND addresses.email_address = ?
- ('jack@google.com',)
+ [...] ('jack@google.com',)
{stop}<User(name='jack', fullname='Jack Bean', nickname='gjffdd')>
<Address(email_address='jack@google.com')>
@@ -1367,7 +1367,7 @@ using the :meth:`_query.Query.join` method:
users.nickname AS users_nickname
FROM users JOIN addresses ON users.id = addresses.user_id
WHERE addresses.email_address = ?
- ('jack@google.com',)
+ [...] ('jack@google.com',)
{stop}[<User(name='jack', fullname='Jack Bean', nickname='gjffdd')>]
:meth:`_query.Query.join` knows how to join between ``User``
@@ -1435,7 +1435,7 @@ distinct email addresses at the same time:
ON users.id = addresses_2.user_id
WHERE addresses_1.email_address = ?
AND addresses_2.email_address = ?
- ('jack@google.com', 'j25@yahoo.com')
+ [...] ('jack@google.com', 'j25@yahoo.com')
{stop}jack jack@google.com j25@yahoo.com
In addition to using the :meth:`_orm.PropComparator.of_type` method, it is
@@ -1496,7 +1496,7 @@ accessible through an attribute called ``c``:
FROM addresses GROUP BY addresses.user_id) AS anon_1
ON users.id = anon_1.user_id
ORDER BY users.id
- ('*',)
+ [...] ('*',)
{stop}<User(name='ed', fullname='Ed Jones', nickname='eddie')> None
<User(name='wendy', fullname='Wendy Williams', nickname='windy')> None
<User(name='mary', fullname='Mary Contrary', nickname='mary')> None
@@ -1534,7 +1534,7 @@ to associate an "alias" of a mapped class to a subquery:
FROM addresses
WHERE addresses.email_address != ?) AS anon_1
ON users.id = anon_1.user_id
- ('j25@yahoo.com',)
+ [...] ('j25@yahoo.com',)
{stop}<User(name='jack', fullname='Jack Bean', nickname='gjffdd')>
<Address(email_address='jack@google.com')>
@@ -1559,7 +1559,7 @@ There is an explicit EXISTS construct, which looks like this:
WHERE EXISTS (SELECT *
FROM addresses
WHERE addresses.user_id = users.id)
- ()
+ [...] ()
{stop}jack
The :class:`~sqlalchemy.orm.query.Query` features several operators which make
@@ -1576,7 +1576,7 @@ usage of EXISTS automatically. Above, the statement can be expressed along the
WHERE EXISTS (SELECT 1
FROM addresses
WHERE users.id = addresses.user_id)
- ()
+ [...] ()
{stop}jack
:meth:`~.RelationshipProperty.Comparator.any` takes criterion as well, to limit the rows matched:
@@ -1591,7 +1591,7 @@ usage of EXISTS automatically. Above, the statement can be expressed along the
WHERE EXISTS (SELECT 1
FROM addresses
WHERE users.id = addresses.user_id AND addresses.email_address LIKE ?)
- ('%google%',)
+ [...] ('%google%',)
{stop}jack
:meth:`~.RelationshipProperty.Comparator.has` is the same operator as
@@ -1609,7 +1609,7 @@ usage of EXISTS automatically. Above, the statement can be expressed along the
WHERE NOT (EXISTS (SELECT 1
FROM users
WHERE users.id = addresses.user_id AND users.name = ?))
- ('jack',)
+ [...] ('jack',)
{stop}[]
Common Relationship Operators
@@ -1685,14 +1685,14 @@ at once:
users.nickname AS users_nickname
FROM users
WHERE users.name = ?
- ('jack',)
+ [...] ('jack',)
SELECT addresses.user_id AS addresses_user_id,
addresses.id AS addresses_id,
addresses.email_address AS addresses_email_address
FROM addresses
WHERE addresses.user_id IN (?)
ORDER BY addresses.id
- (5,)
+ [...] (5,)
{stop}>>> jack
<User(name='jack', fullname='Jack Bean', nickname='gjffdd')>
@@ -1728,7 +1728,7 @@ will emit the extra join regardless:
FROM users
LEFT OUTER JOIN addresses AS addresses_1 ON users.id = addresses_1.user_id
WHERE users.name = ? ORDER BY addresses_1.id
- ('jack',)
+ [...] ('jack',)
{stop}>>> jack
<User(name='jack', fullname='Jack Bean', nickname='gjffdd')>
@@ -1792,7 +1792,7 @@ attribute:
addresses.user_id AS addresses_user_id
FROM addresses JOIN users ON users.id = addresses.user_id
WHERE users.name = ?
- ('jack',)
+ [...] ('jack',)
{stop}>>> jacks_addresses
[<Address(email_address='jack@google.com')>, <Address(email_address='j25@yahoo.com')>]
@@ -1814,9 +1814,9 @@ in the session, then we'll issue a ``count`` query to see that no rows remain:
>>> session.delete(jack)
{sql}>>> session.query(User).filter_by(name='jack').count()
UPDATE addresses SET user_id=? WHERE addresses.id = ?
- ((None, 1), (None, 2))
+ [...] ((None, 1), (None, 2))
DELETE FROM users WHERE users.id = ?
- (5,)
+ [...] (5,)
SELECT count(*) AS count_1
FROM (SELECT users.id AS users_id,
users.name AS users_name,
@@ -1824,7 +1824,7 @@ in the session, then we'll issue a ``count`` query to see that no rows remain:
users.nickname AS users_nickname
FROM users
WHERE users.name = ?) AS anon_1
- ('jack',)
+ [...] ('jack',)
{stop}0
So far, so good. How about Jack's ``Address`` objects ?
@@ -1840,7 +1840,7 @@ So far, so good. How about Jack's ``Address`` objects ?
addresses.user_id AS addresses_user_id
FROM addresses
WHERE addresses.email_address IN (?, ?)) AS anon_1
- ('jack@google.com', 'j25@yahoo.com')
+ [...] ('jack@google.com', 'j25@yahoo.com')
{stop}2
Uh oh, they're still there ! Analyzing the flush SQL, we can see that the
@@ -1914,7 +1914,7 @@ being deleted:
users.nickname AS users_nickname
FROM users
WHERE users.id = ?
- (5,)
+ [...] (5,)
{stop}
# remove one Address (lazy load fires off)
@@ -1924,7 +1924,7 @@ being deleted:
addresses.user_id AS addresses_user_id
FROM addresses
WHERE ? = addresses.user_id
- (5,)
+ [...] (5,)
{stop}
# only one address remains
@@ -1932,14 +1932,14 @@ being deleted:
... Address.email_address.in_(['jack@google.com', 'j25@yahoo.com'])
... ).count()
DELETE FROM addresses WHERE addresses.id = ?
- (2,)
+ [...] (2,)
SELECT count(*) AS count_1
FROM (SELECT addresses.id AS addresses_id,
addresses.email_address AS addresses_email_address,
addresses.user_id AS addresses_user_id
FROM addresses
WHERE addresses.email_address IN (?, ?)) AS anon_1
- ('jack@google.com', 'j25@yahoo.com')
+ [...] ('jack@google.com', 'j25@yahoo.com')
{stop}1
Deleting Jack will delete both Jack and the remaining ``Address`` associated
@@ -1951,9 +1951,9 @@ with the user:
{sql}>>> session.query(User).filter_by(name='jack').count()
DELETE FROM addresses WHERE addresses.id = ?
- (1,)
+ [...] (1,)
DELETE FROM users WHERE users.id = ?
- (5,)
+ [...] (5,)
SELECT count(*) AS count_1
FROM (SELECT users.id AS users_id,
users.name AS users_name,
@@ -1961,7 +1961,7 @@ with the user:
users.nickname AS users_nickname
FROM users
WHERE users.name = ?) AS anon_1
- ('jack',)
+ [...] ('jack',)
{stop}0
{sql}>>> session.query(Address).filter(
@@ -1973,7 +1973,7 @@ with the user:
addresses.user_id AS addresses_user_id
FROM addresses
WHERE addresses.email_address IN (?, ?)) AS anon_1
- ('jack@google.com', 'j25@yahoo.com')
+ [...] ('jack@google.com', 'j25@yahoo.com')
{stop}0
.. topic:: More on Cascades
@@ -2086,7 +2086,7 @@ Create new tables:
PRIMARY KEY (id),
UNIQUE (keyword)
)
- ()
+ [...] ()
COMMIT
CREATE TABLE posts (
id INTEGER NOT NULL,
@@ -2096,7 +2096,7 @@ Create new tables:
PRIMARY KEY (id),
FOREIGN KEY(user_id) REFERENCES users (id)
)
- ()
+ [...] ()
COMMIT
CREATE TABLE post_keywords (
post_id INTEGER NOT NULL,
@@ -2105,7 +2105,7 @@ Create new tables:
FOREIGN KEY(post_id) REFERENCES posts (id),
FOREIGN KEY(keyword_id) REFERENCES keywords (id)
)
- ()
+ [...] ()
COMMIT
Usage is not too different from what we've been doing. Let's give Wendy some blog posts:
@@ -2121,7 +2121,7 @@ Usage is not too different from what we've been doing. Let's give Wendy some bl
users.nickname AS users_nickname
FROM users
WHERE users.name = ?
- ('wendy',)
+ [...] ('wendy',)
{stop}
>>> post = BlogPost("Wendy's Blog Post", "This is a test", wendy)
>>> session.add(post)
@@ -2144,13 +2144,13 @@ keyword string 'firstpost'":
... filter(BlogPost.keywords.any(keyword='firstpost')).\
... all()
INSERT INTO keywords (keyword) VALUES (?)
- ('wendy',)
+ [...] ('wendy',)
INSERT INTO keywords (keyword) VALUES (?)
- ('firstpost',)
+ [...] ('firstpost',)
INSERT INTO posts (user_id, headline, body) VALUES (?, ?, ?)
- (2, "Wendy's Blog Post", 'This is a test')
+ [...] (2, "Wendy's Blog Post", 'This is a test')
INSERT INTO post_keywords (post_id, keyword_id) VALUES (?, ?)
- (...)
+ [...] (...)
SELECT posts.id AS posts_id,
posts.user_id AS posts_user_id,
posts.headline AS posts_headline,
@@ -2161,7 +2161,7 @@ keyword string 'firstpost'":
WHERE posts.id = post_keywords.post_id
AND keywords.id = post_keywords.keyword_id
AND keywords.keyword = ?)
- ('firstpost',)
+ [...] ('firstpost',)
{stop}[BlogPost("Wendy's Blog Post", 'This is a test', <User(name='wendy', fullname='Wendy Williams', nickname='windy')>)]
If we want to look up posts owned by the user ``wendy``, we can tell
@@ -2183,7 +2183,7 @@ the query to narrow down to that ``User`` object as a parent:
WHERE posts.id = post_keywords.post_id
AND keywords.id = post_keywords.keyword_id
AND keywords.keyword = ?))
- (2, 'firstpost')
+ [...] (2, 'firstpost')
{stop}[BlogPost("Wendy's Blog Post", 'This is a test', <User(name='wendy', fullname='Wendy Williams', nickname='windy')>)]
Or we can use Wendy's own ``posts`` relationship, which is a "dynamic"
@@ -2204,7 +2204,7 @@ relationship, to query straight from there:
WHERE posts.id = post_keywords.post_id
AND keywords.id = post_keywords.keyword_id
AND keywords.keyword = ?))
- (2, 'firstpost')
+ [...] (2, 'firstpost')
{stop}[BlogPost("Wendy's Blog Post", 'This is a test', <User(name='wendy', fullname='Wendy Williams', nickname='windy')>)]
Further Reference