From 6ff9176bab791b49a6a3b3125ed0845bfcd2e6bc Mon Sep 17 00:00:00 2001 From: Doctor Date: Mon, 25 Apr 2022 04:35:20 +0300 Subject: [PATCH] format collections.rst --- doc/build/orm/collections.rst | 111 +++++++++++++++++++--------------- 1 file changed, 62 insertions(+), 49 deletions(-) diff --git a/doc/build/orm/collections.rst b/doc/build/orm/collections.rst index 716fea74e3..891e5ff524 100644 --- a/doc/build/orm/collections.rst +++ b/doc/build/orm/collections.rst @@ -48,14 +48,15 @@ when accessed. Filtering criterion may be applied as well as limits and offsets, either explicitly or via array slices:: class User(Base): - __tablename__ = 'user' + __tablename__ = "user" posts = relationship(Post, lazy="dynamic") + jack = session.get(User, id) # filter Jack's blog posts - posts = jack.posts.filter(Post.headline=='this is a post') + posts = jack.posts.filter(Post.headline == "this is a post") # apply array slices posts = jack.posts[5:20] @@ -63,10 +64,10 @@ offsets, either explicitly or via array slices:: The dynamic relationship supports limited write operations, via the :meth:`_orm.AppenderQuery.append` and :meth:`_orm.AppenderQuery.remove` methods:: - oldpost = jack.posts.filter(Post.headline=='old post').one() + oldpost = jack.posts.filter(Post.headline == "old post").one() jack.posts.remove(oldpost) - jack.posts.append(Post('new post')) + jack.posts.append(Post("new post")) Since the read side of the dynamic relationship always queries the database, changes to the underlying collection will not be visible @@ -81,9 +82,7 @@ function in conjunction with ``lazy='dynamic'``:: class Post(Base): __table__ = posts_table - user = relationship(User, - backref=backref('posts', lazy='dynamic') - ) + user = relationship(User, backref=backref("posts", lazy="dynamic")) Note that eager/lazy loading options cannot be used in conjunction dynamic relationships at this time. @@ -111,9 +110,9 @@ A "noload" relationship never loads from the database, even when accessed. It is configured using ``lazy='noload'``:: class MyClass(Base): - __tablename__ = 'some_table' + __tablename__ = "some_table" - children = relationship(MyOtherClass, lazy='noload') + children = relationship(MyOtherClass, lazy="noload") Above, the ``children`` collection is fully writeable, and changes to it will be persisted to the database as well as locally available for reading at the @@ -127,9 +126,9 @@ Alternatively, a "raise"-loaded relationship will raise an emit a lazy load:: class MyClass(Base): - __tablename__ = 'some_table' + __tablename__ = "some_table" - children = relationship(MyOtherClass, lazy='raise') + children = relationship(MyOtherClass, lazy="raise") Above, attribute access on the ``children`` collection will raise an exception if it was not previously eagerloaded. This includes read access but for @@ -166,11 +165,12 @@ values accessible through an attribute on the parent instance. By default, this collection is a ``list``:: class Parent(Base): - __tablename__ = 'parent' + __tablename__ = "parent" parent_id = Column(Integer, primary_key=True) children = relationship(Child) + parent = Parent() parent.children.append(Child()) print(parent.children[0]) @@ -181,12 +181,13 @@ default list, by specifying the :paramref:`_orm.relationship.collection_class` o :func:`~sqlalchemy.orm.relationship`:: class Parent(Base): - __tablename__ = 'parent' + __tablename__ = "parent" parent_id = Column(Integer, primary_key=True) # use a set children = relationship(Child, collection_class=set) + parent = Parent() child = Child() parent.children.add(child) @@ -203,24 +204,28 @@ to achieve a simple dictionary collection. It produces a dictionary class that of the mapped class as a key. Below we map an ``Item`` class containing a dictionary of ``Note`` items keyed to the ``Note.keyword`` attribute:: - from sqlalchemy import Column, Integer, String, ForeignKey + from sqlalchemy import Column, ForeignKey, Integer, String + from sqlalchemy.ext.declarative import declarative_base from sqlalchemy.orm import relationship from sqlalchemy.orm.collections import attribute_mapped_collection - from sqlalchemy.ext.declarative import declarative_base Base = declarative_base() + class Item(Base): - __tablename__ = 'item' + __tablename__ = "item" id = Column(Integer, primary_key=True) - notes = relationship("Note", - collection_class=attribute_mapped_collection('keyword'), - cascade="all, delete-orphan") + notes = relationship( + "Note", + collection_class=attribute_mapped_collection("keyword"), + cascade="all, delete-orphan", + ) + class Note(Base): - __tablename__ = 'note' + __tablename__ = "note" id = Column(Integer, primary_key=True) - item_id = Column(Integer, ForeignKey('item.id'), nullable=False) + item_id = Column(Integer, ForeignKey("item.id"), nullable=False) keyword = Column(String) text = Column(String) @@ -231,7 +236,7 @@ a dictionary of ``Note`` items keyed to the ``Note.keyword`` attribute:: ``Item.notes`` is then a dictionary:: >>> item = Item() - >>> item.notes['a'] = Note('a', 'atext') + >>> item.notes["a"] = Note("a", "atext") >>> item.notes.items() {'a': <__main__.Note object at 0x2eaaf0>} @@ -242,9 +247,9 @@ key we supply must match that of the actual ``Note`` object:: item = Item() item.notes = { - 'a': Note('a', 'atext'), - 'b': Note('b', 'btext') - } + "a": Note("a", "atext"), + "b": Note("b", "btext"), + } The attribute which :func:`.attribute_mapped_collection` uses as a key does not need to be mapped at all! Using a regular Python ``@property`` allows virtually @@ -253,17 +258,20 @@ below when we establish it as a tuple of ``Note.keyword`` and the first ten lett of the ``Note.text`` field:: class Item(Base): - __tablename__ = 'item' + __tablename__ = "item" id = Column(Integer, primary_key=True) - notes = relationship("Note", - collection_class=attribute_mapped_collection('note_key'), - backref="item", - cascade="all, delete-orphan") + notes = relationship( + "Note", + collection_class=attribute_mapped_collection("note_key"), + backref="item", + cascade="all, delete-orphan", + ) + class Note(Base): - __tablename__ = 'note' + __tablename__ = "note" id = Column(Integer, primary_key=True) - item_id = Column(Integer, ForeignKey('item.id'), nullable=False) + item_id = Column(Integer, ForeignKey("item.id"), nullable=False) keyword = Column(String) text = Column(String) @@ -290,12 +298,15 @@ object directly:: from sqlalchemy.orm.collections import column_mapped_collection + class Item(Base): - __tablename__ = 'item' + __tablename__ = "item" id = Column(Integer, primary_key=True) - notes = relationship("Note", - collection_class=column_mapped_collection(Note.__table__.c.keyword), - cascade="all, delete-orphan") + notes = relationship( + "Note", + collection_class=column_mapped_collection(Note.__table__.c.keyword), + cascade="all, delete-orphan", + ) as well as :func:`.mapped_collection` which is passed any callable function. Note that it's usually easier to use :func:`.attribute_mapped_collection` along @@ -303,12 +314,15 @@ with a ``@property`` as mentioned earlier:: from sqlalchemy.orm.collections import mapped_collection + class Item(Base): - __tablename__ = 'item' + __tablename__ = "item" id = Column(Integer, primary_key=True) - notes = relationship("Note", - collection_class=mapped_collection(lambda note: note.text[0:10]), - cascade="all, delete-orphan") + notes = relationship( + "Note", + collection_class=mapped_collection(lambda note: note.text[0:10]), + cascade="all, delete-orphan", + ) Dictionary mappings are often combined with the "Association Proxy" extension to produce streamlined dictionary views. See :ref:`proxying_dictionaries` and :ref:`composite_association_proxy` @@ -357,7 +371,7 @@ if the value of ``B.data`` is not set yet, the key will be ``None``:: Setting ``b1.data`` after the fact does not update the collection:: - >>> b1.data = 'the key' + >>> b1.data = "the key" >>> a1.bs {None: } @@ -365,14 +379,14 @@ Setting ``b1.data`` after the fact does not update the collection:: This can also be seen if one attempts to set up ``B()`` in the constructor. The order of arguments changes the result:: - >>> B(a=a1, data='the key') + >>> B(a=a1, data="the key") >>> a1.bs {None: } vs:: - >>> B(data='the key', a=a1) + >>> B(data="the key", a=a1) >>> a1.bs {'the key': } @@ -384,9 +398,9 @@ An event handler such as the following may also be used to track changes in the collection as well:: from sqlalchemy import event - from sqlalchemy.orm import attributes + @event.listens_for(B.data, "set") def set_item(obj, value, previous, initiator): if obj.a is not None: @@ -394,8 +408,6 @@ collection as well:: obj.a.bs[value] = obj obj.a.bs.pop(previous) - - .. autofunction:: attribute_mapped_collection .. autofunction:: column_mapped_collection @@ -585,8 +597,8 @@ from within an already instrumented call can cause events to be fired off repeatedly, or inappropriately, leading to internal state corruption in rare cases:: - from sqlalchemy.orm.collections import MappedCollection,\ - collection + from sqlalchemy.orm.collections import MappedCollection, collection + class MyMappedCollection(MappedCollection): """Use @internally_instrumented when your methods @@ -618,7 +630,8 @@ Iteration will go through ``itervalues()`` unless otherwise decorated. of :class:`.MappedCollection` which uses :meth:`.collection.internally_instrumented` can be used:: - from sqlalchemy.orm.collections import _instrument_class, MappedCollection + from sqlalchemy.orm.collections import MappedCollection, _instrument_class + _instrument_class(MappedCollection) This will ensure that the :class:`.MappedCollection` has been properly -- 2.47.3