Relationship backref cascade path

157 views
Skip to first unread message

Lele Gaifax

unread,
Jul 24, 2021, 5:50:14 AM7/24/21
to sqlal...@googlegroups.com
Hi all,

I need some clarification on the following RemovedIn20Warning

"Pet" object is being merged into a Session along the backref cascade path
for relationship "Person.pets"; in SQLAlchemy 2.0, this reverse cascade will
not take place...

Does it really means that in SA 2.0 the pattern

new_entity = Entity(attached_to_object_id=1)

won't work at all, or instead that the "other end" one-to-many relationship
list won't be automatically updated? If the latter, is there any way to say
"ok, I don't care about the reverse cascade updates in this particular case,
as no further accesses to the one-to-many rels on the other side will happen"?

Some background on my usage: the app I'm upgrading to SA 1.4 is based on
Pyramid and has a generic way to build CRUD pages for a given entity, so
visiting, say

/Person/{person_id}/Pet/add

will present a form (automatically generated by deform) able to create a new
Pet entity linked to the given Person; its generic POST handler determines the
target entity from the request's query string and will basically do

# obtain "owner" ID from the request
owners = {key: value for key in request.matchdict if key.endswith('_id')}
pet = Pet(**owners)
session.add(pet)
# apply form's data
pet.edit(request.POST.items())
session.commit()

This triggers the mentioned SA 1.4 warning when executed with
SQLALCHEMY_WARN_20=1, as the attached snippet exhibits.

I tried several variants, such as using "back_populates" instead of the "old"
backref, but the only pattern that removed the warning has been

owner = session.get(Person, request.matchdict['person_id'])
pet = Pet()
owner.pets.append(pet)

where I surely can get, if needed, but would require implementing more
per-entity specific knowledge (possibly using introspection) into the generic
CRUD machinery, to "convert" from the "person_id" to the name of the "other
side" relationship attribute, in several dozens of places.

Another approach could be configuring all the "one-to-many" relationships as
"viewonly", but that again would require more analysis on the code paths...

So, am I missing something and there is some recommended alternative, or
should I dig into the rabbit's hole?

Thanks in advance for any hint,
ciao, lele.

test.py

Mike Bayer

unread,
Jul 24, 2021, 9:11:28 AM7/24/21
to noreply-spamdigest via sqlalchemy


On Sat, Jul 24, 2021, at 5:49 AM, Lele Gaifax wrote:
Hi all,

I need some clarification on the following RemovedIn20Warning

  "Pet" object is being merged into a Session along the backref cascade path
  for relationship "Person.pets"; in SQLAlchemy 2.0, this reverse cascade will
  not take place...

Does it really means that in SA 2.0 the pattern

  new_entity = Entity(attached_to_object_id=1)

won't work at all, or instead that the "other end" one-to-many relationship
list won't be automatically updated? If the latter, is there any way to say
"ok, I don't care about the reverse cascade updates in this particular case,
as no further accesses to the one-to-many rels on the other side will happen"?

so you want to use the "new" mode of operation which is given if you either set future=True on Session , or on specific relationships you set cascade_backrefs=False.   Then you want to make sure you add() to the Session all the objects that you want persisted.



  # obtain "owner" ID from the request
  owners = {key: value for key in request.matchdict if key.endswith('_id')}
  pet = Pet(**owners)
  session.add(pet)
  # apply form's data
  pet.edit(request.POST.items())
  session.commit()
  
This triggers the mentioned SA 1.4 warning when executed with
SQLALCHEMY_WARN_20=1, as the attached snippet exhibits.

OK so above, you get the warning on `Pet(**owners)`, but then you are doing session.add(pet), so your code is already correct and you can turn off backref cascades for that.



I tried several variants, such as using "back_populates" instead of the "old"
backref, but the only pattern that removed the warning has been

   owner = session.get(Person, request.matchdict['person_id'])
   pet = Pet()
   owner.pets.append(pet)

where I surely can get, if needed, but would require implementing more
per-entity specific knowledge (possibly using introspection) into the generic
CRUD machinery, to "convert" from the "person_id" to the name of the "other
side" relationship attribute, in several dozens of places.

Another approach could be configuring all the "one-to-many" relationships as
"viewonly", but that again would require more analysis on the code paths...

So, am I missing something and there is some recommended alternative, or
should I dig into the rabbit's hole?

The warning itself refers to the "cascade_backrefs" flag as well as an FAQ entry on this at https://docs.sqlalchemy.org/en/14/errors.html#object-is-being-merged-into-a-session-along-the-backref-cascade , as well as the fact that you can turn off "cascade_backrefs" across the board with Session(future=True) if you don't want to have to dig into individual relationships.

is there a reason you were trying other settings (for example back_populates vs. backref, these two syntaxes are equivalent and aren't related here) and not the one that's documented?  I'm just wondering if you missed seeing that.


Thanks in advance for any hint,
ciao, lele.

-- 
SQLAlchemy - 
The Python SQL Toolkit and Object Relational Mapper


To post example code, please provide an MCVE: Minimal, Complete, and Verifiable Example.  See  http://stackoverflow.com/help/mcve for a full description.
--- 
You received this message because you are subscribed to the Google Groups "sqlalchemy" group.
To unsubscribe from this group and stop receiving emails from it, send an email to sqlalchemy+...@googlegroups.com.


-- 
nickname: Lele Gaifax | Quando vivrò di quello che ho pensato ieri
real: Emanuele Gaifas | comincerò ad aver paura di chi mi copia.
le...@metapensiero.it  |                 -- Fortunato Depero, 1929.

-- 
SQLAlchemy - 
The Python SQL Toolkit and Object Relational Mapper


To post example code, please provide an MCVE: Minimal, Complete, and Verifiable Example.  See  http://stackoverflow.com/help/mcve for a full description.
--- 
You received this message because you are subscribed to the Google Groups "sqlalchemy" group.
To unsubscribe from this group and stop receiving emails from it, send an email to sqlalchemy+...@googlegroups.com.


Attachments:
  • test.py

Lele Gaifax

unread,
Jul 24, 2021, 1:30:04 PM7/24/21
to sqlal...@googlegroups.com
"Mike Bayer" <mik...@zzzcomputing.com> writes:

> On Sat, Jul 24, 2021, at 5:49 AM, Lele Gaifax wrote:
>> Hi all,
>>
>> I need some clarification on the following RemovedIn20Warning
>>
>> "Pet" object is being merged into a Session along the backref cascade path
>> for relationship "Person.pets"; in SQLAlchemy 2.0, this reverse cascade will
>> not take place...
>>
>> Does it really means that in SA 2.0 the pattern
>>
>> new_entity = Entity(attached_to_object_id=1)
>>
>> won't work at all, or instead that the "other end" one-to-many relationship
>> list won't be automatically updated? If the latter, is there any way to say
>> "ok, I don't care about the reverse cascade updates in this particular case,
>> as no further accesses to the one-to-many rels on the other side will happen"?
>
> so you want to use the "new" mode of operation which is given if you either
> set future=True on Session , or on specific relationships you set
> cascade_backrefs=False. Then you want to make sure you add() to the Session
> all the objects that you want persisted.

Oh, thank you: then I simply got the meaning of the warning wrong, ie I
assumed it was related to adding the new object to the "other side ref
collection" (that is, Person.pets), not about registering it as pending within
the session.

>
>>
>> # obtain "owner" ID from the request
>> owners = {key: value for key in request.matchdict if key.endswith('_id')}
>> pet = Pet(**owners)
>> session.add(pet)
>> # apply form's data
>> pet.edit(request.POST.items())
>> session.commit()
>>
>> This triggers the mentioned SA 1.4 warning when executed with
>> SQLALCHEMY_WARN_20=1, as the attached snippet exhibits.
>
> OK so above, you get the warning on `Pet(**owners)`, but then you are doing
> session.add(pet), so your code is already correct and you can turn off
> backref cascades for that.

Great, will try that out!

>
>
>>
>> I tried several variants, such as using "back_populates" instead of the "old"
>> backref...
>>
>> So, am I missing something and there is some recommended alternative, or
>> should I dig into the rabbit's hole?
>
> The warning itself refers to the "cascade_backrefs" flag as well as an FAQ entry on this at
> https://docs.sqlalchemy.org/en/14/errors.html#object-is-being-merged-into-a-session-along-the-backref-cascade
> , as well as the fact that you can turn off "cascade_backrefs" across the board with
> Session(future=True) if you don't want to have to dig into individual relationships.
>
> is there a reason you were trying other settings (for example back_populates
> vs. backref, these two syntaxes are equivalent and aren't related here) and
> not the one that's documented? I'm just wondering if you missed seeing that.

No particular reason, except my misunderstanding and overlooking that chapter
in errors.html (I'm quite sure I visited /one/ of the two shorturls in the
message, evidently the second, the one pointing to "some function in SA 2.0
will no longer to something", and that didn't turn the light on).

Wrt back_populates, you know, I'm a long running SA user, and still use
backref syntax: I wasn't sure they are just equivalent alternatives.

Thanks a lot for clearing this out!

ciao, lele.
Reply all
Reply to author
Forward
0 new messages