Problem
All relationships are currently rendered as 1:N regardless of the actual cardinality. Two common cases are misrepresented:
1:1 relationships
When a foreign key column is also part of the primary key, the relationship is 1:1, not 1:N.
```python
class UserProfile(Base):
tablename = "user_profile"
user_id = Column(Integer, ForeignKey("user.id"), primary_key=True) # 1:1, not 1:N
```
Optional vs required (nullable FKs)
A nullable FK means the relationship is optional (0..1 or 0..N). A non-nullable FK means it is required (1 or 1..N). This distinction is currently lost.
```python
assignee_id = Column(Integer, ForeignKey("user.id"), nullable=True) # 0..N — optional
department_id = Column(Integer, ForeignKey("dept.id"), nullable=False) # 1..N — required
```
Proposed cardinality rules
| FK condition |
Left side |
Right side |
| FK is also PK |
1 |
1 |
| FK is nullable |
0..1 or 0..N |
— |
| FK is non-nullable |
1 |
— |
| FK + unique constraint |
1 |
1 |
Impact
Incorrect cardinality makes the ERD misleading for schema review and documentation purposes.
Problem
All relationships are currently rendered as 1:N regardless of the actual cardinality. Two common cases are misrepresented:
1:1 relationships
When a foreign key column is also part of the primary key, the relationship is 1:1, not 1:N.
```python
class UserProfile(Base):
tablename = "user_profile"
user_id = Column(Integer, ForeignKey("user.id"), primary_key=True) # 1:1, not 1:N
```
Optional vs required (nullable FKs)
A nullable FK means the relationship is optional (0..1 or 0..N). A non-nullable FK means it is required (1 or 1..N). This distinction is currently lost.
```python
assignee_id = Column(Integer, ForeignKey("user.id"), nullable=True) # 0..N — optional
department_id = Column(Integer, ForeignKey("dept.id"), nullable=False) # 1..N — required
```
Proposed cardinality rules
110..1or0..N111Impact
Incorrect cardinality makes the ERD misleading for schema review and documentation purposes.