← Back to team overview

launchpad-reviewers team mailing list archive

[Merge] ~cjwatson/launchpad:stormify-teammembership into launchpad:master

 

Colin Watson has proposed merging ~cjwatson/launchpad:stormify-teammembership into launchpad:master.

Commit message:
Convert TeamMembership and TeamParticipation to Storm

Requested reviews:
  Launchpad code reviewers (launchpad-reviewers)

For more details, see:
https://code.launchpad.net/~cjwatson/launchpad/+git/launchpad/+merge/447654

The deeper we get towards Launchpad's core, the more weird old spellings of queries we find!  But there's nothing really ground-breaking in here, just lots of little details.
-- 
Your team Launchpad code reviewers is requested to review the proposed merge of ~cjwatson/launchpad:stormify-teammembership into launchpad:master.
diff --git a/lib/lp/answers/model/questionsperson.py b/lib/lp/answers/model/questionsperson.py
index 59e2e5e..964c050 100644
--- a/lib/lp/answers/model/questionsperson.py
+++ b/lib/lp/answers/model/questionsperson.py
@@ -84,7 +84,7 @@ class QuestionsPersonMixin:
             IStore(AnswerContact)
             .find(
                 AnswerContact,
-                AnswerContact.person == TeamParticipation.teamID,
+                AnswerContact.person == TeamParticipation.team_id,
                 TeamParticipation.person == self,
                 AnswerContact.person != self,
             )
diff --git a/lib/lp/blueprints/model/specificationsearch.py b/lib/lp/blueprints/model/specificationsearch.py
index 1293fa7..ef3801b 100644
--- a/lib/lp/blueprints/model/specificationsearch.py
+++ b/lib/lp/blueprints/model/specificationsearch.py
@@ -260,7 +260,7 @@ def get_specification_privacy_filter(user):
         ArrayIntersects(
             SQL("Specification.access_grants"),
             Select(
-                ArrayAgg(TeamParticipation.teamID),
+                ArrayAgg(TeamParticipation.team_id),
                 tables=TeamParticipation,
                 where=(TeamParticipation.person == user),
             ),
@@ -277,7 +277,7 @@ def get_specification_privacy_filter(user):
                     AccessPolicyGrant,
                     Join(
                         TeamParticipation,
-                        TeamParticipation.teamID
+                        TeamParticipation.team_id
                         == AccessPolicyGrant.grantee_id,
                     ),
                 ),
diff --git a/lib/lp/bugs/doc/bugsummary.rst b/lib/lp/bugs/doc/bugsummary.rst
index 83daaf4..7cd6770 100644
--- a/lib/lp/bugs/doc/bugsummary.rst
+++ b/lib/lp/bugs/doc/bugsummary.rst
@@ -590,7 +590,7 @@ But how many can the owner see?
     >>> join = LeftJoin(
     ...     BugSummary,
     ...     TeamParticipation,
-    ...     BugSummary.viewed_by_id == TeamParticipation.teamID,
+    ...     BugSummary.viewed_by_id == TeamParticipation.team_id,
     ... )
     >>> store.using(join).find(
     ...     BugSummary,
diff --git a/lib/lp/bugs/model/bug.py b/lib/lp/bugs/model/bug.py
index 2db7afe..5da7f9b 100644
--- a/lib/lp/bugs/model/bug.py
+++ b/lib/lp/bugs/model/bug.py
@@ -3526,11 +3526,11 @@ def generate_subscription_with(bug, person):
                     SQL("all_bugsubscriptions"),
                     Join(
                         TeamParticipation,
-                        TeamParticipation.teamID
+                        TeamParticipation.team_id
                         == SQL("all_bugsubscriptions.person"),
                     ),
                 ],
-                where=[TeamParticipation.personID == person.id],
+                where=[TeamParticipation.person == person],
             ),
         ),
     ]
diff --git a/lib/lp/bugs/model/bugsummary.py b/lib/lp/bugs/model/bugsummary.py
index 4b7d24b..fdbbf46 100644
--- a/lib/lp/bugs/model/bugsummary.py
+++ b/lib/lp/bugs/model/bugsummary.py
@@ -126,9 +126,9 @@ def get_bugsummary_filter_for_user(user):
                 "teams",
                 store,
                 Select(
-                    TeamParticipation.teamID,
+                    TeamParticipation.team_id,
                     tables=[TeamParticipation],
-                    where=(TeamParticipation.personID == user.id),
+                    where=(TeamParticipation.person == user),
                 ),
             ),
             WithMaterialized(
diff --git a/lib/lp/bugs/model/bugtasksearch.py b/lib/lp/bugs/model/bugtasksearch.py
index 7f7dd20..9a49e53 100644
--- a/lib/lp/bugs/model/bugtasksearch.py
+++ b/lib/lp/bugs/model/bugtasksearch.py
@@ -1612,7 +1612,7 @@ def get_bug_privacy_filter_terms(user, check_admin=True):
         ArrayIntersects(
             SQL("BugTaskFlat.access_grants"),
             Select(
-                ArrayAgg(TeamParticipation.teamID),
+                ArrayAgg(TeamParticipation.team_id),
                 tables=TeamParticipation,
                 where=(TeamParticipation.person == user),
             ),
@@ -1629,7 +1629,7 @@ def get_bug_privacy_filter_terms(user, check_admin=True):
                     AccessPolicyGrant,
                     Join(
                         TeamParticipation,
-                        TeamParticipation.teamID
+                        TeamParticipation.team_id
                         == AccessPolicyGrant.grantee_id,
                     ),
                 ),
@@ -1698,9 +1698,9 @@ def get_bug_bulk_privacy_filter_terms(person, bug):
     )
     # And we need to expand team memberships.
     participants = Select(
-        TeamParticipation.personID,
+        TeamParticipation.person_id,
         tables=[TeamParticipation],
-        where=In(TeamParticipation.teamID, teams),
+        where=TeamParticipation.team_id.is_in(teams),
     )
     # The bug must public, or the user must satisfy the above criteria.
     return Or(
diff --git a/lib/lp/bugs/model/structuralsubscription.py b/lib/lp/bugs/model/structuralsubscription.py
index 75b40e6..1694f09 100644
--- a/lib/lp/bugs/model/structuralsubscription.py
+++ b/lib/lp/bugs/model/structuralsubscription.py
@@ -573,8 +573,8 @@ def get_structural_subscriptions_for_target(target, person):
         StructuralSubscription,
         IStructuralSubscriptionTargetHelper(target).join,
         StructuralSubscription.subscriber == Person.id,
-        TeamParticipation.personID == person.id,
-        TeamParticipation.teamID == Person.id,
+        TeamParticipation.person == person,
+        TeamParticipation.team_id == Person.id,
     )
 
 
@@ -615,8 +615,8 @@ def get_structural_subscriptions_for_bug(bug, person=None):
         conditions.extend(
             [
                 StructuralSubscription.subscriber == Person.id,
-                TeamParticipation.personID == person.id,
-                TeamParticipation.teamID == Person.id,
+                TeamParticipation.person == person,
+                TeamParticipation.team_id == Person.id,
             ]
         )
     return _get_structural_subscriptions(
diff --git a/lib/lp/bugs/model/vulnerability.py b/lib/lp/bugs/model/vulnerability.py
index c4c4a91..772cb9f 100644
--- a/lib/lp/bugs/model/vulnerability.py
+++ b/lib/lp/bugs/model/vulnerability.py
@@ -456,7 +456,7 @@ def get_vulnerability_privacy_filter(user):
         ArrayIntersects(
             SQL("Vulnerability.access_grants"),
             Select(
-                ArrayAgg(TeamParticipation.teamID),
+                ArrayAgg(TeamParticipation.team_id),
                 tables=TeamParticipation,
                 where=(TeamParticipation.person == user),
             ),
@@ -473,7 +473,7 @@ def get_vulnerability_privacy_filter(user):
                     AccessPolicyGrant,
                     Join(
                         TeamParticipation,
-                        TeamParticipation.teamID
+                        TeamParticipation.team_id
                         == AccessPolicyGrant.grantee_id,
                     ),
                 ),
diff --git a/lib/lp/code/model/branch.py b/lib/lp/code/model/branch.py
index 48fd5fc..4b15176 100644
--- a/lib/lp/code/model/branch.py
+++ b/lib/lp/code/model/branch.py
@@ -2052,7 +2052,7 @@ def get_branch_privacy_filter(user, branch_class=Branch):
         ArrayIntersects(
             SQL("%s.access_grants" % branch_class.__storm_table__),
             Select(
-                ArrayAgg(TeamParticipation.teamID),
+                ArrayAgg(TeamParticipation.team_id),
                 tables=TeamParticipation,
                 where=(TeamParticipation.person == user),
             ),
@@ -2069,7 +2069,7 @@ def get_branch_privacy_filter(user, branch_class=Branch):
                     AccessPolicyGrant,
                     Join(
                         TeamParticipation,
-                        TeamParticipation.teamID
+                        TeamParticipation.team_id
                         == AccessPolicyGrant.grantee_id,
                     ),
                 ),
diff --git a/lib/lp/code/model/branchcollection.py b/lib/lp/code/model/branchcollection.py
index fd5677d..8f20bd1 100644
--- a/lib/lp/code/model/branchcollection.py
+++ b/lib/lp/code/model/branchcollection.py
@@ -670,7 +670,7 @@ class GenericBranchCollection:
         branch_query = self._getBranchSelect((Branch.owner_id,))
         return self.store.find(
             Person,
-            Person.id == TeamParticipation.teamID,
+            Person.id == TeamParticipation.team_id,
             TeamParticipation.person == person,
             TeamParticipation.team != person,
             Person.id.is_in(branch_query),
@@ -775,8 +775,8 @@ class GenericBranchCollection:
     def ownedByTeamMember(self, person):
         """See `IBranchCollection`."""
         subquery = Select(
-            TeamParticipation.teamID,
-            where=TeamParticipation.personID == person.id,
+            TeamParticipation.team_id,
+            where=TeamParticipation.person == person,
         )
         return self._filterBy([In(Branch.owner_id, subquery)], symmetric=False)
 
diff --git a/lib/lp/code/model/gitcollection.py b/lib/lp/code/model/gitcollection.py
index 2481410..d26b2d1 100644
--- a/lib/lp/code/model/gitcollection.py
+++ b/lib/lp/code/model/gitcollection.py
@@ -553,7 +553,7 @@ class GenericGitCollection:
         repository_query = self._getRepositorySelect((GitRepository.owner_id,))
         return self.store.find(
             Person,
-            Person.id == TeamParticipation.teamID,
+            Person.id == TeamParticipation.team_id,
             TeamParticipation.person == person,
             TeamParticipation.team != person,
             Person.id.is_in(repository_query),
@@ -627,8 +627,8 @@ class GenericGitCollection:
     def ownedByTeamMember(self, person):
         """See `IGitCollection`."""
         subquery = Select(
-            TeamParticipation.teamID,
-            where=TeamParticipation.personID == person.id,
+            TeamParticipation.team_id,
+            where=TeamParticipation.person == person,
         )
         return self._filterBy(
             [In(GitRepository.owner_id, subquery)], symmetric=False
diff --git a/lib/lp/code/model/gitrepository.py b/lib/lp/code/model/gitrepository.py
index 8b3c3ea..87abb5b 100644
--- a/lib/lp/code/model/gitrepository.py
+++ b/lib/lp/code/model/gitrepository.py
@@ -1689,7 +1689,7 @@ class GitRepository(
             clauses = [
                 GitRuleGrant.grantee_type == GitGranteeType.PERSON,
                 TeamParticipation.person == grantee,
-                GitRuleGrant.grantee == TeamParticipation.teamID,
+                GitRuleGrant.grantee == TeamParticipation.team_id,
             ]
         if ref_pattern is not None:
             clauses.extend(
@@ -2579,7 +2579,7 @@ def get_git_repository_privacy_filter(user, repository_class=GitRepository):
         ArrayIntersects(
             SQL("%s.access_grants" % repository_class.__storm_table__),
             Select(
-                ArrayAgg(TeamParticipation.teamID),
+                ArrayAgg(TeamParticipation.team_id),
                 tables=TeamParticipation,
                 where=(TeamParticipation.person == user),
             ),
@@ -2596,7 +2596,7 @@ def get_git_repository_privacy_filter(user, repository_class=GitRepository):
                     AccessPolicyGrant,
                     Join(
                         TeamParticipation,
-                        TeamParticipation.teamID
+                        TeamParticipation.team_id
                         == AccessPolicyGrant.grantee_id,
                     ),
                 ),
diff --git a/lib/lp/code/model/revision.py b/lib/lp/code/model/revision.py
index c3416db..3777ebd 100644
--- a/lib/lp/code/model/revision.py
+++ b/lib/lp/code/model/revision.py
@@ -564,7 +564,7 @@ class RevisionSet:
             origin.append(
                 Join(
                     TeamParticipation,
-                    RevisionAuthor.person_id == TeamParticipation.personID,
+                    RevisionAuthor.person_id == TeamParticipation.person_id,
                 )
             )
             person_condition = TeamParticipation.team == person
diff --git a/lib/lp/code/model/revisioncache.py b/lib/lp/code/model/revisioncache.py
index 9ad12ed..5a28cf2 100644
--- a/lib/lp/code/model/revisioncache.py
+++ b/lib/lp/code/model/revisioncache.py
@@ -134,7 +134,7 @@ class GenericRevisionCollection:
         if person.is_team:
             query = [
                 TeamParticipation.team == person,
-                RevisionAuthor.person_id == TeamParticipation.personID,
+                RevisionAuthor.person_id == TeamParticipation.person_id,
             ]
         else:
             query = [RevisionAuthor.person == person]
diff --git a/lib/lp/oci/model/ocirecipe.py b/lib/lp/oci/model/ocirecipe.py
index 068e286..82c2a6f 100644
--- a/lib/lp/oci/model/ocirecipe.py
+++ b/lib/lp/oci/model/ocirecipe.py
@@ -1198,7 +1198,7 @@ def get_ocirecipe_privacy_filter(user):
         ArrayIntersects(
             SQL("%s.access_grants" % OCIRecipe.__storm_table__),
             Select(
-                ArrayAgg(TeamParticipation.teamID),
+                ArrayAgg(TeamParticipation.team_id),
                 tables=TeamParticipation,
                 where=(TeamParticipation.person == user),
             ),
@@ -1215,7 +1215,7 @@ def get_ocirecipe_privacy_filter(user):
                     AccessPolicyGrant,
                     Join(
                         TeamParticipation,
-                        TeamParticipation.teamID
+                        TeamParticipation.team_id
                         == AccessPolicyGrant.grantee_id,
                     ),
                 ),
@@ -1225,13 +1225,13 @@ def get_ocirecipe_privacy_filter(user):
         False,
     )
 
-    admin_team_id = getUtility(ILaunchpadCelebrities).admin.id
+    admin_team = getUtility(ILaunchpadCelebrities).admin
     user_is_admin = Exists(
         Select(
-            TeamParticipation.personID,
+            TeamParticipation.person_id,
             tables=[TeamParticipation],
             where=And(
-                TeamParticipation.teamID == admin_team_id,
+                TeamParticipation.team == admin_team,
                 TeamParticipation.person == user,
             ),
         )
diff --git a/lib/lp/registry/browser/person.py b/lib/lp/registry/browser/person.py
index 3a61179..2ce4be6 100644
--- a/lib/lp/registry/browser/person.py
+++ b/lib/lp/registry/browser/person.py
@@ -63,6 +63,7 @@ from lazr.restful.interface import copy_field
 from lazr.restful.interfaces import IWebServiceClientRequest
 from lazr.restful.utils import smartquote
 from lazr.uri import URI
+from storm.expr import Desc
 from storm.zope.interfaces import IResultSet
 from zope.browserpage import ViewPageTemplateFile
 from zope.component import adapter, getUtility, queryMultiAdapter
@@ -1700,7 +1701,7 @@ class PersonView(LaunchpadView, FeedsMixin, ContactViaWebLinksMixin):
     def recently_approved_members(self):
         members = self.context.getMembersByStatus(
             TeamMembershipStatus.APPROVED,
-            orderBy="-TeamMembership.date_joined",
+            order_by=Desc("TeamMembership.date_joined"),
         )
         return members[:5]
 
@@ -1708,7 +1709,7 @@ class PersonView(LaunchpadView, FeedsMixin, ContactViaWebLinksMixin):
     def recently_proposed_members(self):
         members = self.context.getMembersByStatus(
             TeamMembershipStatus.PROPOSED,
-            orderBy="-TeamMembership.date_proposed",
+            order_by=Desc("TeamMembership.date_proposed"),
         )
         return members[:5]
 
@@ -1716,7 +1717,7 @@ class PersonView(LaunchpadView, FeedsMixin, ContactViaWebLinksMixin):
     def recently_invited_members(self):
         members = self.context.getMembersByStatus(
             TeamMembershipStatus.INVITED,
-            orderBy="-TeamMembership.date_proposed",
+            order_by=Desc("TeamMembership.date_proposed"),
         )
         return members[:5]
 
@@ -2098,7 +2099,7 @@ class PersonParticipationView(LaunchpadView):
             # The member is a direct member; use the membership data.
             datejoined = membership.datejoined
             dateexpires = membership.dateexpires
-            if membership.personID == team.teamownerID:
+            if membership.person_id == team.teamownerID:
                 role = "Owner"
             elif membership.status == TeamMembershipStatus.ADMIN:
                 role = "Admin"
diff --git a/lib/lp/registry/browser/team.py b/lib/lp/registry/browser/team.py
index 176a90e..5674164 100644
--- a/lib/lp/registry/browser/team.py
+++ b/lib/lp/registry/browser/team.py
@@ -1286,7 +1286,7 @@ class TeamMemberAddView(LaunchpadFormView):
         newmember = data.get("newmember")
         error = None
         if newmember is not None:
-            if newmember.is_team and not newmember.activemembers:
+            if newmember.is_team and newmember.activemembers.is_empty():
                 error = _(
                     "You can't add a team that doesn't have any active"
                     " members."
diff --git a/lib/lp/registry/configure.zcml b/lib/lp/registry/configure.zcml
index b2dc87f..5dda9d1 100644
--- a/lib/lp/registry/configure.zcml
+++ b/lib/lp/registry/configure.zcml
@@ -39,7 +39,7 @@
                 id
                 team
                 person
-                personID
+                person_id
                 status
                 proposed_by
                 acknowledged_by
diff --git a/lib/lp/registry/doc/teammembership.rst b/lib/lp/registry/doc/teammembership.rst
index a0fcd9a..173cd53 100644
--- a/lib/lp/registry/doc/teammembership.rst
+++ b/lib/lp/registry/doc/teammembership.rst
@@ -888,10 +888,11 @@ We can also change the sort order of the results of getMembersByStatus.
     Celso Providelo (cprov)
     Guilherme Salgado (salgado)
 
-    >>> orderBy = "-TeamMembership.date_joined"
-    >>> for person in t3.getMembersByStatus(deactivated, orderBy=orderBy):
+    >>> from storm.locals import Desc
+    >>> for person in t3.getMembersByStatus(deactivated).order_by(
+    ...     Desc("TeamMembership.date_joined")
+    ... ):
     ...     print(person.unique_displayname)
-    ...
     Celso Providelo (cprov)
     Guilherme Salgado (salgado)
 
diff --git a/lib/lp/registry/interfaces/person.py b/lib/lp/registry/interfaces/person.py
index 7cdc22a..3d6db5d 100644
--- a/lib/lp/registry/interfaces/person.py
+++ b/lib/lp/registry/interfaces/person.py
@@ -1878,7 +1878,7 @@ class IPersonViewRestricted(
     @operation_returns_collection_of(Interface)  # Really IPerson
     @export_read_operation()
     @operation_for_version("beta")
-    def getMembersByStatus(status, orderby=None):
+    def getMembersByStatus(status, order_by=None):
         """Return the people whose membership on this team match :status:.
 
         If no orderby is provided, Person.sortingColumns is used.
diff --git a/lib/lp/registry/interfaces/teammembership.py b/lib/lp/registry/interfaces/teammembership.py
index 4f421e8..544af9d 100644
--- a/lib/lp/registry/interfaces/teammembership.py
+++ b/lib/lp/registry/interfaces/teammembership.py
@@ -148,7 +148,7 @@ class ITeamMembership(Interface):
         ),  # Specified in interfaces/person.py.
         exported_as="member",
     )
-    personID = Int(title=_("Person ID"), required=True, readonly=True)
+    person_id = Int(title=_("Person ID"), required=True, readonly=True)
     proposed_by = Attribute(_("Proponent"))
     reviewed_by = Attribute(
         _("The team admin who approved/rejected the member.")
diff --git a/lib/lp/registry/model/distribution.py b/lib/lp/registry/model/distribution.py
index 4189140..1692c07 100644
--- a/lib/lp/registry/model/distribution.py
+++ b/lib/lp/registry/model/distribution.py
@@ -2390,7 +2390,7 @@ class DistributionSet:
                         AccessPolicyGrantFlat,
                         Join(
                             TeamParticipation,
-                            TeamParticipation.teamID
+                            TeamParticipation.team_id
                             == AccessPolicyGrantFlat.grantee_id,
                         ),
                     ),
diff --git a/lib/lp/registry/model/distroseriesdifference.py b/lib/lp/registry/model/distroseriesdifference.py
index 23602af..d151833 100644
--- a/lib/lp/registry/model/distroseriesdifference.py
+++ b/lib/lp/registry/model/distroseriesdifference.py
@@ -505,9 +505,9 @@ class DistroSeriesDifference(StormBase):
                 SPPH.distroseries == distro_series,
                 SPPH.sourcepackagerelease_id == SPR.id,
                 SPPH.status.is_in(active_publishing_status),
-                SPR.creatorID == TP.personID,
+                SPR.creatorID == TP.person_id,
                 SPR.sourcepackagenameID == DSD.source_package_name_id,
-                TP.teamID.is_in(person.id for person in changed_by),
+                TP.team_id.is_in(person.id for person in changed_by),
             )
             differences_changed_by = store.find(
                 columns, differences_changed_by_conditions
diff --git a/lib/lp/registry/model/mailinglist.py b/lib/lp/registry/model/mailinglist.py
index c47b266..c27fbae 100644
--- a/lib/lp/registry/model/mailinglist.py
+++ b/lib/lp/registry/model/mailinglist.py
@@ -647,7 +647,7 @@ class MailingListSet:
             EmailAddress,
             Join(Person, Person.id == EmailAddress.personID),
             Join(Account, Account.id == Person.account_id),
-            Join(TeamParticipation, TeamParticipation.personID == Person.id),
+            Join(TeamParticipation, TeamParticipation.person_id == Person.id),
             Join(
                 MailingListSubscription,
                 MailingListSubscription.person_id == Person.id,
@@ -663,8 +663,8 @@ class MailingListSet:
             (EmailAddress.email, Person.display_name, Team.name),
             And(
                 MailingListSubscription.mailing_list_id.is_in(list_ids),
-                TeamParticipation.teamID.is_in(team_ids),
-                MailingList.team_id == TeamParticipation.teamID,
+                TeamParticipation.team_id.is_in(team_ids),
+                MailingList.team_id == TeamParticipation.team_id,
                 MailingList.status != MailingListStatus.INACTIVE,
                 Account.status == AccountStatus.ACTIVE,
                 Or(
@@ -703,15 +703,17 @@ class MailingListSet:
             Person,
             Join(Account, Account.id == Person.account_id),
             Join(EmailAddress, EmailAddress.personID == Person.id),
-            Join(TeamParticipation, TeamParticipation.personID == Person.id),
-            Join(MailingList, MailingList.team_id == TeamParticipation.teamID),
+            Join(TeamParticipation, TeamParticipation.person_id == Person.id),
+            Join(
+                MailingList, MailingList.team_id == TeamParticipation.team_id
+            ),
             Join(Team, Team.id == MailingList.team_id),
         )
         team_ids, list_ids = self._getTeamIdsAndMailingListIds(team_names)
         team_members = store.using(*tables).find(
             (Team.name, Person.display_name, EmailAddress.email),
             And(
-                TeamParticipation.teamID.is_in(team_ids),
+                TeamParticipation.team_id.is_in(team_ids),
                 MailingList.status != MailingListStatus.INACTIVE,
                 Person.teamowner == None,
                 EmailAddress.status.is_in(EMAIL_ADDRESS_STATUSES),
diff --git a/lib/lp/registry/model/person.py b/lib/lp/registry/model/person.py
index d53f091..3a7d1a5 100644
--- a/lib/lp/registry/model/person.py
+++ b/lib/lp/registry/model/person.py
@@ -33,7 +33,7 @@ import random
 import re
 import weakref
 from datetime import datetime, timedelta, timezone
-from operator import attrgetter
+from operator import attrgetter, itemgetter
 
 import six
 import transaction
@@ -48,8 +48,8 @@ from storm.expr import (
     Column,
     Desc,
     Exists,
-    In,
     Is,
+    IsNot,
     Join,
     LeftJoin,
     Min,
@@ -329,7 +329,7 @@ def get_person_visibility_terms(user):
         And(
             Person.id.is_in(
                 Select(
-                    TeamParticipation.teamID,
+                    TeamParticipation.team_id,
                     tables=[TeamParticipation],
                     where=(TeamParticipation.person == user),
                 )
@@ -981,19 +981,20 @@ class Person(
         person participates in, the one with the oldest creation date is
         returned.
         """
-        query = And(
-            TeamMembership.teamID == team.id,
-            TeamMembership.personID == Person.q.id,
-            Or(
-                TeamMembership.status == TeamMembershipStatus.ADMIN,
-                TeamMembership.status == TeamMembershipStatus.APPROVED,
+        clauses = (
+            TeamMembership.team_id == team.id,
+            TeamMembership.person_id == Person.id,
+            TeamMembership.status.is_in(
+                (TeamMembershipStatus.ADMIN, TeamMembershipStatus.APPROVED)
             ),
-            TeamParticipation.teamID == Person.id,
-            TeamParticipation.personID == self.id,
+            TeamParticipation.team_id == Person.id,
+            TeamParticipation.person_id == self.id,
         )
-        clauseTables = ["TeamMembership", "TeamParticipation"]
-        member = Person.selectFirst(
-            query, clauseTables=clauseTables, orderBy="datecreated"
+        member = (
+            IStore(Person)
+            .find(Person, *clauses)
+            .order_by(Person.datecreated)
+            .first()
         )
         assert member is not None, (
             "%(person)s is an indirect member of %(team)s but %(person)s "
@@ -1180,8 +1181,8 @@ class Person(
             ownership_participation = ClassAlias(TeamParticipation)
             clauses.extend(
                 [
-                    Product._ownerID == ownership_participation.teamID,
-                    ownership_participation.personID == self.id,
+                    Product._ownerID == ownership_participation.team_id,
+                    ownership_participation.person_id == self.id,
                 ]
             )
         else:
@@ -1215,12 +1216,9 @@ class Person(
         with_sql = [
             With(
                 "teams",
-                SQL(
-                    """
-                 SELECT team FROM TeamParticipation
-                 WHERE TeamParticipation.person = %d
-                """
-                    % self.id
+                Select(
+                    TeamParticipation.team_id,
+                    where=(TeamParticipation.person == self),
                 ),
             ),
             WithMaterialized(
@@ -1268,14 +1266,14 @@ class Person(
             .using(
                 Person,
                 Join(
-                    TeamParticipation, Person.id == TeamParticipation.personID
+                    TeamParticipation, Person.id == TeamParticipation.person_id
                 ),
                 LeftJoin(
-                    Product, TeamParticipation.teamID == Product._ownerID
+                    Product, TeamParticipation.team_id == Product._ownerID
                 ),
                 LeftJoin(
                     Distribution,
-                    TeamParticipation.teamID == Distribution.ownerID,
+                    TeamParticipation.team_id == Distribution.ownerID,
                 ),
                 Join(
                     CommercialSubscription,
@@ -1480,7 +1478,11 @@ class Person(
             except KeyError:
                 pass
 
-        tp = TeamParticipation.selectOneBy(team=team, person=self)
+        tp = (
+            IStore(TeamParticipation)
+            .find(TeamParticipation, team=team, person=self)
+            .one()
+        )
         in_team = tp is not None
         self._inTeam_cache[team.id] = in_team
         return in_team
@@ -1515,11 +1517,9 @@ class Person(
 
         found_team_ids = set(
             IStore(TeamParticipation).find(
-                TeamParticipation.teamID,
-                And(
-                    TeamParticipation.teamID.is_in(unknown_team_ids),
-                    TeamParticipation.personID == self.id,
-                ),
+                TeamParticipation.team_id,
+                TeamParticipation.team_id.is_in(unknown_team_ids),
+                TeamParticipation.person_id == self.id,
             )
         )
 
@@ -1530,7 +1530,11 @@ class Person(
 
     def hasParticipationEntryFor(self, team):
         """See `IPerson`."""
-        return bool(TeamParticipation.selectOneBy(person=self, team=team))
+        return (
+            not IStore(TeamParticipation)
+            .find(TeamParticipation, person=self, team=team)
+            .is_empty()
+        )
 
     def leave(self, team):
         """See `IPerson`."""
@@ -1592,7 +1596,8 @@ class Person(
         """See `IPerson`."""
         return list(
             Store.of(self).find(
-                TeamParticipation.personID, TeamParticipation.teamID == self.id
+                TeamParticipation.person_id,
+                TeamParticipation.team_id == self.id,
             )
         )
 
@@ -1787,12 +1792,12 @@ class Person(
                 Join(
                     Person,
                     TeamParticipation,
-                    Person.id == TeamParticipation.teamID,
+                    Person.id == TeamParticipation.team_id,
                 )
             ],
             And(
-                TeamParticipation.personID == self.id,
-                TeamParticipation.teamID != self.id,
+                TeamParticipation.person_id == self.id,
+                TeamParticipation.team_id != self.id,
             ),
             need_api=True,
         )
@@ -1805,12 +1810,12 @@ class Person(
                 Join(
                     Person,
                     TeamParticipation,
-                    Person.id == TeamParticipation.personID,
+                    Person.id == TeamParticipation.person_id,
                 )
             ],
             And(
-                TeamParticipation.teamID == self.id,
-                TeamParticipation.personID != self.id,
+                TeamParticipation.team_id == self.id,
+                TeamParticipation.person_id != self.id,
                 Person.teamownerID != None,
             ),
             need_api=True,
@@ -1849,7 +1854,11 @@ class Person(
             )
 
         event = JoinTeamEvent
-        tm = TeamMembership.selectOneBy(person=person, team=self)
+        tm = (
+            IStore(TeamMembership)
+            .find(TeamMembership, person=person, team=self)
+            .one()
+        )
         if tm is not None:
             if tm.status == TeamMembershipStatus.ADMIN or (
                 tm.status == TeamMembershipStatus.APPROVED
@@ -1895,9 +1904,7 @@ class Person(
                 dateexpires=expires,
                 comment=comment,
             )
-            # Accessing the id attribute ensures that the team
-            # creation has been flushed to the database.
-            tm.id
+            Store.of(tm).flush()
             notify(event(person, self))
         else:
             # We can't use tm.setExpirationDate() here because the reviewer
@@ -1912,7 +1919,11 @@ class Person(
         return (status_changed, tm.status)
 
     def _accept_or_decline_membership(self, team, status, comment):
-        tm = TeamMembership.selectOneBy(person=self, team=team)
+        tm = (
+            IStore(TeamMembership)
+            .find(TeamMembership, person=self, team=team)
+            .one()
+        )
         assert tm is not None
         assert tm.status == TeamMembershipStatus.INVITED
         tm.setStatus(status, getUtility(ILaunchBag).user, comment=comment)
@@ -1956,8 +1967,8 @@ class Person(
             ),
         }
         constraints = And(
-            TeamMembership.personID == self.id,
-            TeamMembership.teamID == team.id,
+            TeamMembership.person_id == self.id,
+            TeamMembership.team_id == team.id,
             TeamMembership.status.is_in(active_and_transitioning.keys()),
         )
         tm = Store.of(self).find(TeamMembership, constraints).one()
@@ -1974,7 +1985,11 @@ class Person(
         must be active (APPROVED or ADMIN) and set to expire in less than
         DAYS_BEFORE_EXPIRATION_WARNING_IS_SENT days.
         """
-        tm = TeamMembership.selectOneBy(person=self, team=team)
+        tm = (
+            IStore(TeamMembership)
+            .find(TeamMembership, person=self, team=team)
+            .one()
+        )
         assert (
             tm.canBeRenewedByMember()
         ), "This membership can't be renewed by the member themselves."
@@ -1995,7 +2010,11 @@ class Person(
         self, person, status, reviewer, expires=None, comment=None
     ):
         """See `IPerson`."""
-        tm = TeamMembership.selectOneBy(person=person, team=self)
+        tm = (
+            IStore(TeamMembership)
+            .find(TeamMembership, person=person, team=self)
+            .one()
+        )
         assert tm is not None
         tm.setExpirationDate(expires, reviewer)
         tm.setStatus(status, reviewer, comment=comment)
@@ -2022,20 +2041,20 @@ class Person(
 
         class RestrictedParticipation:
             __storm_table__ = "RestrictedParticipation"
-            teamID = Int(primary=True, name="team")
+            team_id = Int(primary=True, name="team")
 
         store = Store.of(self)
         restricted_participation_cte = WithMaterialized(
             "RestrictedParticipation",
             store,
             Select(
-                TeamParticipation.teamID,
+                TeamParticipation.team_id,
                 tables=[TeamParticipation],
                 where=TeamParticipation.person == self,
             ),
         )
         team_select = Select(
-            RestrictedParticipation.teamID, tables=[RestrictedParticipation]
+            RestrictedParticipation.team_id, tables=[RestrictedParticipation]
         )
 
         return (
@@ -2050,12 +2069,12 @@ class Person(
                             where=Person.teamownerID.is_in(team_select),
                         ),
                         Select(
-                            TeamMembership.teamID,
+                            TeamMembership.team_id,
                             tables=[TeamMembership],
                             where=And(
                                 TeamMembership.status
                                 == TeamMembershipStatus.ADMIN,
-                                TeamMembership.personID.is_in(team_select),
+                                TeamMembership.person_id.is_in(team_select),
                             ),
                         ),
                     )
@@ -2069,22 +2088,24 @@ class Person(
         """See `IPerson`."""
         if not self.is_team:
             raise ValueError("This method must only be used for teams.")
-        owner = Person.select("id = %s" % sqlvalues(self.teamowner))
-        return self.adminmembers.union(
-            owner, orderBy=self._sortingColumnsForSetOperations
+        owner = IStore(Person).find(Person, id=self.teamowner.id)
+        return self.adminmembers.union(owner).order_by(
+            self._sortingColumnsForSetOperations
         )
 
-    def getMembersByStatus(self, status, orderBy=None):
+    def getMembersByStatus(self, status, order_by=None):
         """See `IPerson`."""
-        query = (
-            "TeamMembership.team = %s AND TeamMembership.status = %s "
-            "AND TeamMembership.person = Person.id"
-            % sqlvalues(self.id, status)
-        )
-        if orderBy is None:
-            orderBy = Person.sortingColumns
-        return Person.select(
-            query, clauseTables=["TeamMembership"], orderBy=orderBy
+        if order_by is None:
+            order_by = Person.sortingColumns
+        return (
+            IStore(Person)
+            .find(
+                Person,
+                TeamMembership.team == self,
+                TeamMembership.status == status,
+                TeamMembership.person == Person.id,
+            )
+            .order_by(order_by)
         )
 
     def _getEmailsByStatus(self, status):
@@ -2306,7 +2327,7 @@ class Person(
             if not isinstance(status, tuple):
                 status = (status,)
             origin.append(
-                Join(TeamMembership, TeamMembership.personID == Person.id)
+                Join(TeamMembership, TeamMembership.person_id == Person.id)
             )
             conditions = And(
                 # Membership in this team,
@@ -2442,8 +2463,8 @@ class Person(
     @property
     def activemembers(self):
         """See `IPerson`."""
-        return self.approvedmembers.union(
-            self.adminmembers, orderBy=self._sortingColumnsForSetOperations
+        return self.approvedmembers.union(self.adminmembers).order_by(
+            self._sortingColumnsForSetOperations
         )
 
     @property
@@ -2463,9 +2484,8 @@ class Person(
     @property
     def inactivemembers(self):
         """See `IPerson`."""
-        return self.expiredmembers.union(
-            self.deactivatedmembers,
-            orderBy=self._sortingColumnsForSetOperations,
+        return self.expiredmembers.union(self.deactivatedmembers).order_by(
+            self._sortingColumnsForSetOperations
         )
 
     @property
@@ -2476,8 +2496,8 @@ class Person(
     @property
     def pendingmembers(self):
         """See `IPerson`."""
-        return self.proposedmembers.union(
-            self.invited_members, orderBy=self._sortingColumnsForSetOperations
+        return self.proposedmembers.union(self.invited_members).order_by(
+            self._sortingColumnsForSetOperations
         )
 
     @property
@@ -2489,15 +2509,13 @@ class Person(
         # sorting works as is user expected, e.g. (A b C) not (A C b).
         return store.find(
             TeamMembership,
-            And(
-                TeamMembership.personID == self.id,
-                TeamMembership.teamID == Team.id,
-                TeamMembership.status.is_in(
-                    [
-                        TeamMembershipStatus.APPROVED,
-                        TeamMembershipStatus.ADMIN,
-                    ]
-                ),
+            TeamMembership.person == self,
+            TeamMembership.team_id == Team.id,
+            TeamMembership.status.is_in(
+                (
+                    TeamMembershipStatus.APPROVED,
+                    TeamMembershipStatus.ADMIN,
+                )
             ),
         ).order_by(Upper(Team.display_name), Upper(Team.name))
 
@@ -2511,14 +2529,15 @@ class Person(
     @property
     def open_membership_invitations(self):
         """See `IPerson`."""
-        return TeamMembership.select(
-            """
-            TeamMembership.person = %s AND status = %s
-            AND Person.id = TeamMembership.team
-            """
-            % sqlvalues(self.id, TeamMembershipStatus.INVITED),
-            clauseTables=["Person"],
-            orderBy=Person.sortingColumns,
+        return (
+            IStore(TeamMembership)
+            .find(
+                TeamMembership,
+                TeamMembership.person == self,
+                TeamMembership.status == TeamMembershipStatus.INVITED,
+                TeamMembership.team == Person.id,
+            )
+            .order_by(Person.sortingColumns)
         )
 
     def canDeactivate(self):
@@ -2834,22 +2853,16 @@ class Person(
         If called on an person rather than a team, this will obviously return
         no memberships at all.
         """
-        statuses = ",".join(quote(status) for status in statuses)
-        # We don't want to escape 'statuses' so we can't easily use
-        # sqlvalues() on the query below.
-        query = """
-            TeamMembership.status IN (%s)
-            AND Person.id = TeamMembership.person
-            AND TeamMembership.team = %d
-            """ % (
-            statuses,
-            self.id,
-        )
-        return TeamMembership.select(
-            query,
-            clauseTables=["Person"],
-            prejoinClauseTables=["Person"],
-            orderBy=Person.sortingColumns,
+        return DecoratedResultSet(
+            IStore(TeamMembership)
+            .find(
+                (TeamMembership, Person),
+                TeamMembership.status.is_in(statuses),
+                TeamMembership.person == Person.id,
+                TeamMembership.team == self,
+            )
+            .order_by(Person.sortingColumns),
+            result_decorator=itemgetter(0),
         )
 
     def getLatestApprovedMembershipsForPerson(self, limit=5):
@@ -2877,17 +2890,15 @@ class Person(
         store = Store.of(self)
         all_direct_memberships = store.find(
             TeamMembership,
-            And(
-                TeamMembership.personID.is_in(
-                    [team.id for team in teams] + [self.id]
-                ),
-                TeamMembership.teamID != self.id,
-                TeamMembership.status.is_in(
-                    [
-                        TeamMembershipStatus.APPROVED,
-                        TeamMembershipStatus.ADMIN,
-                    ]
-                ),
+            TeamMembership.person_id.is_in(
+                [team.id for team in teams] + [self.id]
+            ),
+            TeamMembership.team != self,
+            TeamMembership.status.is_in(
+                (
+                    TeamMembershipStatus.APPROVED,
+                    TeamMembershipStatus.ADMIN,
+                )
             ),
         ).order_by(Desc(TeamMembership.datejoined), Desc(TeamMembership.id))
         # Cast the results to list now, because they will be iterated over
@@ -2923,15 +2934,15 @@ class Person(
     @property
     def teams_participated_in(self):
         """See `IPerson`."""
-        return Person.select(
-            """
-            Person.id = TeamParticipation.team
-            AND TeamParticipation.person = %s
-            AND Person.teamowner IS NOT NULL
-            """
-            % sqlvalues(self.id),
-            clauseTables=["TeamParticipation"],
-            orderBy=Person.sortingColumns,
+        return (
+            IStore(Person)
+            .find(
+                Person,
+                Person.id == TeamParticipation.team_id,
+                TeamParticipation.person == self,
+                IsNot(Person.teamownerID, None),
+            )
+            .order_by(Person.sortingColumns)
         )
 
     @property
@@ -2941,12 +2952,12 @@ class Person(
         store = Store.of(self)
         origin = [
             Team,
-            Join(TeamParticipation, Team.id == TeamParticipation.teamID),
+            Join(TeamParticipation, Team.id == TeamParticipation.team_id),
             LeftJoin(
                 TeamMembership,
                 And(
                     TeamMembership.person == self.id,
-                    TeamMembership.teamID == TeamParticipation.teamID,
+                    TeamMembership.team_id == TeamParticipation.team_id,
                     TeamMembership.status.is_in(
                         [
                             TeamMembershipStatus.APPROVED,
@@ -2961,7 +2972,7 @@ class Person(
             find_objects,
             And(
                 TeamParticipation.person == self.id,
-                TeamParticipation.person != TeamParticipation.teamID,
+                TeamParticipation.person != TeamParticipation.team_id,
                 TeamMembership.id == None,
             ),
         )
@@ -2969,17 +2980,17 @@ class Person(
     @property
     def teams_with_icons(self):
         """See `IPerson`."""
-        return Person.select(
-            """
-            Person.id = TeamParticipation.team
-            AND TeamParticipation.person = %s
-            AND Person.teamowner IS NOT NULL
-            AND Person.icon IS NOT NULL
-            AND TeamParticipation.team != %s
-            """
-            % sqlvalues(self.id, self.id),
-            clauseTables=["TeamParticipation"],
-            orderBy=Person.sortingColumns,
+        return (
+            IStore(Person)
+            .find(
+                Person,
+                Person.id == TeamParticipation.team_id,
+                TeamParticipation.person == self,
+                IsNot(Person.teamownerID, None),
+                IsNot(Person.iconID, None),
+                TeamParticipation.team != self,
+            )
+            .order_by(Person.sortingColumns)
         )
 
     @property
@@ -5504,7 +5515,7 @@ def _get_recipients_for_team(team):
     store = IStore(Person)
     source = store.using(
         TeamMembership,
-        Join(Person, TeamMembership.personID == Person.id),
+        Join(Person, TeamMembership.person_id == Person.id),
         LeftJoin(
             EmailAddress,
             And(
@@ -5521,15 +5532,14 @@ def _get_recipients_for_team(team):
         # Find Persons that have a preferred email address and an active
         # account, or are a team, or both.
         intermediate_transitive_results = source.find(
-            (TeamMembership.personID, EmailAddress.personID),
-            In(
-                TeamMembership.status,
-                [
-                    TeamMembershipStatus.ADMIN.value,
-                    TeamMembershipStatus.APPROVED.value,
-                ],
+            (TeamMembership.person_id, EmailAddress.personID),
+            TeamMembership.status.is_in(
+                (
+                    TeamMembershipStatus.ADMIN,
+                    TeamMembershipStatus.APPROVED,
+                )
             ),
-            In(TeamMembership.teamID, pending_team_ids),
+            TeamMembership.team_id.is_in(pending_team_ids),
             Or(
                 And(
                     EmailAddress.personID != None,
diff --git a/lib/lp/registry/model/product.py b/lib/lp/registry/model/product.py
index e0edcdb..87291df 100644
--- a/lib/lp/registry/model/product.py
+++ b/lib/lp/registry/model/product.py
@@ -1855,7 +1855,7 @@ class ProductSet:
                         AccessPolicyGrantFlat,
                         Join(
                             TeamParticipation,
-                            TeamParticipation.teamID
+                            TeamParticipation.team_id
                             == AccessPolicyGrantFlat.grantee_id,
                         ),
                     ),
diff --git a/lib/lp/registry/model/sharingjob.py b/lib/lp/registry/model/sharingjob.py
index 9f61dd1..bf2bb78 100644
--- a/lib/lp/registry/model/sharingjob.py
+++ b/lib/lp/registry/model/sharingjob.py
@@ -472,7 +472,7 @@ class RemoveArtifactSubscriptionsJob(SharingJobDerived):
                 In(
                     BugSubscription.person_id,
                     Select(
-                        TeamParticipation.personID,
+                        TeamParticipation.person_id,
                         where=TeamParticipation.team == self.grantee,
                     ),
                 )
@@ -481,7 +481,7 @@ class RemoveArtifactSubscriptionsJob(SharingJobDerived):
                 In(
                     BranchSubscription.person_id,
                     Select(
-                        TeamParticipation.personID,
+                        TeamParticipation.person_id,
                         where=TeamParticipation.team == self.grantee,
                     ),
                 )
@@ -490,7 +490,7 @@ class RemoveArtifactSubscriptionsJob(SharingJobDerived):
                 In(
                     GitSubscription.person_id,
                     Select(
-                        TeamParticipation.personID,
+                        TeamParticipation.person_id,
                         where=TeamParticipation.team == self.grantee,
                     ),
                 )
@@ -499,7 +499,7 @@ class RemoveArtifactSubscriptionsJob(SharingJobDerived):
                 In(
                     SnapSubscription.person_id,
                     Select(
-                        TeamParticipation.personID,
+                        TeamParticipation.person_id,
                         where=TeamParticipation.team == self.grantee,
                     ),
                 )
@@ -508,7 +508,7 @@ class RemoveArtifactSubscriptionsJob(SharingJobDerived):
                 In(
                     SpecificationSubscription.person_id,
                     Select(
-                        TeamParticipation.personID,
+                        TeamParticipation.person_id,
                         where=TeamParticipation.team == self.grantee,
                     ),
                 )
@@ -517,7 +517,7 @@ class RemoveArtifactSubscriptionsJob(SharingJobDerived):
                 In(
                     OCIRecipeSubscription.person_id,
                     Select(
-                        TeamParticipation.personID,
+                        TeamParticipation.person_id,
                         where=TeamParticipation.team == self.grantee,
                     ),
                 )
diff --git a/lib/lp/registry/model/teammembership.py b/lib/lp/registry/model/teammembership.py
index ad05906..81f5644 100644
--- a/lib/lp/registry/model/teammembership.py
+++ b/lib/lp/registry/model/teammembership.py
@@ -12,6 +12,7 @@ from datetime import datetime, timedelta, timezone
 
 from storm.expr import Func
 from storm.info import ClassAlias
+from storm.locals import DateTime, Int, Reference, Unicode
 from storm.store import Store
 from zope.component import getUtility
 from zope.interface import implementer
@@ -45,70 +46,64 @@ from lp.registry.interfaces.teammembership import (
     TeamMembershipStatus,
 )
 from lp.services.database.constants import UTC_NOW
-from lp.services.database.datetimecol import UtcDateTimeCol
 from lp.services.database.enumcol import DBEnum
 from lp.services.database.interfaces import IStore
-from lp.services.database.sqlbase import (
-    SQLBase,
-    cursor,
-    flush_database_updates,
-    sqlvalues,
-)
-from lp.services.database.sqlobject import ForeignKey, StringCol
+from lp.services.database.sqlbase import flush_database_updates, sqlvalues
+from lp.services.database.stormbase import StormBase
 
 
 @implementer(ITeamMembership)
-class TeamMembership(SQLBase):
+class TeamMembership(StormBase):
     """See `ITeamMembership`."""
 
-    _table = "TeamMembership"
-    _defaultOrder = "id"
+    __storm_table__ = "TeamMembership"
+    __storm_order__ = "id"
 
-    team = ForeignKey(dbName="team", foreignKey="Person", notNull=True)
-    person = ForeignKey(
-        dbName="person",
-        foreignKey="Person",
-        storm_validator=validate_person,
-        notNull=True,
-    )
-    last_changed_by = ForeignKey(
-        dbName="last_changed_by",
-        foreignKey="Person",
-        storm_validator=validate_public_person,
-        default=None,
+    id = Int(primary=True)
+    team_id = Int(name="team", allow_none=False)
+    team = Reference(team_id, "Person.id")
+    person_id = Int(name="person", validator=validate_person, allow_none=False)
+    person = Reference(person_id, "Person.id")
+    last_changed_by_id = Int(
+        name="last_changed_by", validator=validate_public_person, default=None
     )
-    proposed_by = ForeignKey(
-        dbName="proposed_by",
-        foreignKey="Person",
-        storm_validator=validate_public_person,
-        default=None,
+    last_changed_by = Reference(last_changed_by_id, "Person.id")
+    proposed_by_id = Int(
+        name="proposed_by", validator=validate_public_person, default=None
     )
-    acknowledged_by = ForeignKey(
-        dbName="acknowledged_by",
-        foreignKey="Person",
-        storm_validator=validate_public_person,
-        default=None,
+    proposed_by = Reference(proposed_by_id, "Person.id")
+    acknowledged_by_id = Int(
+        name="acknowledged_by", validator=validate_public_person, default=None
     )
-    reviewed_by = ForeignKey(
-        dbName="reviewed_by",
-        foreignKey="Person",
-        storm_validator=validate_public_person,
-        default=None,
+    acknowledged_by = Reference(acknowledged_by_id, "Person.id")
+    reviewed_by_id = Int(
+        name="reviewed_by", validator=validate_public_person, default=None
     )
+    reviewed_by = Reference(reviewed_by_id, "Person.id")
     status = DBEnum(name="status", allow_none=False, enum=TeamMembershipStatus)
     # XXX: salgado, 2008-03-06: Need to rename datejoined and dateexpires to
     # match their db names.
-    datejoined = UtcDateTimeCol(dbName="date_joined", default=None)
-    dateexpires = UtcDateTimeCol(dbName="date_expires", default=None)
-    date_created = UtcDateTimeCol(default=UTC_NOW)
-    date_proposed = UtcDateTimeCol(default=None)
-    date_acknowledged = UtcDateTimeCol(default=None)
-    date_reviewed = UtcDateTimeCol(default=None)
-    date_last_changed = UtcDateTimeCol(default=None)
-    last_change_comment = StringCol(default=None)
-    proponent_comment = StringCol(default=None)
-    acknowledger_comment = StringCol(default=None)
-    reviewer_comment = StringCol(default=None)
+    datejoined = DateTime(
+        name="date_joined", default=None, tzinfo=timezone.utc
+    )
+    dateexpires = DateTime(
+        name="date_expires", default=None, tzinfo=timezone.utc
+    )
+    date_created = DateTime(default=UTC_NOW, tzinfo=timezone.utc)
+    date_proposed = DateTime(default=None, tzinfo=timezone.utc)
+    date_acknowledged = DateTime(default=None, tzinfo=timezone.utc)
+    date_reviewed = DateTime(default=None, tzinfo=timezone.utc)
+    date_last_changed = DateTime(default=None, tzinfo=timezone.utc)
+    last_change_comment = Unicode(default=None)
+    proponent_comment = Unicode(default=None)
+    acknowledger_comment = Unicode(default=None)
+    reviewer_comment = Unicode(default=None)
+
+    def __init__(self, team, person, status, dateexpires=None):
+        super().__init__()
+        self.team = team
+        self.person = person
+        self.status = status
 
     def isExpired(self):
         """See `ITeamMembership`."""
@@ -316,13 +311,14 @@ class TeamMembership(SQLBase):
             self.last_change_comment,
         )
 
+    def destroySelf(self):
+        Store.of(self).remove(self)
+
 
 @implementer(ITeamMembershipSet)
 class TeamMembershipSet:
     """See `ITeamMembershipSet`."""
 
-    _defaultOrder = ["Person.displayname", "Person.name"]
-
     def new(self, person, team, status, user, dateexpires=None, comment=None):
         """See `ITeamMembershipSet`."""
         proposed = TeamMembershipStatus.PROPOSED
@@ -363,7 +359,11 @@ class TeamMembershipSet:
 
     def getByPersonAndTeam(self, person, team):
         """See `ITeamMembershipSet`."""
-        return TeamMembership.selectOneBy(person=person, team=team)
+        return (
+            IStore(TeamMembership)
+            .find(TeamMembership, person=person, team=team)
+            .one()
+        )
 
     def getMembershipsToExpire(self, when=None):
         """See `ITeamMembershipSet`."""
@@ -408,27 +408,16 @@ class TeamMembershipSet:
     def deactivateActiveMemberships(self, team, comment, reviewer):
         """See `ITeamMembershipSet`."""
         now = datetime.now(timezone.utc)
-        cur = cursor()
         all_members = list(team.activemembers)
-        cur.execute(
-            """
-            UPDATE TeamMembership
-            SET status=%(status)s,
-                last_changed_by=%(last_changed_by)s,
-                last_change_comment=%(comment)s,
-                date_last_changed=%(date_last_changed)s
-            WHERE
-                TeamMembership.team = %(team)s
-                AND TeamMembership.status IN %(original_statuses)s
-            """,
-            dict(
-                status=TeamMembershipStatus.DEACTIVATED,
-                last_changed_by=reviewer.id,
-                comment=comment,
-                date_last_changed=now,
-                team=team.id,
-                original_statuses=ACTIVE_STATES,
-            ),
+        IStore(TeamMembership).find(
+            TeamMembership,
+            TeamMembership.team == team,
+            TeamMembership.status.is_in(ACTIVE_STATES),
+        ).set(
+            status=TeamMembershipStatus.DEACTIVATED,
+            last_changed_by_id=reviewer.id,
+            last_change_comment=comment,
+            date_last_changed=now,
         )
         for member in all_members:
             # store.invalidate() is called for each iteration.
@@ -436,11 +425,14 @@ class TeamMembershipSet:
 
 
 @implementer(ITeamParticipation)
-class TeamParticipation(SQLBase):
-    _table = "TeamParticipation"
+class TeamParticipation(StormBase):
+    __storm_table__ = "TeamParticipation"
 
-    team = ForeignKey(dbName="team", foreignKey="Person", notNull=True)
-    person = ForeignKey(dbName="person", foreignKey="Person", notNull=True)
+    id = Int(primary=True)
+    team_id = Int(name="team", allow_none=False)
+    team = Reference(team_id, "Person.id")
+    person_id = Int(name="person", allow_none=False)
+    person = Reference(person_id, "Person.id")
 
 
 def _cleanTeamParticipation(child, parent):
@@ -619,8 +611,8 @@ def find_team_participations(people, teams=None):
         Team = ClassAlias(Person, "Team")
         person_ids = [person.id for person in people]
         conditions = [
-            TeamParticipation.personID == Person.id,
-            TeamParticipation.teamID == Team.id,
+            TeamParticipation.person_id == Person.id,
+            TeamParticipation.team_id == Team.id,
             Person.id.is_in(person_ids),
         ]
         team_ids = [team.id for team in teams_to_query]
diff --git a/lib/lp/registry/scripts/tests/test_closeaccount.py b/lib/lp/registry/scripts/tests/test_closeaccount.py
index 458a2a7..cd857d2 100644
--- a/lib/lp/registry/scripts/tests/test_closeaccount.py
+++ b/lib/lp/registry/scripts/tests/test_closeaccount.py
@@ -930,8 +930,8 @@ class TestCloseAccount(TestCaseWithFactory):
         self.assertContentEqual(
             [person_id, team.id],
             store.find(
-                TeamParticipation.teamID,
-                TeamParticipation.personID == person_id,
+                TeamParticipation.team_id,
+                TeamParticipation.person_id == person_id,
             ),
         )
         script = self.makeScript([person.name])
@@ -941,8 +941,8 @@ class TestCloseAccount(TestCaseWithFactory):
         self.assertContentEqual(
             [person_id],
             store.find(
-                TeamParticipation.teamID,
-                TeamParticipation.personID == person_id,
+                TeamParticipation.team_id,
+                TeamParticipation.person_id == person_id,
             ),
         )
 
diff --git a/lib/lp/registry/services/sharingservice.py b/lib/lp/registry/services/sharingservice.py
index e750aba..5fc8c27 100644
--- a/lib/lp/registry/services/sharingservice.py
+++ b/lib/lp/registry/services/sharingservice.py
@@ -112,13 +112,13 @@ class SharingService:
             AccessPolicyGrant,
             Join(
                 TeamParticipation,
-                TeamParticipation.teamID == AccessPolicyGrant.grantee_id,
+                TeamParticipation.team_id == AccessPolicyGrant.grantee_id,
             ),
         ]
         result = store.using(*tables).find(
             AccessPolicyGrant,
             AccessPolicyGrant.policy_id.is_in(policy_ids),
-            TeamParticipation.personID == person.id,
+            TeamParticipation.person_id == person.id,
         )
         return not result.is_empty()
 
@@ -154,9 +154,9 @@ class SharingService:
             with_statement = With(
                 "teams",
                 Select(
-                    TeamParticipation.teamID,
+                    TeamParticipation.team_id,
                     tables=TeamParticipation,
-                    where=TeamParticipation.person == user.id,
+                    where=TeamParticipation.person == user,
                 ),
             )
             teams_sql = SQL("SELECT team from teams")
@@ -453,7 +453,7 @@ class SharingService:
             ),
             Join(
                 TeamParticipation,
-                TeamParticipation.teamID == AccessPolicyGrantFlat.grantee_id,
+                TeamParticipation.team_id == AccessPolicyGrantFlat.grantee_id,
             ),
         )
         spec_ids = [spec.id for spec in specifications]
@@ -464,7 +464,7 @@ class SharingService:
                     AccessPolicyGrantFlat.abstract_artifact_id == None,
                     AccessArtifact.specification == Specification.id,
                 ),
-                TeamParticipation.personID == person.id,
+                TeamParticipation.person == person,
                 In(Specification.id, spec_ids),
             )
         )
@@ -686,13 +686,13 @@ class SharingService:
         store = IStore(AccessArtifactGrant)
         tables = [
             Person,
-            Join(TeamParticipation, TeamParticipation.personID == Person.id),
+            Join(TeamParticipation, TeamParticipation.person_id == Person.id),
         ]
         result_set = store.using(*tables).find(
             Person,
             Or(
-                In(TeamParticipation.teamID, policy_grantees),
-                In(TeamParticipation.teamID, artifact_grantees),
+                TeamParticipation.team_id.is_in(policy_grantees),
+                TeamParticipation.team_id.is_in(artifact_grantees),
             ),
             In(Person.id, person_ids),
         )
diff --git a/lib/lp/registry/stories/teammembership/xx-add-member.rst b/lib/lp/registry/stories/teammembership/xx-add-member.rst
index 9a66d96..b80bb89 100644
--- a/lib/lp/registry/stories/teammembership/xx-add-member.rst
+++ b/lib/lp/registry/stories/teammembership/xx-add-member.rst
@@ -22,10 +22,13 @@ Let's make sure that 'cprov' is now an Approved member of
 
     >>> from lp.registry.model.person import Person
     >>> from lp.registry.model.teammembership import TeamMembership
+    >>> from lp.services.database.interfaces import IStore
     >>> cprov = Person.byName("cprov")
     >>> landscape_team = Person.byName("landscape-developers")
-    >>> cprov_landscape_membership = TeamMembership.selectOneBy(
-    ...     personID=cprov.id, teamID=landscape_team.id
+    >>> cprov_landscape_membership = (
+    ...     IStore(TeamMembership)
+    ...     .find(TeamMembership, person=cprov, team=landscape_team)
+    ...     .one()
     ... )
     >>> cprov_landscape_membership.status.title
     'Approved'
@@ -56,8 +59,10 @@ members.
     >>> launchpad = Person.byName("launchpad")
     >>> launchpad in landscape_team.activemembers
     False
-    >>> membership = TeamMembership.selectOneBy(
-    ...     person=launchpad, team=landscape_team
+    >>> membership = (
+    ...     IStore(TeamMembership)
+    ...     .find(TeamMembership, person=launchpad, team=landscape_team)
+    ...     .one()
     ... )
     >>> membership.status.title
     'Invited'
diff --git a/lib/lp/registry/tests/test_teammembership.py b/lib/lp/registry/tests/test_teammembership.py
index ff2792a..ec7e3c9 100644
--- a/lib/lp/registry/tests/test_teammembership.py
+++ b/lib/lp/registry/tests/test_teammembership.py
@@ -811,8 +811,11 @@ class TestTeamMembership(TestCaseWithFactory):
         operate on the correct data.
         """
         login("foo.bar@xxxxxxxxxxxxx")
-        tm = TeamMembership.selectFirstBy(
-            status=TeamMembershipStatus.APPROVED, orderBy="id"
+        tm = (
+            IStore(TeamMembership)
+            .find(TeamMembership, status=TeamMembershipStatus.APPROVED)
+            .order_by(TeamMembership.id)
+            .first()
         )
         tm.setStatus(
             TeamMembershipStatus.DEACTIVATED,
diff --git a/lib/lp/registry/vocabularies.py b/lib/lp/registry/vocabularies.py
index 98333e0..9add187 100644
--- a/lib/lp/registry/vocabularies.py
+++ b/lib/lp/registry/vocabularies.py
@@ -402,7 +402,7 @@ class UserTeamsParticipationVocabulary(SQLObjectVocabularyBase):
         if launchbag.user:
             user = launchbag.user
             clauses = [
-                Person.id == TeamParticipation.teamID,
+                Person.id == TeamParticipation.team_id,
                 TeamParticipation.person == user,
                 Person.teamowner != None,
             ]
@@ -879,14 +879,13 @@ class ValidTeamMemberVocabulary(
 
     @property
     def extra_clause(self):
-        clause = SQL(
-            """
-            Person.id NOT IN (
-                SELECT team FROM TeamParticipation
-                WHERE person = %d
+        clause = Not(
+            Person.id.is_in(
+                Select(
+                    TeamParticipation.team_id,
+                    TeamParticipation.person == self.team,
                 )
-            """
-            % self.team.id
+            )
         )
         if self.is_closed_team:
             clause = And(
@@ -960,8 +959,8 @@ class AllUserTeamsParticipationVocabulary(ValidTeamVocabulary):
                 Join(
                     tp_alias,
                     And(
-                        tp_alias.teamID == Person.id,
-                        tp_alias.personID == user.id,
+                        tp_alias.team_id == Person.id,
+                        tp_alias.person_id == user.id,
                     ),
                 )
             ]
diff --git a/lib/lp/scripts/garbo.py b/lib/lp/scripts/garbo.py
index 7781da4..f27f0b5 100644
--- a/lib/lp/scripts/garbo.py
+++ b/lib/lp/scripts/garbo.py
@@ -1929,8 +1929,8 @@ class ArchiveAuthTokenDeactivator(BulkPruner):
                     ArchiveSubscriber.status
                     == ArchiveSubscriberStatus.CURRENT,
                     ArchiveSubscriber.subscriber_id
-                    == TeamParticipation.teamID,
-                    TeamParticipation.personID == ArchiveAuthToken.person_id,
+                    == TeamParticipation.team_id,
+                    TeamParticipation.person_id == ArchiveAuthToken.person_id,
                 ),
             ),
         )
diff --git a/lib/lp/scripts/tests/test_garbo.py b/lib/lp/scripts/tests/test_garbo.py
index ea92f5a..e331386 100644
--- a/lib/lp/scripts/tests/test_garbo.py
+++ b/lib/lp/scripts/tests/test_garbo.py
@@ -785,7 +785,7 @@ class TestGarbo(FakeAdapterMixin, TestCaseWithFactory):
         removeSecurityProxy(merged_team).merged = self.factory.makeTeam()
         store = Store.of(team)
         store.flush()
-        result = store.find(TeamMembership, TeamMembership.team == team.id)
+        result = store.find(TeamMembership, team=team)
         self.assertEqual(3, result.count())
         self.runDaily()
         self.assertContentEqual([team.teamowner], [tm.person for tm in result])
diff --git a/lib/lp/services/auth/model.py b/lib/lp/services/auth/model.py
index abedcbf..436c382 100644
--- a/lib/lp/services/auth/model.py
+++ b/lib/lp/services/auth/model.py
@@ -192,9 +192,9 @@ class AccessTokenSet:
                     Or(
                         AccessToken.owner_id.is_in(
                             Select(
-                                TeamParticipation.teamID,
+                                TeamParticipation.team_id,
                                 where=TeamParticipation.person
-                                == visible_by_user.id,
+                                == visible_by_user,
                             )
                         ),
                         AccessToken.git_repository_id.is_in(
diff --git a/lib/lp/snappy/model/snap.py b/lib/lp/snappy/model/snap.py
index c55f435..6572d17 100644
--- a/lib/lp/snappy/model/snap.py
+++ b/lib/lp/snappy/model/snap.py
@@ -2066,7 +2066,7 @@ def get_snap_privacy_filter(user):
         ArrayIntersects(
             SQL("%s.access_grants" % Snap.__storm_table__),
             Select(
-                ArrayAgg(TeamParticipation.teamID),
+                ArrayAgg(TeamParticipation.team_id),
                 tables=TeamParticipation,
                 where=(TeamParticipation.person == user),
             ),
@@ -2083,7 +2083,7 @@ def get_snap_privacy_filter(user):
                     AccessPolicyGrant,
                     Join(
                         TeamParticipation,
-                        TeamParticipation.teamID
+                        TeamParticipation.team_id
                         == AccessPolicyGrant.grantee_id,
                     ),
                 ),
@@ -2093,13 +2093,13 @@ def get_snap_privacy_filter(user):
         False,
     )
 
-    admin_team_id = getUtility(ILaunchpadCelebrities).admin.id
+    admin_team = getUtility(ILaunchpadCelebrities).admin
     user_is_admin = Exists(
         Select(
-            TeamParticipation.personID,
+            TeamParticipation.person_id,
             tables=[TeamParticipation],
             where=And(
-                TeamParticipation.teamID == admin_team_id,
+                TeamParticipation.team == admin_team,
                 TeamParticipation.person == user,
             ),
         )
diff --git a/lib/lp/soyuz/doc/gina-multiple-arch.rst b/lib/lp/soyuz/doc/gina-multiple-arch.rst
index 3d16759..c9bbea2 100644
--- a/lib/lp/soyuz/doc/gina-multiple-arch.rst
+++ b/lib/lp/soyuz/doc/gina-multiple-arch.rst
@@ -20,7 +20,9 @@ Get the current counts of stuff in the database:
     >>> orig_spr_count = SourcePackageRelease.select().count()
     >>> orig_sspph_count = IStore(SSPPH).find(SSPPH).count()
     >>> orig_person_count = Person.select().count()
-    >>> orig_tp_count = TeamParticipation.select().count()
+    >>> orig_tp_count = (
+    ...     IStore(TeamParticipation).find(TeamParticipation).count()
+    ... )
     >>> orig_email_count = EmailAddress.select().count()
     >>> orig_bpr_count = (
     ...     IStore(BinaryPackageRelease).find(BinaryPackageRelease).count()
@@ -138,7 +140,10 @@ porridge):
 
     >>> print(Person.select().count() - orig_person_count)
     2
-    >>> print(TeamParticipation.select().count() - orig_tp_count)
+    >>> print(
+    ...     IStore(TeamParticipation).find(TeamParticipation).count()
+    ...     - orig_tp_count
+    ... )
     2
     >>> print(EmailAddress.select().count() - orig_email_count)
     2
diff --git a/lib/lp/soyuz/doc/gina.rst b/lib/lp/soyuz/doc/gina.rst
index c225f5c..db82fd9 100644
--- a/lib/lp/soyuz/doc/gina.rst
+++ b/lib/lp/soyuz/doc/gina.rst
@@ -27,7 +27,9 @@ Get the current counts of stuff in the database:
     >>> orig_spr_count = SourcePackageRelease.select().count()
     >>> orig_sspph_count = IStore(SSPPH).find(SSPPH).count()
     >>> orig_person_count = Person.select().count()
-    >>> orig_tp_count = TeamParticipation.select().count()
+    >>> orig_tp_count = (
+    ...     IStore(TeamParticipation).find(TeamParticipation).count()
+    ... )
     >>> orig_email_count = EmailAddress.select().count()
     >>> orig_bpr_count = (
     ...     IStore(BinaryPackageRelease).find(BinaryPackageRelease).count()
@@ -571,7 +573,10 @@ Kamion, 2 being uploaded by mdz and 2 by doko).
     cjwatson
     >>> print(Person.select().count() - orig_person_count)
     13
-    >>> print(TeamParticipation.select().count() - orig_tp_count)
+    >>> print(
+    ...     IStore(TeamParticipation).find(TeamParticipation).count()
+    ...     - orig_tp_count
+    ... )
     13
     >>> print(EmailAddress.select().count() - orig_email_count)
     13
@@ -664,7 +669,10 @@ changed, etc.
     17
     >>> print(Person.select().count() - orig_person_count)
     13
-    >>> print(TeamParticipation.select().count() - orig_tp_count)
+    >>> print(
+    ...     IStore(TeamParticipation).find(TeamParticipation).count()
+    ...     - orig_tp_count
+    ... )
     13
     >>> print(EmailAddress.select().count() - orig_email_count)
     13
diff --git a/lib/lp/soyuz/model/archive.py b/lib/lp/soyuz/model/archive.py
index 72264d4..c108e11 100644
--- a/lib/lp/soyuz/model/archive.py
+++ b/lib/lp/soyuz/model/archive.py
@@ -3716,10 +3716,10 @@ class ArchiveSet:
                 # Create a subselect to capture all the teams that are
                 # owners of archives AND the user is a member of:
                 user_teams_subselect = Select(
-                    TeamParticipation.teamID,
+                    TeamParticipation.team_id,
                     where=And(
-                        TeamParticipation.personID == user.id,
-                        TeamParticipation.teamID == Archive.ownerID,
+                        TeamParticipation.person == user,
+                        TeamParticipation.team_id == Archive.ownerID,
                     ),
                 )
 
@@ -3889,7 +3889,7 @@ def get_archive_privacy_filter(user):
             Not(Archive.private),
             Archive.ownerID.is_in(
                 Select(
-                    TeamParticipation.teamID,
+                    TeamParticipation.team_id,
                     where=(TeamParticipation.person == user),
                 )
             ),
@@ -3925,7 +3925,7 @@ def get_enabled_archive_filter(
 
     main = getUtility(IComponentSet)["main"]
     user_teams = Select(
-        TeamParticipation.teamID, where=TeamParticipation.person == user
+        TeamParticipation.team_id, where=TeamParticipation.person == user
     )
 
     is_owner = Archive.ownerID.is_in(user_teams)
diff --git a/lib/lp/soyuz/model/archiveauthtoken.py b/lib/lp/soyuz/model/archiveauthtoken.py
index d5d0d1b..42b7673 100644
--- a/lib/lp/soyuz/model/archiveauthtoken.py
+++ b/lib/lp/soyuz/model/archiveauthtoken.py
@@ -123,8 +123,8 @@ class ArchiveAuthTokenSet:
                         TeamParticipation,
                         And(
                             ArchiveSubscriber.subscriber_id
-                            == TeamParticipation.teamID,
-                            TeamParticipation.personID
+                            == TeamParticipation.team_id,
+                            TeamParticipation.person_id
                             == ArchiveAuthToken.person_id,
                         ),
                     ),
diff --git a/lib/lp/soyuz/model/archivepermission.py b/lib/lp/soyuz/model/archivepermission.py
index 4ee25fa..fd699d2 100644
--- a/lib/lp/soyuz/model/archivepermission.py
+++ b/lib/lp/soyuz/model/archivepermission.py
@@ -178,7 +178,7 @@ class ArchivePermissionSet:
         clauses = [
             ArchivePermission.archive == archive,
             ArchivePermission.permission == permission,
-            ArchivePermission.person == TeamParticipation.teamID,
+            ArchivePermission.person == TeamParticipation.team_id,
             TeamParticipation.person == person,
         ]
 
diff --git a/lib/lp/soyuz/model/archivesubscriber.py b/lib/lp/soyuz/model/archivesubscriber.py
index 8a393fa..d57cf23 100644
--- a/lib/lp/soyuz/model/archivesubscriber.py
+++ b/lib/lp/soyuz/model/archivesubscriber.py
@@ -111,7 +111,7 @@ class ArchiveSubscriber(StormBase):
             )
 
             team_participation = Join(
-                TeamParticipation, TeamParticipation.personID == Person.id
+                TeamParticipation, TeamParticipation.person_id == Person.id
             )
 
             # Only return people with preferred email address set.
@@ -126,7 +126,7 @@ class ArchiveSubscriber(StormBase):
             ).find(
                 (Person, EmailAddress),
                 EmailAddress.status == EmailAddressStatus.PREFERRED,
-                TeamParticipation.teamID == self.subscriber_id,
+                TeamParticipation.team == self.subscriber,
                 Person.teamowner == None,
                 # There is no existing archive auth token.
                 ArchiveAuthToken.person_id == None,
@@ -184,7 +184,7 @@ class ArchiveSubscriberSet:
             ArchiveSubscriber,
             Join(
                 TeamParticipation,
-                TeamParticipation.teamID == ArchiveSubscriber.subscriber_id,
+                TeamParticipation.team_id == ArchiveSubscriber.subscriber_id,
             ),
         ]
 
@@ -218,7 +218,7 @@ class ArchiveSubscriberSet:
             store.using(*origin)
             .find(
                 result_row,
-                TeamParticipation.personID == subscriber.id,
+                TeamParticipation.person == subscriber,
                 *extra_exprs,
             )
             .order_by(Desc(ArchiveSubscriber.date_created))
diff --git a/lib/lp/translations/model/translationgroup.py b/lib/lp/translations/model/translationgroup.py
index fb304b2..38af7d3 100644
--- a/lib/lp/translations/model/translationgroup.py
+++ b/lib/lp/translations/model/translationgroup.py
@@ -345,7 +345,7 @@ class TranslationGroupSet:
             ),
             Join(
                 TeamParticipation,
-                TeamParticipation.teamID == Translator.translator_id,
+                TeamParticipation.team_id == Translator.translator_id,
             ),
         ]
         result = store.using(*origin).find(
diff --git a/lib/lp/translations/model/translationsperson.py b/lib/lp/translations/model/translationsperson.py
index 99cd46d..96529b1 100644
--- a/lib/lp/translations/model/translationsperson.py
+++ b/lib/lp/translations/model/translationsperson.py
@@ -293,9 +293,9 @@ class TranslationsPerson:
                     Join(
                         TeamParticipation,
                         And(
-                            TeamParticipation.teamID
+                            TeamParticipation.team_id
                             == Translator.translator_id,
-                            TeamParticipation.personID == self.person.id,
+                            TeamParticipation.person == self.person,
                         ),
                     ),
                 ],
@@ -446,8 +446,8 @@ class TranslationsPerson:
         # query won't be interested in its actual contents anyway.
         Reviewership = ClassAlias(TeamParticipation, "Reviewership")
         reviewerjoin_condition = And(
-            Reviewership.teamID == Translator.translator_id,
-            Reviewership.personID == self.person.id,
+            Reviewership.team_id == Translator.translator_id,
+            Reviewership.person_id == self.person.id,
         )
         if expect_reviewer_status:
             TranslationTeamJoin = Join(Reviewership, reviewerjoin_condition)
diff --git a/lib/lp/translations/model/translator.py b/lib/lp/translations/model/translator.py
index 2abefeb..557454e 100644
--- a/lib/lp/translations/model/translator.py
+++ b/lib/lp/translations/model/translator.py
@@ -70,7 +70,7 @@ class TranslatorSet:
             Translator,
             Join(
                 TeamParticipation,
-                TeamParticipation.teamID == Translator.translator_id,
+                TeamParticipation.team_id == Translator.translator_id,
             ),
             Join(
                 "TranslationGroup",