Skip to content

Commit d7a6024

Browse files
Henkhoganpre-commit-ci[bot]sheinbergonagronholm
authored
Allow to opt out from special naming when fieldname ends with _id (#356)
* Allow to opt out from special naming when fieldname ends with _id * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * PR Fixes * Fix changes.rst * Split the line in CHANGES.rst --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Co-authored-by: idan.sheinberg <[email protected]> Co-authored-by: Alex Grönholm <[email protected]>
1 parent cf87688 commit d7a6024

File tree

4 files changed

+62
-1
lines changed

4 files changed

+62
-1
lines changed

CHANGES.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ Version history
55

66
- Dropped support for Python 3.9
77
- Fix Postgres ``DOMAIN`` adaptation regression introduced in SQLAlchemy 2.0.42 (PR by @sheinbergon)
8+
- Support disabling special naming logic for single column many-to-one and one-to-one relationships
9+
(PR by @Henkhogan, revised by @sheinbergon)
810

911
**3.1.1**
1012

README.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,8 @@ values must be delimited by commas, e.g. ``--options noconstraints,nobidi``):
103103
* ``noconstraints``: ignore constraints (foreign key, unique etc.)
104104
* ``nocomments``: ignore table/column comments
105105
* ``noindexes``: ignore indexes
106+
* ``noidsuffix``: prevent the special naming logic for single column many-to-one
107+
and one-to-one relationships (see `Relationship naming logic`_ for details)
106108

107109
* ``declarative``
108110

src/sqlacodegen/generators.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -766,6 +766,7 @@ class DeclarativeGenerator(TablesGenerator):
766766
"use_inflect",
767767
"nojoined",
768768
"nobidi",
769+
"noidsuffix",
769770
}
770771

771772
def __init__(
@@ -1102,7 +1103,7 @@ def generate_relationship_name(
11021103

11031104
# If there's a constraint with a single column that ends with "_id", use the
11041105
# preceding part as the relationship name
1105-
if relationship.constraint:
1106+
if relationship.constraint and "noidsuffix" not in self.options:
11061107
is_source = relationship.source.table is relationship.constraint.table
11071108
if is_source or relationship.type not in (
11081109
RelationshipType.ONE_TO_ONE,

tests/test_generator_declarative.py

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1563,6 +1563,62 @@ class SimpleItems(Base):
15631563
)
15641564

15651565

1566+
@pytest.mark.parametrize("generator", [["noidsuffix"]], indirect=True)
1567+
def test_named_foreign_key_constraints_with_noidsuffix(
1568+
generator: CodeGenerator,
1569+
) -> None:
1570+
Table(
1571+
"simple_items",
1572+
generator.metadata,
1573+
Column("id", INTEGER, primary_key=True),
1574+
Column("container_id", INTEGER),
1575+
ForeignKeyConstraint(
1576+
["container_id"], ["simple_containers.id"], name="foreignkeytest"
1577+
),
1578+
)
1579+
Table(
1580+
"simple_containers",
1581+
generator.metadata,
1582+
Column("id", INTEGER, primary_key=True),
1583+
)
1584+
1585+
validate_code(
1586+
generator.generate(),
1587+
"""\
1588+
from typing import Optional
1589+
1590+
from sqlalchemy import ForeignKeyConstraint, Integer
1591+
from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column, relationship
1592+
1593+
class Base(DeclarativeBase):
1594+
pass
1595+
1596+
1597+
class SimpleContainers(Base):
1598+
__tablename__ = 'simple_containers'
1599+
1600+
id: Mapped[int] = mapped_column(Integer, primary_key=True)
1601+
1602+
simple_items: Mapped[list['SimpleItems']] = relationship('SimpleItems', \
1603+
back_populates='simple_containers')
1604+
1605+
1606+
class SimpleItems(Base):
1607+
__tablename__ = 'simple_items'
1608+
__table_args__ = (
1609+
ForeignKeyConstraint(['container_id'], ['simple_containers.id'], \
1610+
name='foreignkeytest'),
1611+
)
1612+
1613+
id: Mapped[int] = mapped_column(Integer, primary_key=True)
1614+
container_id: Mapped[Optional[int]] = mapped_column(Integer)
1615+
1616+
simple_containers: Mapped[Optional['SimpleContainers']] = relationship('SimpleContainers', \
1617+
back_populates='simple_items')
1618+
""",
1619+
)
1620+
1621+
15661622
# @pytest.mark.xfail(strict=True)
15671623
def test_colname_import_conflict(generator: CodeGenerator) -> None:
15681624
Table(

0 commit comments

Comments
 (0)