Skip to content

Implementing SQLAlchemy Best Practices in iDrv5-MyFR8

This document provides practical guidance for implementing the SQLAlchemy relationship best practices in our codebase.

This document provides practical guidance for implementing the SQLAlchemy relationship best practices in our codebase.

Problem:

# In models/rates.py
from models.customer import Customer
class Rate(db.Model):
customer = db.relationship(Customer, back_populates='rates')
# In models/customer.py
from models.rates import Rate
class Customer(db.Model):
rates = db.relationship(Rate, back_populates='customer')

Solution:

# In models/rates.py
# No import needed!
class Rate(db.Model):
customer = db.relationship('Customer', back_populates='rates')
# In models/customer.py
# No import needed!
class Customer(db.Model):
rates = db.relationship('Rate', back_populates='customer')

Problem:

class FreightRate(db.Model):
rate_card = relationship("models.sqlalchemy_freight.RateCard", back_populates="rates")

Solution:

class FreightRate(db.Model):
rate_card = relationship("RateCard", back_populates="rates")

3. Add Missing Relationship Back-References

Section titled “3. Add Missing Relationship Back-References”

Problem:

class WorkflowDefinition(db.Model):
# Missing relationship definitions
pass
class WorkflowState(db.Model):
definition = db.relationship('WorkflowDefinition', back_populates='workflow_states')

Solution:

class WorkflowDefinition(db.Model):
# Add the missing back-reference
workflow_states = db.relationship('WorkflowState', back_populates='definition')
class WorkflowState(db.Model):
definition = db.relationship('WorkflowDefinition', back_populates='workflow_states')

Problem:

# Parent model with insufficient cascade options
class Post(db.Model):
comments = db.relationship('Comment', back_populates='post')
# Child model references parent
class Comment(db.Model):
post = db.relationship('Post', back_populates='comments')

Solution:

# Add appropriate cascade options
class Post(db.Model):
comments = db.relationship('Comment', back_populates='post',
cascade='all, delete-orphan')
class Comment(db.Model):
post = db.relationship('Post', back_populates='comments')

1. Identify Models with Relationship Issues

Section titled “1. Identify Models with Relationship Issues”

Use this command to find relationships in your models:

Terminal window
grep -r "relationship(" --include="*.py" ./models/

Look for:

  • Fully-qualified model paths (models.module.Model)
  • Missing back-references (relationship defined on one side only)
  • Inconsistent naming between related models
  1. Start with the most fundamental models (those with fewer dependencies)
  2. Replace fully-qualified references with string model names
  3. Add missing back-references on related models
  4. Test the application after each module update

Common issues to watch for after changes:

  • Missing tables in queries
  • AttributeError for undefined relationships
  • Inconsistent data when using cascade operations

Original code:

class Fleet(db.Model):
manager = db.relationship('User', backref=db.backref('managed_fleets', lazy=True))
vehicles = db.relationship('Vehicle', backref='fleet', lazy=True)
class Vehicle(db.Model):
# Notice the relationship is defined via backref on Fleet, not here
pass

Improved code:

class Fleet(db.Model):
manager = db.relationship('User', back_populates='managed_fleets')
vehicles = db.relationship('Vehicle', back_populates='fleet')
class Vehicle(db.Model):
# Explicitly define the relationship on both sides
fleet = db.relationship('Fleet', back_populates='vehicles')
  1. Check that all models load correctly
  2. Verify relationship queries work as expected
  3. Test cascade operations if applicable
  4. Check API endpoints that rely on these relationships
  1. Use linters or code reviews to catch relationship issues
  2. Document complex relationship patterns
  3. Keep the SQLAlchemy Relationship Guide updated
  4. Train new team members on proper relationship patterns