Flask Training , study and exam guide
1 Introduction to Flask
1.1 What is Flask?
1.2 History and Evolution of Flask
1.3 Flask vs Django
1.4 Setting Up the Development Environment
2 Flask Basics
2.1 Installing Flask
2.2 Creating Your First Flask Application
2.3 Understanding the Flask Application Structure
2.4 Routing in Flask
2.5 Variable Rules in Routing
2.6 HTTP Methods (GET, POST, PUT, DELETE)
3 Templates and Static Files
3.1 Introduction to Jinja2 Templates
3.2 Rendering Templates
3.3 Template Inheritance
3.4 Static Files (CSS, JavaScript, Images)
3.5 Using Bootstrap with Flask
4 Forms and User Input
4.1 Introduction to Flask-WTF
4.2 Creating Forms with Flask-WTF
4.3 Validating User Input
4.4 Handling File Uploads
4.5 Flash Messages
5 Databases with Flask
5.1 Introduction to SQLAlchemy
5.2 Setting Up a Database
5.3 Defining Models
5.4 CRUD Operations with SQLAlchemy
5.5 Relationships in SQLAlchemy
5.6 Migrations with Flask-Migrate
6 Authentication and Authorization
6.1 Introduction to Flask-Login
6.2 User Authentication
6.3 Protecting Routes with Login Required
6.4 User Roles and Permissions
6.5 Password Hashing with Werkzeug
7 RESTful APIs with Flask
7.1 Introduction to RESTful APIs
7.2 Creating a RESTful API with Flask
7.3 Serializing and Deserializing Data
7.4 Handling API Errors
7.5 Authentication for APIs
8 Testing Flask Applications
8.1 Introduction to Unit Testing
8.2 Writing Tests with Flask-Testing
8.3 Testing Routes and Views
8.4 Testing Database Interactions
8.5 Continuous Integration with Flask
9 Deployment and Scaling
9.1 Introduction to Deployment
9.2 Deploying Flask Applications on Heroku
9.3 Deploying Flask Applications on AWS
9.4 Scaling Flask Applications
9.5 Load Balancing and Caching
10 Advanced Topics
10.1 Background Tasks with Celery
10.2 WebSockets with Flask-SocketIO
10.3 Internationalization and Localization
10.4 Custom Error Pages
10.5 Extending Flask with Blueprints
11 Exam Preparation
11.1 Review of Key Concepts
11.2 Practice Questions
11.3 Mock Exams
11.4 Tips for the Exam Day
5 to 5 Relationships in SQLAlchemy

5 to 5 Relationships in SQLAlchemy

Key Concepts

Many-to-Many Relationships

Many-to-many relationships occur when multiple records in one table are associated with multiple records in another table. In SQLAlchemy, this is typically managed using an association table that links the two main tables.

Association Tables

An association table is a middleman table that contains foreign keys pointing to the primary keys of the two related tables. This table does not have its own meaningful data but serves to connect the two main tables.

from sqlalchemy import Table, Column, Integer, ForeignKey
from sqlalchemy.orm import relationship
from sqlalchemy.ext.declarative import declarative_base

Base = declarative_base()

association_table = Table('association', Base.metadata,
    Column('left_id', Integer, ForeignKey('left.id')),
    Column('right_id', Integer, ForeignKey('right.id'))
)

class Left(Base):
    __tablename__ = 'left'
    id = Column(Integer, primary_key=True)
    rights = relationship("Right", secondary=association_table, back_populates="lefts")

class Right(Base):
    __tablename__ = 'right'
    id = Column(Integer, primary_key=True)
    lefts = relationship("Left", secondary=association_table, back_populates="rights")
    

Backref and Back_Populates

The backref and back_populates arguments in the relationship function are used to define the bidirectional relationship between the two tables. backref automatically creates a back reference in the related class, while back_populates explicitly defines the relationship on both sides.

class Left(Base):
    __tablename__ = 'left'
    id = Column(Integer, primary_key=True)
    rights = relationship("Right", secondary=association_table, back_populates="lefts")

class Right(Base):
    __tablename__ = 'right'
    id = Column(Integer, primary_key=True)
    lefts = relationship("Left", secondary=association_table, back_populates="rights")
    

Cascading Operations

Cascading operations allow you to define how changes in one table should affect related records in another table. For example, when a record in the "left" table is deleted, you can cascade the deletion to all related records in the "right" table.

class Left(Base):
    __tablename__ = 'left'
    id = Column(Integer, primary_key=True)
    rights = relationship("Right", secondary=association_table, back_populates="lefts", cascade="all, delete")

class Right(Base):
    __tablename__ = 'right'
    id = Column(Integer, primary_key=True)
    lefts = relationship("Left", secondary=association_table, back_populates="rights", cascade="all, delete")
    

Querying Relationships

Querying many-to-many relationships involves joining the main tables through the association table. SQLAlchemy provides powerful query tools to filter and retrieve related records efficiently.

from sqlalchemy.orm import sessionmaker

Session = sessionmaker(bind=engine)
session = Session()

left_records = session.query(Left).all()
for left in left_records:
    print(f"Left ID: {left.id}")
    for right in left.rights:
        print(f"  Right ID: {right.id}")