<p dir="auto"><strong>Migrated issue, originally created by Michael Bayer (<a href="https://github.com/zzzeek">@zzzeek</a>)</strong></p>
<p dir="auto">this is related to <a class="issue-link js-issue-link" data-error-text="Failed to load title" data-id="384633460" data-permission-text="Title is private" data-url="https://github.com/sqlalchemy/sqlalchemy/issues/3365" data-hovercard-type="issue" data-hovercard-url="/sqlalchemy/sqlalchemy/issues/3365/hovercard" href="https://github.com/sqlalchemy/sqlalchemy/issues/3365">#3365</a> but is a more fundamental change.</p>
<p dir="auto">First, test case from <a class="issue-link js-issue-link" data-error-text="Failed to load title" data-id="384633460" data-permission-text="Title is private" data-url="https://github.com/sqlalchemy/sqlalchemy/issues/3365" data-hovercard-type="issue" data-hovercard-url="/sqlalchemy/sqlalchemy/issues/3365/hovercard" href="https://github.com/sqlalchemy/sqlalchemy/issues/3365">#3365</a>:</p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="from sqlalchemy import Column, Integer, Text, ForeignKey, create_engine
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import Session, relationship

Base = declarative_base()


class Parent(Base):
    __tablename__ = &quot;parent&quot;
    id = Column(Integer, primary_key=True)


class Child(Base):
    __tablename__ = &quot;child&quot;
    _id_parent = Column(
        &quot;id_parent&quot;, Integer, ForeignKey(Parent.id), primary_key=True)
    name = Column(Text, primary_key=True)
    parent = relationship(Parent)

engine = create_engine('sqlite://')
Base.metadata.create_all(engine)
session = Session(engine)

p = Parent(id=1)
session.add(p)
session.commit()

c = Child(name=&quot;foo&quot;, parent=p)
session.add(c)
session.commit()

session.query(Child).filter(Child.parent == p).delete(&quot;evaluate&quot;)"><pre class="notranslate"><code class="notranslate">from sqlalchemy import Column, Integer, Text, ForeignKey, create_engine
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import Session, relationship

Base = declarative_base()


class Parent(Base):
    __tablename__ = "parent"
    id = Column(Integer, primary_key=True)


class Child(Base):
    __tablename__ = "child"
    _id_parent = Column(
        "id_parent", Integer, ForeignKey(Parent.id), primary_key=True)
    name = Column(Text, primary_key=True)
    parent = relationship(Parent)

engine = create_engine('sqlite://')
Base.metadata.create_all(engine)
session = Session(engine)

p = Parent(id=1)
session.add(p)
session.commit()

c = Child(name="foo", parent=p)
session.add(c)
session.commit()

session.query(Child).filter(Child.parent == p).delete("evaluate")
</code></pre></div>
<p dir="auto">raises: "AttributeError: 'Child' object has no attribute 'id_parent'"</p>
<p dir="auto">with the fix, raises: "sqlalchemy.exc.InvalidRequestError: Could not evaluate current criteria in Python. Specify 'fetch' or False for the synchronize_session parameter."</p>
<p dir="auto">the patch involves adding ORM context to the primaryjoin/secondaryjoin:</p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="diff --git a/lib/sqlalchemy/orm/evaluator.py b/lib/sqlalchemy/orm/evaluator.py
index 1e828ff..fb59186 100644
--- a/lib/sqlalchemy/orm/evaluator.py
+++ b/lib/sqlalchemy/orm/evaluator.py
@@ -59,7 +59,9 @@ class EvaluatorCompiler(object):
                 )
             key = parentmapper._columntoproperty[clause].key
         else:
-            key = clause.key
+            raise UnevaluatableError(
+                &quot;Cannot evaluate column: %s&quot; % clause
+            )
 
         get_corresponding_attr = operator.attrgetter(key)
         return lambda obj: get_corresponding_attr(obj)
diff --git a/lib/sqlalchemy/orm/relationships.py b/lib/sqlalchemy/orm/relationships.py
index b649c9e..291af09 100644
--- a/lib/sqlalchemy/orm/relationships.py
+++ b/lib/sqlalchemy/orm/relationships.py
@@ -1942,6 +1942,7 @@ class JoinCondition(object):
         self._annotate_fks()
         self._annotate_remote()
         self._annotate_local()
+        self._annotate_parentmapper()
         self._setup_pairs()
         self._check_foreign_cols(self.primaryjoin, True)
         if self.secondaryjoin is not None:
@@ -2405,6 +2406,19 @@ class JoinCondition(object):
             self.primaryjoin, {}, locals_
         )
 
+    def _annotate_parentmapper(self):
+        if self.prop is None:
+            return
+
+        def parentmappers_(elem):
+            if &quot;remote&quot; in elem._annotations:
+                return elem._annotate({&quot;parentmapper&quot;: self.prop.mapper})
+            elif &quot;local&quot; in elem._annotations:
+                return elem._annotate({&quot;parentmapper&quot;: self.prop.parent})
+        self.primaryjoin = visitors.replacement_traverse(
+            self.primaryjoin, {}, parentmappers_
+        )
+
     def _check_remote_side(self):
         if not self.local_remote_pairs:
             raise sa_exc.ArgumentError(
@@ -2811,9 +2825,6 @@ class JoinCondition(object):
 
         bind_to_col = dict((binds[col].key, col) for col in binds)
 
-        # this is probably not necessary
-        lazywhere = _deep_deannotate(lazywhere)
-
         return lazywhere, bind_to_col, equated_columns
 
 
"><pre class="notranslate"><code class="notranslate">diff --git a/lib/sqlalchemy/orm/evaluator.py b/lib/sqlalchemy/orm/evaluator.py
index 1e828ff..fb59186 100644
--- a/lib/sqlalchemy/orm/evaluator.py
+++ b/lib/sqlalchemy/orm/evaluator.py
@@ -59,7 +59,9 @@ class EvaluatorCompiler(object):
                 )
             key = parentmapper._columntoproperty[clause].key
         else:
-            key = clause.key
+            raise UnevaluatableError(
+                "Cannot evaluate column: %s" % clause
+            )
 
         get_corresponding_attr = operator.attrgetter(key)
         return lambda obj: get_corresponding_attr(obj)
diff --git a/lib/sqlalchemy/orm/relationships.py b/lib/sqlalchemy/orm/relationships.py
index b649c9e..291af09 100644
--- a/lib/sqlalchemy/orm/relationships.py
+++ b/lib/sqlalchemy/orm/relationships.py
@@ -1942,6 +1942,7 @@ class JoinCondition(object):
         self._annotate_fks()
         self._annotate_remote()
         self._annotate_local()
+        self._annotate_parentmapper()
         self._setup_pairs()
         self._check_foreign_cols(self.primaryjoin, True)
         if self.secondaryjoin is not None:
@@ -2405,6 +2406,19 @@ class JoinCondition(object):
             self.primaryjoin, {}, locals_
         )
 
+    def _annotate_parentmapper(self):
+        if self.prop is None:
+            return
+
+        def parentmappers_(elem):
+            if "remote" in elem._annotations:
+                return elem._annotate({"parentmapper": self.prop.mapper})
+            elif "local" in elem._annotations:
+                return elem._annotate({"parentmapper": self.prop.parent})
+        self.primaryjoin = visitors.replacement_traverse(
+            self.primaryjoin, {}, parentmappers_
+        )
+
     def _check_remote_side(self):
         if not self.local_remote_pairs:
             raise sa_exc.ArgumentError(
@@ -2811,9 +2825,6 @@ class JoinCondition(object):
 
         bind_to_col = dict((binds[col].key, col) for col in binds)
 
-        # this is probably not necessary
-        lazywhere = _deep_deannotate(lazywhere)
-
         return lazywhere, bind_to_col, equated_columns
 
 

</code></pre></div>
<p dir="auto">We'd just start tracking "parentmapper" throughout all PJ/SJ conditions.</p>
<p dir="auto">I have this code.</p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="def save_all_allowed_fields():
    AllowedFieldsModel.query.delete()
    db.session.commit()

    db.session.add_all(set(
        AllowedFieldsModel(field_name=n)
        for n in request.json.get('fields')
    ))

    db.session.commit()

    return '', 204"><pre class="notranslate"><code class="notranslate">def save_all_allowed_fields():
    AllowedFieldsModel.query.delete()
    db.session.commit()

    db.session.add_all(set(
        AllowedFieldsModel(field_name=n)
        for n in request.json.get('fields')
    ))

    db.session.commit()

    return '', 204
</code></pre></div>
<p dir="auto">and get error</p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="sqlalchemy.exc.IntegrityError: (psycopg2.IntegrityError) duplicate key value violates unique constraint &quot;allowed_fields_pkey&quot;
DETAIL:  Key (field_name)=(profileType) already exists."><pre class="notranslate"><code class="notranslate">sqlalchemy.exc.IntegrityError: (psycopg2.IntegrityError) duplicate key value violates unique constraint "allowed_fields_pkey"
DETAIL:  Key (field_name)=(profileType) already exists.
</code></pre></div>
<p dir="auto">Way it is heppens if I deleted all rows?<br>
version of alchemy 1.2.15, python 3.7</p>